本节书摘来自华章计算机《微信公众平台开发:从零基础到thinkphp5高性能框架实践》一书中的第3章,第3.3节,作者 方倍工作室,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
单击进入配置页面,可以看到当前有服务器配置信息,状态为未启用,如图3-20所示。

单击“修改配置”按钮,进入修改页面,如图3-21所示。
在弹出的提示框中单击“确定”按钮,相关参数填写成功,如图3-23所示。
再单击右上角的“启用”按钮,启用服务器的配置。系统弹出提示框,询问“是否确定开启服务器配置”,如图3-24所示。
单击“确定”按钮,将启用服务器配置。
如果单击按钮后,上方提示“token验证失败”,可以重试几次,微信服务器有时不稳定也会造成这样的情况,并不是程序本身有问题。启用成功后的界面如图3-25所示。
这样就成功配置并启用了服务器。
提交url和token的时候,有时会碰到提交不成功的情况,具体有以下几种。
1.请求url超时
这种情况一般是由于服务器网速或响应速度太慢。此时可以先重试几次或者等一段时间再试,如果还是这样,则需要考虑更换速度更快、性能更好的服务器。
2.系统发生错误,请稍后重试
这种情况一般是由于微信服务器短时间内的异常引起的,一般重试或者过一段时间尝试即可。
3.token验证失败
这种情况需要具体分析验证过程被卡在哪一个环节了。此时可以通过调用变量$_server来获取服务器和执行环境信息,以便进行分析。
这里需要使用以下两个元素。
$_server['remote_addr']:来访者的ip地址,此处为微信服务器的ip地址。
$_server['query_string']:查询请求字符串,此处为微信服务器发过来的get请求字符串。
将以上两个变量记录到日志中。函数定义如下。
上面代码中,当环境为sae时,使用sae的调试函数sae_debug()将内容记录到日志中。而在具有读写权限的空间下,使用file_put_contents()函数把字符串写入文件。
然后在程序的数据处理之前调用该函数,记录信息,代码如下。
当提交url和token验证的时候,程序目录下应当生成一个log.xml文件。内容类似如下。
下面可以得出初步结论。
没有生成日志文件:微信服务器没有访问到你的服务器,需要先检查你的服务器是否可以通过公网访问,以及url路径是否正确并且可以访问。如果可以通过公网访问,而微信服务器不能访问,那么可能是防火墙拦截了80端口或微信服务器的ip地址,也可能是服务器所在区域与微信服务器通信不畅,需要更换服务器。
已经生成日志文件:查看remote_addr和query_string的内容是否与上述类似。确认signature、timestamp、nonce、echostr等4个参数都有值。如果这些都没有问题,则检查程序中定义的token值是否与提交的一致,再检查程序流程及数据处理是否与官方文档描述的一致。
如果确定以上均没有问题,可以使用下面章节中的微信调试器进行测试,它提供了更为宽松的校验方式,并且可以实时输出当前的xml数据供调试时参考。
在上面的例子中,已经嵌入了一个简单的时间查询功能,发送一个问号“?”就能回复当前的时间,如图3-26所示。
这个功能是基于下面的代码实现的。
上述代码在收到消息后,判断消息内容是否为问号(包括英文输入状态下的问号和中文输入状态下的问号),如果包含,则将当前时间(包括年月日时分秒)作为回复内容,构造成一个消息回复给用户。这样公众号就实现了当前时间的自动回复。
下面结合3.3.3节的代码来分析微信公众平台的消息交互原理。下面的代码基于微信公众平台官方示例代码修改完善而成。
首先看一下代码的结构。
第2~5行是注释部分。
第7行使用define()函数定义常量,常量名称为token,常量的值为weixin,这个值就是在启用开发模式时填写的token。
第15~75行定义了一个类wechatcallbackapitest,并在类中定义了3个方法valid()、checksignature()和responsemsg()。
第8~13行为程序执行语句。第8行实例化了一个类对象。在第9行中,判断是否有get请求有echostr变量,如果有,则执行valid()方法,否则执行responsemsg()方法。
下面分析微信消息交互流程。
提交url和token申请验证的时候,微信服务器将发送get请求到填写的url上,并且带上4个参数(signature、timestamp、nonce、echostr)。get请求类似如下。
上述请求的参数说明如表3-1所示。
这个get请求是包含echostr变量的,所以执行valid()方法。在该方法中,又调用了校验签名方法checksignature()。如果签名校验为真,则原样输出变量$echostr的值。
加密/校验流程如下。
1)将token、timestamp、nonce等3个参数进行字典序排序,见第33~34行。
2)将3个参数字符串拼接成一个字符串进行sha1加密,见第35~36行。
3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信,见第38~42行。
发送问号的时候,微信服务器也会带上前面3个参数(signature、timestamp、nonce)访问开发者设置的url,同时还会将消息的xml数据包post到url上。xml格式类似如下。
而消息请求不包含echostr变量,所以将执行响应消息方法responsemsg()。
响应消息方法首先接收上述原始post数据,见第47行。
然后它将数据载入对象中,对象名为simplexmlelement,libxml_nocdata?表示将cdata合并为文本节点,代码中第50行实现此功能。
第51~54行取得xml类对象的值,并赋给新的变量,注意发送方变为接收方,接收方变为发送方。
第55~62行构造要回复的xml数据包。
第63行判断发送过来的关键字是不是问号。
第64~65行设置回复的消息类型为text,内容为当前年月日时分秒。
第66~67行封装回复的xml数据包,并且向微信服务器输出。xml格式如下。
这样用户就会收到回复的消息,效果如图3-26所示。
在图3-21中,微信公众平台在配置服务器时,提供了3种加解密模式供开发者选择,即“明文模式”、“兼容模式”、“安全模式(推荐)”。选择“兼容模式”和“安全模式(推荐)”前,需在开发者中心填写aes对称加密算法的消息加解密密钥encodingaeskey。公众号用此密钥对收到的密文消息体进行解密,回复消息体也用此密钥加密。
明文模式:维持现有模式,没有适配加解密新特性,消息体明文收发,默认设置为明文模式。
兼容模式:公众平台发送消息内容将同时包括明文和密文,消息包长度增加到原来的3倍左右;公众号回复明文或密文均可,不影响现有消息收发;开发者可在此模式下进行调试。
安全模式(推荐):公众平台发送消息体的内容只含有密文,公众号回复的消息体也为密文,建议开发者在调试成功后使用此模式收发消息。
消息体加解密的实现过程如下。
假设本次的开发配置中url为
接口程序中需要配置以下3个参数。
当用户向公众号发送消息时,微信公众号将会在url中带上signature、timestamp、nonce、encrypt_type、msg_signature等参数,类似如下。
同时向该接口推送如下xml消息,即一个已加密的消息。
这时程序需要从url中获得以下参数。这些参数将用于加解密过程。
接口程序收到消息后,先进行解密,解密部分代码如下。
解密完成后,把解密内容又返回给$poststr,这是为了将消息中解密后的内容和明文模式时的消息统一,方便后续处理。解密后的xml如下。
对消息在自己的原有的代码流程中处理,完成之后,一个要回复的文本消息如下。
把上述消息加密,返回给微信公众号,加密过程如下。
加密后的内容如下。
这样一个安全模式下的加解密消息就完成了。
完整的代码如下。