4.3 接收消息
接收的消息是微信服务器发送给公共账号的消息。在第3章中我们已经介绍了微信服务器的数据交互方式,当订阅用户给微信公众号发送消息时,微信服务器会将消息封装成XML数据,以POST方式发送到我们配置的URL上。根据消息类型的不同,XML数据的格式也有所不同,下面我们将详细介绍每种消息格式。
4.3.1 文本消息
文本消息是最常使用的交互方式,发送的所有文字(包括URL)都是文本消息。文本消息的结构如下:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <MsgId>1234567890123456</MsgId> </xml>
参数说明如表4-4所示。
表4-4 参数说明
表格中的部分参数详细解释如下:
- ToUserName 微信公共账号的原始ID,在公共账号的账号信息里能看到,类似gh_******的格式,这个字段对公共账号的开发者而言没什么用途。
- FromUserName 消息发送者的OpenID,类似于og17nt6kNCcqq25b77C8L2zEJXdQ的格式。对于同一个公共账号,订阅用户的OpenID是固定不变的,而对于不同的公共账号,用户的OpenID是不同的。
- CreateTime 消息创建的时间,是一个整型数字,表示从1970年1月1日0时0分0秒到现在经过的秒数。
- MsgType 消息类型。现在微信服务器提供6种类型的消息,即文本消息(text)、图片消息(image)、语音消息(voice)、视频消息(video)、地理位置消息(location)、链接消息(link)。
下面给出具体的代码。因为微信服务器是以POST的方式发送数据的,所以首先解析POST请求,提取出数据,代码如下:
/** *解析接收到的post数据 * @return SimpleXMLElement */ public function parsePostRequestData() { $rawData = $GLOBALS['HTTP_RAW_POST_DATA']; $data = simplexml_load_string($rawData, 'SimpleXMLElement', LIBXML_NOCDATA); if ($data !== false) $this->_postData = $data;
return $data; }
$GLOBALS['HTTP_RAW_POST_DATA']从$GLOBALS全局变量中获取POST数据,这时得到的数据是无类型的,通过simplexml_load_string函数解析成xml对象,就能供后续使用了。
isTextMsg用于判断消息的类型是否为文本消息:
const MSG_TYPE_TEXT = 'text'; /** *判断是否是文字信息 * @return boolean */ public function isTextMsg() { return $this->_postData->MsgType == self::MSG_TYPE_TEXT; } //发送消息 $this->text("你发送的是文本消息,消息内容是:".$data->Content);
text函数用来发送文本消息,这个将在后面介绍,如图4-3所示。
图4-3
4.3.2 图片消息
图片消息是多媒体消息,微信在收到这类消息时会将图片存在微信服务器端,生成图片的URL和媒体ID,图片URL是可以公共访问的,而公共账号可以通过媒体ID获取图片文件。
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[image]]></MsgType> <PicUrl><![CDATA[this is a url]]></PicUrl> <MediaId><![CDATA[media_id]]></MediaId> <MsgId>1234567890123456</MsgId> </xml>
参数说明如表4-5所示。
表4-5 参数说明
const MSG_TYPE_IMAGE='image'; /** *判断是否是图片 * @return boolean */ public function isImageMsg(){ return $this->_postData->MsgType == self::MSG_TYPE_IMAGE; } //发送消息 $this->text("你发送的是图片消息,图片链接是: ".$data->PicUrl."\n媒体ID是: ".$data->MediaId);
运行结果如图4-4所示。
图4-4
4.3.3 语音消息
语音消息同样只发送媒体ID,还提供语音的格式。
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA[voice]]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <Format><![CDATA[Format]]></Format> <MsgId>1234567890123456</MsgId> </xml>
参数说明如表4-6所示。
表4-6 参数说明
const MSG_TYPE_VOICE = 'voice'; /** *判断是否是语音消息 * @return boolean */ public function isVoiceMsg(){ return $this->_postData->MsgType == self::MSG_TYPE_VOICE; } //发送消息 $this->text("你发送的是语音消息,媒体ID是: ".$data->MediaId."\n语音格式是: ".$data->Format);
运行结果如图4-5所示。
图4-5
4.3.4 地理位置消息
在LBS和O2O的价值被极大发掘的今天,知道用户的位置能提供很多针对性、个性化的服务。微信也提供了在输入中发送当前位置的功能,如图4-6所示。
消息格式如下:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[location]]></MsgType> <Location_X>23.134521</Location_X> <Location_Y>113.358803</Location_Y> <Scale>20</Scale> <Label><![CDATA[位置信息]]></Label> <MsgId>1234567890123456</MsgId> </xml>
图4-6
参数说明如表4-7所示。
表4-7 参数说明
const MSG_TYPE_LOCATION = 'location'; /** *判断是否是位置信息 * @return boolean */ public function isLocationMsg() { return $this->_postData->MsgType == self::MSG_TYPE_LOCATION; } //发送消息 $this->text("你发送的是位置消息,维度为: ".$data->Location_X."\n经度为: ".$data->Location_Y."\n缩放 级别为: ".$data->Scale."\n位置为: ".$data->Label);
运行结果如图4-7所示。
图4-7
4.3.5 链接消息
图4-8
这里的链接消息和URL不是相同的概念,微信公众平台将URL作为文本消息。那么怎么发送链接消息呢?打开已有的链接(朋友圈或者朋友发送的分享),单击右上角的“分享”按钮,选择“发送给朋友”,就可以发送给微信朋友和微信群了。如果想分享一个网页,就复制URL并粘贴到消息框,再发送给微信朋友。建议发送给公共账号,免得打扰别人。打开链接(默认用微信浏览器打开),单击右上角的“分享”按钮就可以分享到朋友圈或发送给朋友。当前微信并不支持发送链接消息给公共账号,如果想发送,那么可以先将链接收藏到收藏夹,然后在消息框添加“我的收藏”,如图4-8所示。
链接消息的格式如下:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1351776360</CreateTime> <MsgType><![CDATA[link]]></MsgType> <Title><![CDATA[公众平台官方网站链接]]></Title> <Description><![CDATA[公众平台官方网站链接]]></Description> <Url><![CDATA[url]]></Url> <MsgId>1234567890123456</MsgId> </xml>
参数说明如表4-8所示。
表4-8 参数说明
const MSG_TYPE_LINK='link'; /** *判断是否是链接 * @return boolean */ public function isLinkMsg(){ return $this->_postData->MsgType == self::MSG_TYPE_LINK; } //发送消息 $this->text("你发送的是链接消息,标题是: ".$data->Title."\n摘要是: ".$data->Description."\n链接是: ".$data->Url);
运行结果如图4-9所示。
图4-9
视频消息也是多媒体消息,与语音消息类似,格式如下:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1357290913</CreateTime> <MsgType><![CDATA[video]]></MsgType> <MediaId><![CDATA[media_id]]></MediaId> <ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId> <MsgId>1234567890123456</MsgId> </xml>
参数说明如表4-9所示。
表4-9 参数说明
const MSG_TYPE_VIDEO = 'video'; /** *判断是否是视频消息 * @return boolean */ public function isVideoMsg(){ return $this->_postData->MsgType == self::MSG_TYPE_VIDEO; } //发送消息 $this->text("你发送的是视频消息,媒体ID是: ".$data->MediaId."\n缩略图ID是: ".$data-> ThumbMediaId);
运行结果如图4-10所示。
图4-10
4.3.6 公众平台消息体签名及加、解密
2014年10月14日,公众平台消息体签名及加密功能上线。该功能主要对公众平台推送给公众账号的基础消息和公众账号回复的响应消息进行加密,以更好地保护用户和公众账号的信息安全。
加解密的原理是AES对称加密。开发者服务器和公众平台服务器在发送消息时用EncodingAESKey(加密所用的密钥)将消息体加密成密文,再进行传输。这样在网络上传输的内容是加密的,即使被截获也无法得知明文。公众账号用此密钥对收到的密文消息体进行解密,回复消息体也用此密钥加密。
公众平台提供了3种加解密的模式供开发者选择,即明文模式、兼容模式、安全模式(可在“开发者中心”选择相应模式)。选择兼容模式和安全模式前,需在开发者中心填写消息加解密密钥EncodingAESKey,如图4-11所示。
图4-11
- 明文模式:维持现有模式,没有适配加解密新特性,消息体明文收发,默认设置为明文模式。
- 兼容模式:公众平台发送消息内容将同时包括明文和密文,消息包长度增加到原来的3倍左右。公众号回复明文或密文均可,不影响现有消息收发。开发者可在此模式下进行调试。
- 安全模式(推荐):公众平台发送消息体的内容只含有密文,公众账号回复的消息体也为密文,建议开发者在调试成功后使用此模式收发消息。
公众平台消息体签名及加解密方案的示例代码可参考下载资源中的代码。