3.1 Token验证
Token简单的说就是微信后台和公众账号服务器之间的秘钥,只有他们俩知道这个Token字符串。
Token验证过程
1. 微信后台向公众号服务器发送数据的时候,会额外携带4个参数:timestamp(时间戳)、nonce(随机数)、signature(对timestamp、nonce和Token进行SHA1加密后的字符串,加密过程不可逆,即不能通过其他三个计算出Token)、echostr(随机字符串,接入url时才有此参数)
2. 公众号服务器收到timestamp、nonce、signature之后,同样对timestamp、nonce和Token使用SHA1加密算法进行加密,得到自己的签名,如果接收到的签名和自己的签名是一样的,说明请求是来自微信后台而不是恶意的第三方
注:恶意的第三方有可能会截获timestamp、signature和nonce,然后直接利用这三个参数对公众账号服务器进行请求,这样公众账号服务器无法判断这是恶意请求,这种攻击叫replay攻击,防御方法很简单,加上对timestamp的校验,在收到请求后,将请求包中的timestamp与当前时间比较,如果误差大于一定值,就可以认为这个请求是恶意的。
3.2 请求消息
微信公众账号能够接收到的消息有文本(Text)、图片(image)、地理位置(location)、语音(voice)、视频(video)、事件(event)、链接消息(link)
1.请求文本消息
示例代码解读:
3 //get post data, May be due to the different environments
4 $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
5
6 //extract post data
7 if (!empty($postStr)){
8 /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
9 the best way is to check the validity of xml by yourself */
10 libxml_disable_entity_loader(true);
11 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
12 $fromUsername = $postObj->FromUserName;
13 $toUsername = $postObj->ToUserName;
14 $keyword = trim($postObj->Content);
15 $time = time();
16 $textTpl = "<xml>
17 <ToUserName><![CDATA[%s]]></ToUserName>
18 <FromUserName><![CDATA[%s]]></FromUserName>
19 <CreateTime>%s</CreateTime>
20 <MsgType><![CDATA[%s]]></MsgType>
21 <Content><![CDATA[%s]]></Content>
22 <FuncFlag>0</FuncFlag>
23 </xml>";
24 if(!empty( $keyword ))
25 {
26 $msgType = "text";
27 $contentStr = "欢迎关注装修是家微信公众号!后续将为您提供更多精彩内容";
28 $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
29 echo $resultStr;
30 }else{
31 echo "Input something...";
32 }
33
34 }else {
35 echo "";
36 exit;
37 }
38 }
第4行的作用是接收从微信公众账号服务端发送过来的代码
第11行的作用是通过simplexml_load_string将postStr字符串转换成对象格类型的数据,如下:
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
这样方便直接获取某个字段的数据。
第12行是获取用户的openid,可以表示发送方账号,但是不能通过这个openid在微信上找到对应的用户,而且对于不同的公众账号,同一个用户的openid是不一样的。
第13行是获取开发者的微信号公众账号
第14行是获取用户发送的消息内容
2. 图片消息
微信后台对图片消息封装是这样的:
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<PicUrl><![CDATA[%s]]></PicUrl>
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
3. 地理位置消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Location_X><![CDATA[%s]]></Location_X> 地理位置纬度
<Location_Y><![CDATA[%s]]></Location_Y> 地理位置经度
<Scale>20</Scale> 地图缩放大小
<Label><!DATA[%s]]></Label> 地理位置信息
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
4. 语音消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<MediaId><![CDATA[%s]]></MediaId> 语音消息媒体id,可以调用多媒体文件下载接口拉取数据
<Format><!DATA[%s]]></Format> 语音格式,如amr,speex等
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
5. 视频消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<MediaId><![CDATA[%s]]></MediaId> 语音消息媒体id,可以调用多媒体文件下载接口拉取数据
<ThumbMediaId><!DATA[%s]]></ThumbMediaId> 视频消息缩略图的媒体ID,可以调用多媒体文件下载接口拉取数据
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
6. 链接消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Title><![CDATA[%s]]></Title> 消息标题
<Description><![CDATA[%s]]></Description> 消息描述
<Url><![CDATA[%s]]></Url> 消息链接
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
7. 事件消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Event><![CDATA[%s]]></Event> 事件类型,有subscribe和unsubscribe
<FuncFlag>0</FuncFlag>
</xml>
具体参照开发者文档
3.3 回复消息
1. 文本消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>
2. 图片消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType> //image
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
</xml>
3. 语音消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType> //voice
<Voice>
<MediaId><![CDATA[%s]]></MediaId>
</Voice>
</xml>
4. 音乐消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType> //music
<Music>
<Title><![CDATA[%s]]></Title> //音乐标题
<Description><![CDATA[%s]]></Description> //音乐描述
<MusicUrl><![CDATA[%s]]></MusicUrl> //音乐链接
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl> //高质量音乐链接,wifi环境下优先使用该链接播放
<ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
</Music>
</xml>
5. 视频消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType> //video
<Video>
<MediaId><![CDATA[%s]]></MediaId> //语音消息媒体id,可以调用多媒体文件下载接口拉取数据
<ThumbMediaId><!DATA[%s]]></ThumbMediaId> //视频消息缩略图的媒体ID,可以调用多媒体文件下载接口拉取数据
</Video>
</xml>
6. 图文消息
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType> //news
<ArticleCount>2</ArticleCount> //图文消息个数,限制在10以内,默认第一个item为大图
<Articles>
<item>
<Title><![CDATA[%s]]></Title> //图文消息标题
<Description><![CDATA[%s]]></Description> //图文消息描述
<PicUrl><![CDATA[%s]]></PicUrl> //图片链接
<Url><![CDATA[%s]]></Url> //消息链接
</item>
<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
</Articles>
</xml>