在上一章中实现了一文本消息的互动。本章将在上一篇基础上完成开发。
微信的基础消息接口包括三个部分:接收普通消息、发送被动回复消息、接收事件消息。
<MsgType><![CDATA[text]]></MsgType>
一个公众号接收用户的文本消息包括
<xml>
<ToUserName><![CDATA[接收方账号]]></ToUserName>
<FromUserName><![CDATA[发送者的openid]]></FromUserName>
<CreateTime>时间整型</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[内容]></Content>
<MsgId>消息id</MsgId> <!-消息64位 -->
</xml>
微信用户接收公众号的文本消息组织包括:
<xml>
<ToUserName><![CDATA[接收方账号(收到的openid)]]></ToUserName>
<FromUserName><![CDATA[发送者的openid]]></FromUserName>
<CreateTime>时间整型</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[我是内容]></Content>
<MsgId>消息id</MsgId> <!-消息64位 -->
</xml>
一个公众号接收用户的图片消息包括
<xml>
<!-只列出不同-->
<MsgType><![CDATA[image]]></MsgType>
<PicUrl><![CDATA[http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=10_5fQEan8J_3b09bXLjDaYFmjjKqjem8tD6om2oxyUF_zKIt5pEjp7xNU_KiCyWokEnN3QcklwVXWIEyh4qhN-7idad2TRsrHGVt9VBZCxeL7mhUapJ-iSE2owvuvBmOMk4gFwk_iVW0Qak9x9XJTiAIATFP&type=image]]></PicUrl>
<MediaId><![CDATA[媒体id]]></MediaId>
</xml>
PicUrl就是图片地址。
媒体id可以从多媒体文件下载接口拉取。
一个公众号回复用户的图片消息包括:
<xml>
<!-只列出不同-->
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[媒体id]]></MediaId>
</Image>
<MediaId><![CDATA[媒体id]]></MediaId>
</xml>
语音消息的MsgType为:voice。
一个公众号接收用户的语音消息包括
<xml>
<!-只列出不同-->
<MsgType><![CDATA[voice]]></MsgType>
<MediaId><![CDATA[xxxxxxxx]]></MediaId>
<Format><![CDATA[amr/speex]]></Format>
<Recognition><![CDAATA[]]></Recognition>
</xml>
一个公众号回复用户的语音消息包括:
<xml>
<!-只列出不同-->
<MsgType><![CDATA[voice]]></MsgType>
<Voice>
<MediaId><![CDATA[媒体id]]></MediaId>
</Voice>
</xml>
视频消息的MsgType为:video。
一个公众号接收用户的语音消息包括
<xml>
<!-只列出不同-->
<MsgType><![CDATA[video]]></MsgType>
<MediaId><![CDATA[xxxxxxxx]]></MediaId>
<ThumbMediaId><![CDATA[缩略图媒体id]]></ThumbMediaId>
</xml>
一个公众号回复用户的语音消息包括:
<xml>
<!-只列出不同-->
<MsgType><![CDATA[video]]></MsgType>
<Video>
<MediaId><![CDATA[xxxx]]></MediaId>
<ThumbMediaId><![CDATA[缩略图媒体id]]></ThumbMediaId>
<Titile><![CDATA[标题]]></Titile>
<Description><![CDATA[描述]]></Description>
</Video>
</xml>
地理位置消息的MsgType为:location。
<xml>
<!-只列出不同-->
<MsgType><![CDATA[location]]></MsgType>
<Location_X>纬度数字</Location_X>
<Location_Y>经度数字</Location_Y>
<Scale>放大倍数比如16</Scale>
<Label><![CDATA[中国北京天安门]]></Label>
</xml>
链接消息的title为link
<xml>
<!-只列出不同-->
<MsgType><![CDATA[location]]></MsgType>
<Titile><![CDATA[标题]]></Titile>
<Description><![CDATA[描述]]></Description>
<Url><![CDATA[url地址]]></Url>
</xml>
音乐消息的type为music。、
<xml>
<!--只列出不同-->
<MsgType><![CDATA[music]]></MsgType>
<Music>
<Title><![CDATA[最炫民族风]]></Title>
<Description>
<![CDATA[凤凰传奇]]>
</Description>
<!--音乐的一般链接和Hq(高品质)链接-->
<MusicUrl><![CDATA[http://adasfasfasfwsgvwe.vas.vsdvs]]></MusicUrl>
<HQMusicUrl><![CDATA[http://adasfasfasfwsgvwe.vas.vsdvs]]></HQMusicUrl>
</Music>
</xml>
图文可以分为单图文和多图文,显示方式基本是一样的。
<xml>
<ToUserName><![CDATA[发送的微信账号]]></ToUserName>
<FromUserName><![CDATA[收到的微信账号]]></FromUserName>
<CreateTime>时间戳</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<Content><![CDATA[内容]]></Content>
<ArticleCount>1</ArticleCount>
<Articles>
<item>
<Title>标题</Title>
<Description>摘要</Description>
<PicUrl> <![CDATA[题图地址]]></PicUrl>
<Url><![CDATA[链接地址]]></Url>
</item>
<!--如果是多图文,将有几个不同的item-->
</Articles>
</xml>
基础接口的事件只有两个,就是关注和取消关注。 msgType
为event。
用户点击关注公众号->
<xml>
<ToUserName><![CDATA[发送的微信账号]]></ToUserName>
<FromUserName><![CDATA[收到的微信账号]]></FromUserName>
<CreateTime>时间戳</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[subscribe]]></Event><!--订阅-->
<EventKey><![CDATA[]]></EventKey><!--为空-->
</xml>
用户取关->
<xml>
<ToUserName><![CDATA[发送的微信账号]]></ToUserName>
<FromUserName><![CDATA[收到的微信账号]]></FromUserName>
<CreateTime>时间戳</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[unsubscribe]]></Event><!--取消订阅-->
<EventKey><![CDATA[]]></EventKey><!--为空-->
</xml>
【需求】根据之前的消息范例,写一个微信公众号的SDK。
基础消息的SDK将前面章节的各种接收消息类型进行了处理,另外对被动发送消息类型进行了定义。
在 responseMsg()
方法中,先提取消息类型 $postObj->MsgType
,从而实现各种消息类型的分离。在类wechatCallbackapiTest中,为每种消息定型定义了接收方法函数。在每个方法里面,返回消息的主要特征值,组成文本信息作为内容回复。
在接收到文本指令回复文本、图文(包括单图文和多图文)、音乐三种消息时,是使用直接构造相应消息类型实现的,而图片、语音、视频三种消息需要MediaId参数,在这里直接使用用户发送过来的消息中的MediaId,然后组装成响应消息回复。
由之前的原理可得:
用户发出消息=>校验=>判断消息类型,跳转不同业务逻辑=>根据不同消息类型,制定不同的消息。
和上一章一样,定义一个 wechatCallbackapiTest
类:
<?php
/**
* 微信第一个SDK
*/
header('Content-type:text');
define('TOKEN','weixin');
$wechatObj=new wechatCallbackapiTest();
if(!isset($_GET['echostr'])){
$wechatObj->responseMsg();
}else{
$wechatObj->valid();
}
public wechatCallbackapiTest{
// ...
}
?>
收到消息,先判断MsgType。再根据类型转发到receiveXXX方法。
<?php
// ...
//响应消息
public function responseMsg(){
$postStr=$GLOBALS['HTTP_RAW_POST_DATA'];
if(!empty($postStr)){
// $this->logger("R \r\n.postStr");
$postObj=simplexml_load_string($postStr,'SimpleXMLElement',LIBXML_NOCDATA);
$RX_TYPE=trim($postObj->MsgType);
//消息类型分类
switch ($RX_TYPE) {
case 'event': //事件
$result=$this->receiveEvent($postObj);
break;
case 'text'://文本
$result=$this->receiveText($postObj);
break;
case 'image'://图片
$result=$this->receiveImage($postObj);
break;
case 'location'://位置
$result=$this->receiveLocation($postObj);
break;
case 'voice'://语音
$result=$this->receiveVoice($postObj);
break;
case 'video':
case 'shortVideo'://视频
$result=$this->receiveVideo($postObj);
break;
case 'link':
$result=$this->receiveLink($postObj);
break;
default:
$result='未知的消息类型。';
break;
}
// $this->logger("T \r\n".$result);
echo $result;
}else{
echo '';
}
}
?>
receiveXXX就是针对每种消息进行分类处理好大部分恢复内容后,进入组装流程(transmitXXX)。
<?php
// 。。。
/ 回复文本消息
private function transmitText($object,$content){
if(!isset($content)||empty($content)){
return "";
}
$xmlTpl="
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>
";
$result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time(),$content);
return $result;
}
//回复图文消息
private function transmitNews($object,$content){
if(!is_array($content)){
return "";
}
$itemTpl="
<item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
";
$item_str="";
foreach ($content as $item){
$item_str.=sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
}
$xmlTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<ArticleCount>%s</ArticleCount>
<Articles>
$item_str
</Articles>
</xml>";
$result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time(),count($content));
return $result;
}
//回复音乐消息
private function transmitMusic($object,$content){
if(!is_array($content)){
return '';
}
$itemTpl="
<Music>
<Title><![CDATA[%s]]></Title>
<Description>
<![CDATA[%s]]>
</Description>
<MusicUrl><![CDATA[%s]]></MusicUrl>
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
</Music>
";
$item_str=sprintf($itemTpl,$content['Title'],$content['Description'],$content['MusicUrl'],$content['HQMusicUrl']);
$xmlTpl="
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[music]]></MsgType>
$item_str
</xml>
";
$result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time());
return $result;
}
//回复图片消息
private function transmitImage($object,$content){
$itemTpl="
<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>
";
$item_str=sprintf($itemTpl,$content['MediaId']);
$xmlTpl="
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
$item_str
</xml>
";
$result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time());
return $result;
}
//回复语音
private function transmitVoice($object,$content){
$itemTpl="
<Voice>
<MediaId><![CDATA[%s]]></MediaId>
</Voice>
";
$item_str=sprintf($itemTpl,$content['MediaId']);
$xmlTpl="
<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
$item_str
</xml>
";
$result=sprintf($xmlTpl,$object->FromUserName,$object->ToUserName,time());
return $result;
}
//回复视频消息
private function transmitVideo($object, $videoArray)
{
$itemTpl = "<Video>
<MediaId><![CDATA[%s]]></MediaId>
<ThumbMediaId><![CDATA[%s]]></ThumbMediaId>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
</Video>";
$item_str = sprintf($itemTpl, $videoArray['MediaId'], $videoArray['ThumbMediaId'], $videoArray['Title'], $videoArray['Description']);
$xmlTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
$item_str
</xml>";
$result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time());
return $result;
}
// 。。。
?>
自此,一个基础微信的SDJK就完成了。