博客列表 >微信公众号开发

微信公众号开发

威灵仙的博客
威灵仙的博客原创
2018年07月19日 22:29:55807浏览

主题:

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

运行实例 »

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


声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议