主题:
通过微信公众号API接口实现微信的关注、取消关注、定位、JSSDK定位。
实现效果:
用户关注后,将关注者信息存入数据库:
取消关注后,软删除(sub_status值变为0):
定位(关注时即可获取定位信息并存入数据库):
JSSDK定位:
控制器Wechat.php实例
<?php namespace app\index\controller; use think\Controller; class Wechat extends Controller { // 微信signature签名校验 public function __construct() { parent::__construct(); $this->model = model('Wechat'); } public function index() { $check = $this->model->check(); // 判断模型中返回值 if(!$check) { exit('signature error'); } // 接收微信请求数据流对象 $xmldata = file_get_contents("php://input"); // 转换获取到的xml字符串为SimpleXMLElement对象,然后输出对象的键和元素 $postObj = simplexml_load_string($xmldata, 'SimpleXMLElement', LIBXML_NOCDATA); // 将对xml象转化为一个数组 $data = (array)$postObj; // 事件推送,企业级开发中必须做数据真实性判断再执行下一步 if(isset($data['MsgType']) && $data['MsgType'] == 'event') { // 关注 if($data['Event'] == 'subscribe') { $this->model->subscribe($data); } // 取消关注 if($data['Event'] == 'unsubscribe') { $this->model->unsubscribe($data); } // 定位 if($data['Event'] == 'LOCATION') { $this->model->location($data); // file_put_contents('D://location.txt', var_export($data, true)); exit('success'); } } // 消息推送 if(isset($data['MsgType']) && $data['MsgType'] == 'text') { $this->robot($data); exit('success'); } exit(input('get.echostr')); } // 获取校验access_token(区别于网页授权access_token) public function get_access_token() { $access_token = $this->model->access_token(); return $access_token; } // 微信网页授权 public function auth() { // 如果正式公众号必须使用备案域名,并配置到公众号回调域名中 $redirect_uri = config('app.myurl'). 'index.php/index/wechat/userinfo'; // 第一步:用户同意授权,获取code $url_code = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='. config('app.appid'). '&redirect_uri='. urlEncode($redirect_uri).'&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect'; // 获取$url的Loation请求头信息 header('Location:'. $url_code); } // 显示用户信息 public function userinfo() { // 获取code $code = input('get.code'); // 第二步:通过code换取网页授权access_token(注意这个和之前的普通access_token完全不一样) $res = $this->model->auth_access_token($code, false); $auth_access_token = $res['access_token']; $openid = $res['openid']; // 第三步:拉取用户信息(需要scope为snsapi_userinfo) $userinfo = $this->model->get_userinfo($auth_access_token, $openid); dump($userinfo); } // 获取用户地理位置,JSSDK方式 public function location() { $data['appid'] = config('app.appid'); $data['timestamp'] = time(); $data['nonceStr'] = md5(time().rand(1,999)); // 生成签名 // 1.获取jsapi_ticket $access_token = $this->model->access_token(); $jsapi_ticket = $this->model->jsapi_ticket($access_token); // 2.构造签名字符串 $params['noncestr'] = $data['nonceStr']; $params['jsapi_ticket'] = $jsapi_ticket; $params['timestamp'] = $data['timestamp']; $params['url'] = config('app.myurl'). 'index.php/index/wechat/location'; ksort($params); // 防止url字符转义 $str = urldecode(http_build_query($params)); // 3.生成签名 $data['signature'] = sha1($str); // 将所有数据打包成一个数组传入视图,默认传入方法名同名视图 return $this->fetch('', $data); } }
运行实例 »
点击 "运行实例" 按钮查看在线实例
模型Wechat.php实例
<?php namespace app\index\model; use think\Model; use think\facade\Cache; use think\Db; class Wechat extends Model { // 微信signature签名校验 public function check() { // 将微信服务器的请求数据分别存为变量 $signature = input('get.signature'); $timestamp = input('get.timestamp'); $nonce = input('get.nonce'); $echostr = input('get.echostr'); // 在框架配置文件中设置微信的token,并读取 $token = config('app.wechattoken'); // 将获取的数据存到一个数组中 $tmpArr = array($timestamp, $nonce, $token); // 排序数据数组 sort($tmpArr, SORT_STRING); // 将排序后的数组数据拼接成一个字符串 $str = implode($tmpArr); // 判断加密后的字符串与微信请求中的signature是否一致 if(sha1($str) != $signature) { return false; } return true; } // 获取校验access_token(区别于网页授权access_token) public function access_token($iscache = true) { // 如果某个参数使用较多,放到一个变量中,方便更改 $cache_key = 'access_token'; // 默认不用删除缓存 if(!$iscache) { Cache::rm($cache_key); } // 获取缓存中的access_token值 $access_token = Cache::get($cache_key); if($access_token && $iscache) { return $access_token; } // 将appid和appsecret(微信公众号中获取)的值保存至config/app.php中,并调取 $appid = config('app.appid'); $appsecret = config('app.appsecret'); // 拼接url $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='. $appid. '&secret='. $appsecret; // 获取access_token的值,返回一个json数据 $res = http_Get($url); // 将json数据转换成数组 $res = json_decode($res, true); // 如果没有拿到access_token的值,返回false if(!isset($res['access_token'])) { return false; } // 拿到数据后进行缓存,使用facade中的Cache Cache::set($cache_key, $res['access_token'], $res['expires_in']-300); return $res['access_token']; } // 换取网页授权access_token public function auth_access_token($code) { $appid = config('app.appid'); $appsecret = config('app.appsecret'); $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='. $appid. '&secret='. $appsecret. '&code='. $code. '&grant_type=authorization_code'; $res = http_Get($url); $res = json_decode($res, true); if(!isset($res['access_token'])) { return false; } return $res; } // 获取jsapi_ticket public function jsapi_ticket($access_token, $iscache = true) { $key = 'jsapi_ticket'; if(!$iscache) { Cache::rm($key); } $data = Cache::get($key); if($data && $iscache) { return $data; } $appid = config('app.appid'); $appsecret = config('app.appsecret'); $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='. $access_token. '&type=jsapi'; $res = http_Get($url); $res = json_decode($res,true); if(!isset($res['ticket'])) { return false; } Cache::set($key,$res['ticket'],($res['expires_in']-300)); return $res['ticket']; } // 拉取用户信息 public function get_userinfo($auth_access_token, $openid) { $url = 'https://api.weixin.qq.com/sns/userinfo?access_token='. $auth_access_token. '&openid='. $openid. '&lang=zh_CN'; $res = http_Get($url); $res = json_decode($res, true); return $res; } // 关注 public function subscribe($data) { // 检查用户是否已存在 $user = Db::name('user')->where(array('openid' => $data['FromUserName']))->find(); // 判断是否有历史关注记录,软删除 if(!$user) { Db::name('user')->insertGetId(array('openid' => $data['FromUserName'],'sub_status' => 1,'add_time' => time())); } else { Db::name('user')->where(array('openid' => $data['FromUserName']))->update(array('sub_status' => 1)); } } // 取消关注 public function unsubscribe($data) { // 软删除 Db::name('user') ->where(array('openid' => $data['FromUserName'])) ->update(array('sub_status' => 0)); } // 定位 public function location($data) { // 更新数据库中经纬度数据 Db::name('user') ->where(array('openid' => $data['FromUserName'])) ->update(array('lat' => $data['Latitude'],'lng' => $data['Longitude'])); } }
运行实例 »
点击 "运行实例" 按钮查看在线实例
地图显示视图location.html实例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>微信定位</title> </head> <body> </body> <!-- 这里src中前面可不加http/https --> <script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script type="text/javascript"> // 此方法只有在微信中有效 wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '{$appid}', // 必填,公众号的唯一标识 timestamp: {$timestamp}, // 必填,生成签名的时间戳 nonceStr: '{$nonceStr}', // 必填,生成签名的随机串 signature: '{$signature}',// 必填,签名 jsApiList: ['getLocation', 'openLocation'] // 必填,需要使用的JS接口列表 }); // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 wx.ready(function(){ getLocation(openLocation); }); // 获取地理位置接口 function getLocation(callback) { wx.getLocation({ type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 // 判断返回值是否定义 if(callback != undefined) { callback(res); } } }); } // 使用微信内置地图查看位置接口,创建一个方法 function openLocation(res) { wx.openLocation({ latitude: res.latitude, // 纬度,浮点数,范围为90 ~ -90 longitude: res.longitude, // 经度,浮点数,范围为180 ~ -180。 name: '', // 位置名 address: '', // 地址详情说明 scale: 15, // 地图缩放级别,整形值,范围从1~28。默认为最大 infoUrl: '' // 在查看位置界面底部显示的超链接,可点击跳转 }); } </script> </html>
实例
主题: 通过微信公众号API接口实现微信的关注、取消关注、定位、JSSDK定位。 实现效果: 用户关注后,将关注者信息存入数据库: QQ截图20180608165141.png 取消关注后,软删除(sub_status值变为0): 2.png 定位(关注时即可获取定位信息并存入数据库): 3.png JSSDK定位: Screenshot_2018-06-08-16-57-38-232_com.tencent.mm.png 控制器Wechat.php实例 <?php namespace app\index\controller; use think\Controller; class Wechat extends Controller { // 微信signature签名校验 public function __construct() { parent::__construct(); $this->model = model('Wechat'); } public function index() { $check = $this->model->check(); // 判断模型中返回值 if(!$check) { exit('signature error'); } // 接收微信请求数据流对象 $xmldata = file_get_contents("php://input"); // 转换获取到的xml字符串为SimpleXMLElement对象,然后输出对象的键和元素 $postObj = simplexml_load_string($xmldata, 'SimpleXMLElement', LIBXML_NOCDATA); // 将对xml象转化为一个数组 $data = (array)$postObj; // 事件推送,企业级开发中必须做数据真实性判断再执行下一步 if(isset($data['MsgType']) && $data['MsgType'] == 'event') { // 关注 if($data['Event'] == 'subscribe') { $this->model->subscribe($data); } // 取消关注 if($data['Event'] == 'unsubscribe') { $this->model->unsubscribe($data); } // 定位 if($data['Event'] == 'LOCATION') { $this->model->location($data); // file_put_contents('D://location.txt', var_export($data, true)); exit('success'); } } // 消息推送 if(isset($data['MsgType']) && $data['MsgType'] == 'text') { $this->robot($data); exit('success'); } exit(input('get.echostr')); } // 获取校验access_token(区别于网页授权access_token) public function get_access_token() { $access_token = $this->model->access_token(); return $access_token; } // 微信网页授权 public function auth() { // 如果正式公众号必须使用备案域名,并配置到公众号回调域名中 $redirect_uri = config('app.myurl'). 'index.php/index/wechat/userinfo'; // 第一步:用户同意授权,获取code $url_code = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='. config('app.appid'). '&redirect_uri='. urlEncode($redirect_uri).'&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect'; // 获取$url的Loation请求头信息 header('Location:'. $url_code); } // 显示用户信息 public function userinfo() { // 获取code $code = input('get.code'); // 第二步:通过code换取网页授权access_token(注意这个和之前的普通access_token完全不一样) $res = $this->model->auth_access_token($code, false); $auth_access_token = $res['access_token']; $openid = $res['openid']; // 第三步:拉取用户信息(需要scope为snsapi_userinfo) $userinfo = $this->model->get_userinfo($auth_access_token, $openid); dump($userinfo); } // 获取用户地理位置,JSSDK方式 public function location() { $data['appid'] = config('app.appid'); $data['timestamp'] = time(); $data['nonceStr'] = md5(time().rand(1,999)); // 生成签名 // 1.获取jsapi_ticket $access_token = $this->model->access_token(); $jsapi_ticket = $this->model->jsapi_ticket($access_token); // 2.构造签名字符串 $params['noncestr'] = $data['nonceStr']; $params['jsapi_ticket'] = $jsapi_ticket; $params['timestamp'] = $data['timestamp']; $params['url'] = config('app.myurl'). 'index.php/index/wechat/location'; ksort($params); // 防止url字符转义 $str = urldecode(http_build_query($params)); // 3.生成签名 $data['signature'] = sha1($str); // 将所有数据打包成一个数组传入视图,默认传入方法名同名视图 return $this->fetch('', $data); } } 运行实例 » 点击 "运行实例" 按钮查看在线实例 模型Wechat.php实例 <?php namespace app\index\model; use think\Model; use think\facade\Cache; use think\Db; class Wechat extends Model { // 微信signature签名校验 public function check() { // 将微信服务器的请求数据分别存为变量 $signature = input('get.signature'); $timestamp = input('get.timestamp'); $nonce = input('get.nonce'); $echostr = input('get.echostr'); // 在框架配置文件中设置微信的token,并读取 $token = config('app.wechattoken'); // 将获取的数据存到一个数组中 $tmpArr = array($timestamp, $nonce, $token); // 排序数据数组 sort($tmpArr, SORT_STRING); // 将排序后的数组数据拼接成一个字符串 $str = implode($tmpArr); // 判断加密后的字符串与微信请求中的signature是否一致 if(sha1($str) != $signature) { return false; } return true; } // 获取校验access_token(区别于网页授权access_token) public function access_token($iscache = true) { // 如果某个参数使用较多,放到一个变量中,方便更改 $cache_key = 'access_token'; // 默认不用删除缓存 if(!$iscache) { Cache::rm($cache_key); } // 获取缓存中的access_token值 $access_token = Cache::get($cache_key); if($access_token && $iscache) { return $access_token; } // 将appid和appsecret(微信公众号中获取)的值保存至config/app.php中,并调取 $appid = config('app.appid'); $appsecret = config('app.appsecret'); // 拼接url $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='. $appid. '&secret='. $appsecret; // 获取access_token的值,返回一个json数据 $res = http_Get($url); // 将json数据转换成数组 $res = json_decode($res, true); // 如果没有拿到access_token的值,返回false if(!isset($res['access_token'])) { return false; } // 拿到数据后进行缓存,使用facade中的Cache Cache::set($cache_key, $res['access_token'], $res['expires_in']-300); return $res['access_token']; } // 换取网页授权access_token public function auth_access_token($code) { $appid = config('app.appid'); $appsecret = config('app.appsecret'); $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='. $appid. '&secret='. $appsecret. '&code='. $code. '&grant_type=authorization_code'; $res = http_Get($url); $res = json_decode($res, true); if(!isset($res['access_token'])) { return false; } return $res; } // 获取jsapi_ticket public function jsapi_ticket($access_token, $iscache = true) { $key = 'jsapi_ticket'; if(!$iscache) { Cache::rm($key); } $data = Cache::get($key); if($data && $iscache) { return $data; } $appid = config('app.appid'); $appsecret = config('app.appsecret'); $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='. $access_token. '&type=jsapi'; $res = http_Get($url); $res = json_decode($res,true); if(!isset($res['ticket'])) { return false; } Cache::set($key,$res['ticket'],($res['expires_in']-300)); return $res['ticket']; } // 拉取用户信息 public function get_userinfo($auth_access_token, $openid) { $url = 'https://api.weixin.qq.com/sns/userinfo?access_token='. $auth_access_token. '&openid='. $openid. '&lang=zh_CN'; $res = http_Get($url); $res = json_decode($res, true); return $res; } // 关注 public function subscribe($data) { // 检查用户是否已存在 $user = Db::name('user')->where(array('openid' => $data['FromUserName']))->find(); // 判断是否有历史关注记录,软删除 if(!$user) { Db::name('user')->insertGetId(array('openid' => $data['FromUserName'],'sub_status' => 1,'add_time' => time())); } else { Db::name('user')->where(array('openid' => $data['FromUserName']))->update(array('sub_status' => 1)); } } // 取消关注 public function unsubscribe($data) { // 软删除 Db::name('user') ->where(array('openid' => $data['FromUserName'])) ->update(array('sub_status' => 0)); } // 定位 public function location($data) { // 更新数据库中经纬度数据 Db::name('user') ->where(array('openid' => $data['FromUserName'])) ->update(array('lat' => $data['Latitude'],'lng' => $data['Longitude'])); } } 运行实例 » 点击 "运行实例" 按钮查看在线实例 地图显示视图location.html实例 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>微信定位</title> </head> <body> </body> <!-- 这里src中前面可不加http/https --> <script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> <script type="text/javascript"> // 此方法只有在微信中有效 wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: '{$appid}', // 必填,公众号的唯一标识 timestamp: {$timestamp}, // 必填,生成签名的时间戳 nonceStr: '{$nonceStr}', // 必填,生成签名的随机串 signature: '{$signature}',// 必填,签名 jsApiList: ['getLocation', 'openLocation'] // 必填,需要使用的JS接口列表 }); // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。 wx.ready(function(){ getLocation(openLocation); }); // 获取地理位置接口 function getLocation(callback) { wx.getLocation({ type: 'gcj02', // 默认为wgs84的gps坐标,如果要返回直接给openLocation用的火星坐标,可传入'gcj02' success: function (res) { var latitude = res.latitude; // 纬度,浮点数,范围为90 ~ -90 var longitude = res.longitude; // 经度,浮点数,范围为180 ~ -180。 var speed = res.speed; // 速度,以米/每秒计 var accuracy = res.accuracy; // 位置精度 // 判断返回值是否定义 if(callback != undefined) { callback(res); } } }); } // 使用微信内置地图查看位置接口,创建一个方法 function openLocation(res) { wx.openLocation({ latitude: res.latitude, // 纬度,浮点数,范围为90 ~ -90 longitude: res.longitude, // 经度,浮点数,范围为180 ~ -180。 name: '', // 位置名 address: '', // 地址详情说明 scale: 15, // 地图缩放级别,整形值,范围从1~28。默认为最大 infoUrl: '' // 在查看位置界面底部显示的超链接,可点击跳转 }); } </script> </html>
运行实例 »
点击 "运行实例" 按钮查看在线实例