Blogger Information
Blog 60
fans 0
comment 1
visits 37534
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
微信公众号开发
威灵仙的博客
Original
805 people have browsed it

主题:

通过微信公众号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>

运行实例 »

点击 "运行实例" 按钮查看在线实例


Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post