搭建本地开发环境
由于微信公众平台开发,涉及到与平台对接,所以需要公网域名,而内网映射到公网的方法:国内有花生壳,但是蛋疼的是80端口要花钱买,而微信只对80端口开放对接。没办法只能用国外免费的NGROK,国外的网真难撸
1. 先注册ngrok帐号 注册地址:https://dashboard.ngrok.com/user/signup 注意在注册时会出现验证码项,但天朝有些不明原因被屏蔽了,弄了一天也没注册成功,后来用谷歌浏览器+谷歌访问助手,成功注册到了。。。
2. 注册成功 登录帐号 下载ngrok程序,解压到项目根目录,例如:D:\myphp_www\PHPTutorial\WWW\tp51
3. 用命令行 安装程序 并运行程序
4. 安装成功,如下图界面:并且获取到外网域名了
注意:norok程序运行窗口,在开发过程中最好不要关闭,一关闭就会断线,再开启公网域名就会更新了
5. 配置本地域名管理器-PHP工具箱。
到此,本地开发环境就配置成功了,,但是后续开发服务号需要备案域名,所以云服务器+备案域名是最佳运行环境。
接入微信公众平台开发,开发者需要按照如下步骤完成:
一、填写服务器配置
登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。
URL 根据开发环境域名配置 Token 协议密钥 开发者自定义 EncodingAESKey 开发者自定义或随机生成43个字符
二、验证服务器地址的有效性
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:
signature 微信加密签名 timestamp 时间戳 nonce 随机数 echostr 随机字符串
我们这里用get的方法拿:signature timestamp nonce echostr 这四项参数
$signature = input('get.signature'); $timestamp = input('get.timestamp'); $nonce = input('get.nonce'); $echostr = input('get.echostr'); $token = config('app.token');
token 是我们自定义的,所以让我们提供:$token = ‘abcd12345’
而在企业级开发中,一般密钥口令之类的,我们不能写在项目中,而是写到配置中 再在项目中调用的
//微信配置 'token' => 'aMCikdpelcnEk1omMjK4'
开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:
先将获取到的参数,保存到本地记事本,看看能否获得到相关参数
file_put_contents('D://data.txt','signature='.$signature.' timestamp='.$timestamp.' nonce='.$nonce.' echostr='.$echostr);
1)将token、timestamp、nonce三个参数进行字典序排序
$tmpArr = array($timestamp,$nonce,$token); //将几个参数放到一个数组中 sort($tmpArr, SORT_STRING); //sort(,SORT_STRING) 对数组进行排序
2)将三个参数字符串拼接成一个字符串进行sha1加密
$str = implode($tmpArr);//implode 拼接字符串 $sign = sha1($str);//sha1加密字符串 echo $sign;//输出一下看看效果 exit;
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if ($sign !=$signature) {//如果检验不匹配 exit('signature error');//返回一个签名错误 } exit($echostr);//如果匹配通过,原样返回
以上所有校验代码都可以进行优化,将校验过程封装到模型中做为校验方法:tp51/application/model/Weixin.php
<?php namespace app\index\model; use think\Model; use think\facade\Cache; class Weixin extends Model{ // 签名校验 public function valid(){ $signature = input('get.signature'); $timestamp = input('get.timestamp'); $nonce = input('get.nonce'); $echostr = input('get.echostr'); $token = config('app.token'); $tmpArr = array($timestamp,$nonce,$token); sort($tmpArr, SORT_STRING); $str = implode($tmpArr); if(sha1($str) != $signature){ return false; } return true; }
而在控制器中直接用valid()方法调用:
<?php namespace app\index\controller; use think\Controller; use think\facade\Cache;//导入门面模式缓存方法 class Weixin extends Controller{ public function __construct(){ parent::__construct(); $this->model = model('Weixin');//用构造器方法 方便后期整体参数修改 } public function valid(){ $valid = $this->model->valid(); if(!$valid){ exit('signature error'); } exit(input('get.echostr')); }
三、依据接口文档实现业务逻辑
验证URL有效性成功后即接入生效,成为开发者。你可以在公众平台网站中申请微信认证,认证成功后,将获得更多接口权限,满足更多业务需求。
成为开发者后,用户每次向公众号发送消息、或者产生自定义菜单、或产生微信支付订单等情况时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,开发者可以依据自身业务逻辑进行响应,如回复消息。
获取access_token
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
1. 公众号可以使用AppID和AppSecret调用本接口来获取access_token。
2. AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。
3. 调用接口时,请提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。
接口https请求方式: GET:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
此请求URL中有两个重要参数: APPID APPSECRET 这两个参数一般不直接写在项目中,而是写到项目配置中APP
//微信配置 'token' => 'aMCikdpelc00k1omMjK4', 'appid' => 'wxdb8a19000a62f575', 'appsecret' => '8084703db2897e05000024975dc1708',
URL请求方式:GET,微信官方有给我们提供实例程序如下:把它写到公共文件下面:tp51/application/common.php
<? // 应用公共文件 function http_Get($url){ $curl = curl_init(); curl_setopt($curl,CURLOPT_URL,trim($url)); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl,CURLOPT_HEADER,0); curl_setopt($curl,CURLOPT_CUSTOMREQUEST,'GET');//需要要传送的内容 curl_setopt($curl,CURLOPT_RETURNTRANSFER,1); $return_str = curl_exec($curl); curl_close($curl); return $return_str; }
这个实例程序怎么写的,为什么这样写,我们都不用管它,尽管按官方的方法写就行
curl:就是在应用程序里面模拟浏览器去访问一些URL资源
//获取access_token public function get_access_token(){ $appid = config('app.appid'); $appsecret = config('app.appsecret'); $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret; $res = http_Get($url); dump($res); exit; }
此处$appid $appsecret 都是调用配置文件的值 URL用字符串拼接的方式 用http_Get请求的方法
测试得到错误信息是:IP不在白名单内,只需添加公网IP到白名单即可获取到access_token
由于微信公众平台的access_token有调用次数限制,服务号是10000次,个人号更少,每天调用完就没得用了,还会造成通讯浪费,对于固定密钥我们可以一个策略方法:将获取到的access_token缓存到本地目录中,当需要时直接从本地目录调用即可。
然而access_token只有2个小时的有效期,到期就更新,所以我们又要想到缓存周期为2小时内,当快过2小时时,再次从平台获取缓存
$res = json_decode($res,true);//json_decode对JSON数据进行解码,转换为PHP变量 Cache::set('access_token',$res['access_token'],$res['expires_in']-300); //cache::set() 方法 有三个参数:1. 键 2. 值 3. 时间
前提要先导入方法:use think\facade\Cache;//导入门面模式缓存方法
同样我们也要把这个获取access_token的方法,封装到模型中:tp51/application/model/Weixin.php
//获取access_token public function access_token($iscache = true){ $key = 'access_token'; //简化常量 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/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret; $res = http_get($url); $res = json_decode($res,true); if(!isset($res['access_token'])){ return false; } Cache::set($key,$res['access_token'],($res['expires_in']-100)); return $res['access_token']; }
1. access_token($iscache = true) 默认要缓存 access_token
2. 判断是否要删除缓存
if(!$iscache){ Cache::rm($key); }
3. 判断是否有缓存数据:如果有就直接从缓存拿数据 如果没有就从平台获取数据
$data = Cache::get($key); if($data && $iscache){ return $data; }
而在控制器中直接用get_access_token()方法调用:
//获取access_token public function get_access_token(){ $key = 'access_token'; $access_token = Cache::get($key); if($access_token){ return $access_token; } $appid = config('app.appid'); $appsecret = config('app.appsecret'); $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret; $res = http_Get($url); $res = json_decode($res,true); Cache::set($cache_key,$res['access_token'],$res['expires_in']-600); return $res['access_token']; }
总结:其实整个过程就是:
1. 开发者网站发出接入请求,微信公众平台发出GET请求,signature timestamp nonce echostr 等参数(这些参数由微信公众平台和开发者共同约定设置好的,只有两者知道),开发者网站与其对比匹配,其中将token、timestamp、nonce三个参数进行字典序排序,拼接,加密。。如果对比通过,就允许接入。对比不通过,就是非法请求,拒绝!
2. 微信公众平台为了通讯的安全性,设定了个口令,并且2小时更新一次,开发者网站后续功能操作,需要实时检验口令,口令通过才能继续通讯操作相关功能。。由于官方口令的限制性,我们又对口令采取了缓存本地并且每2小时内重新从微信平台获取口令一次的策略
以上两部完成了对接和验证功能,就可以继续后面的工作开发。。。
其实第三方平台对接都是这个策略,先互相校验设定好的口令(类似于江湖上的对暗号),暗号对上了,就可以开始互相交换相关数据,并开发相关功能操作。。。