上QQ阅读APP看书,第一时间看更新
4.5 回复消息
对于每一个POST请求,开发者需要在响应包中返回特定XML结构的响应报文,现在支持回复文本、图片、图文、语音、视频、音乐。需要注意的是,回复图片等多媒体消息需要预先上传多媒体文件到微信服务器。
微信服务器在5秒内收不到响应会断掉链接,并且重新发起请求,最多重试3次。所以我们需要有消息的排重机制,防止对同一消息或事件回复多条响应消息。对于有msgid的消息可以使用msgid排重。事件类型消息则可以使用FromUserName+CreateTime排重。
对于有些耗时较多,无法保证在5秒内应答的请求可以直接回复空串,微信服务器不会对此做任何处理,并且不会发起重试。在这种情况下,可以使用客服消息接口进行异步回复,这个将在后面介绍。
4.5.1 回复文本消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> </xml>
参数说明如表4-15所示。
表4-15 参数说明
const REPLY_TYPE_TEXT = 'text'; /** *生成向用户发送的文字信息 * @param string $content * @return string xml字符串 */ public function outputText($content) { $textTpl = '<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Content><![CDATA[%s]]></Content> </xml>';
$text = sprintf($textTpl, $this->_postData->FromUserName, $this->_postData->ToUserName, time(), self::REPLY_TYPE_TEXT, $content); header('Content-Type: application/xml'); echo $text; }
header函数向客户端发送原始的HTTP报头,因为我们要发送的是XML格式的内容,定义Content-Type为application/xml。
4.5.2 回复图片消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[image]]></MsgType> <Image> <MediaId><![CDATA[media_id]]></MediaId> </Image> </xml>
参数说明如表4-16所示。
表4-16 参数说明
const REPLY_TYPE_IMAGE='image'; /** *生成向用户发送的图片信息 * @param string $media_id * @return string xml字符串 */ public function outputImage($media_id) { $textTpl = '<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Image> <MediaId><![CDATA[%s]]></MediaId> </Image> </xml>';
$text = sprintf($textTpl, $this->_postData->FromUserName, $this->_postData->ToUserName, time(), self::REPLY_TYPE_IMAGE, $media_id); header('Content-Type: application/xml'); echo $text; }
注意这里的mediaid是笔者上传获取的,而且微信服务器对多媒体只保存3天,所以读者在实验这段代码的时候请自行上传多媒体文件获取mediaid。上传下载多媒体的接口将在后面介绍,如图4-18所示。
图4-18
4.5.3 回复语音消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[voice]]></MsgType> <Voice> <MediaId><![CDATA[media_id]]></MediaId> </Voice> </xml>
参数说明如表4-17所示。
表4-17 参数说明
const REPLY_TYPE_VOICE = 'voice'; /** *生成向用户发送的语音信息 * @param string $content * @return string xml字符串 */ public function outputVoice($media_id) { $textTpl = '<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Voice> <MediaId><![CDATA[%s]]></MediaId> </Voice> </xml>';
$text = sprintf($textTpl, $this->_postData->FromUserName, $this->_postData->ToUserName, time(), self::REPLY_TYPE_VOICE, $media_id); header('Content-Type: application/xml'); echo $text; }
运行结果如图4-19所示。
图4-19
4.5.4 回复视频消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[video]]></MsgType> <Video> <MediaId><![CDATA[media_id]]></MediaId> <Title><![CDATA[title]]></Title> <Description><![CDATA[description]]></Description> </Video> </xml>
参数说明如表4-18所示。
表4-18 参数说明
const REPLY_TYPE_VIDEO = 'video'; /** *生成向用户发送的视频信息 * @param string $content * @return string xml字符串 */ public function outputVideo($videopost) { $textTpl = '<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Video> <MediaId><![CDATA[%s]]></MediaId> <Title><![CDATA[%s]]></Title> <Description><![CDATA[%s]]></Description> </Video> </xml>';
$text = sprintf($textTpl, $this->_postData->FromUserName, $this->_postData->ToUserName, time(), self::REPLY_TYPE_VIDEO, $videopost['media_id'], $videopost['title'], $videopost['description']); header('Content-Type: application/xml'); echo $text; } private function testVideo() { $video = array( 'media_id' => 'Dx09rTLDC3nZKTSmfWMHXKxNxb01oTbgqn3yHtLPgTUmDJxSSamGW7uqNGRZp3of', 'title' => '独墅湖', 'description' => '生活在独墅湖' ); $this->outputVideo($video); }
运行结果如图4-20所示。
图4-20
4.5.5 回复音乐消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[music]]></MsgType> <Music> <Title><![CDATA[TITLE]]></Title> <Description><![CDATA[DESCRIPTION]]></Description> <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl> <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl> <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId> </Music> </xml>
参数说明如表4-19所示。
表4-19 参数说明
const REPLY_TYPE_MUSIC='music'; /** *生成向用户发送的音乐信息 * @param type $musicpost * @return type * @throws Exception */ public function outputMusic($musicpost){ $textTpl = '<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <Music>%s</Music> </xml>';
$musicTpl = ' <Title><![CDATA[%s]]></Title> <Description><![CDATA[%s]]></Description> <MusicUrl><![CDATA[%s]]></MusicUrl> <HQMusicUrl><![CDATA[%s]]></HQMusicUrl> '; $music = ''; if (is_array($musicpost)){ $music .= sprintf($musicTpl, $musicpost['title'], $musicpost['description'], $musicpost['musicurl'], $musicpost['hdmusicurl']); }else{ throw new Exception('$posts数据结构错误'); }
$text = sprintf($textTpl, $this->_postData->FromUserName, $this->_postData->ToUserName, time(), self::REPLY_TYPE_MUSIC, $music); header('Content-Type: application/xml'); echo $text; } private function testMusic() { $music = array( 'title' => '在春天里', 'description' => '在春天里-汪峰', 'musicurl' => 'http://7xnmen.com1.z0.glb.clouddn.com/musicinspring.wma', 'hdmusicurl' => 'http://7xnmen.com1.z0.glb.clouddn.com/musicinspring.mp3' ); $this->outputMusic($music); }
运行结果如图4-21所示。
图4-21
4.5.6 回复图文消息
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[news]]></MsgType> <ArticleCount>2</ArticleCount> <Articles> <item> <Title><![CDATA[title1]]></Title> <Description><![CDATA[description1]]></Description> <PicUrl><![CDATA[picurl]]></PicUrl> <Url><![CDATA[url]]></Url> </item> <item> <Title><![CDATA[title]]></Title> <Description><![CDATA[description]]></Description> <PicUrl><![CDATA[picurl]]></PicUrl> <Url><![CDATA[url]]></Url> </item> </Articles> </xml>
参数说明如表4-20所示。
表4-20 参数说明
const REPLY_TYPE_NEWS = 'news'; /** *生成向用户发送的图文信息 * @param arrry $posts文章数组,每一个元素是一个文章数组,索引跟微信官方接口说明一致 * @return string xml字符串 */ public function outputNews($posts = array()) { $textTpl = '<xml> <ToUserName><![CDATA[%s]]></ToUserName> <FromUserName><![CDATA[%s]]></FromUserName> <CreateTime>%s</CreateTime> <MsgType><![CDATA[%s]]></MsgType> <ArticleCount>%d</ArticleCount> <Articles>%s</Articles> </xml>';
$itemTpl = '<item> <Title><![CDATA[%s]]></Title> <Discription><![CDATA[%s]]></Discription> <PicUrl><![CDATA[%s]]></PicUrl> <Url><![CDATA[%s]]></Url> </item>';
$items = ''; foreach ((array)$posts as $p) { if (is_array($p)) $items .= sprintf($itemTpl, $p['title'], $p['discription'], $p['picurl'], $p['url']); else throw new Exception('$posts数据结构错误'); }
$text = sprintf($textTpl, $this->_postData->FromUserName, $this->_postData->ToUserName, time(), self::REPLY_TYPE_NEWS, count($posts), $items); header('Content-Type: application/xml'); echo $text; }
private function testNews() { $posts = array( array( 'title' => '世界因你而不同', 'discription' => '最大化你的影响力,这就是你一生的意义。', 'picurl' => 'http://www.hers.cn/uploadfile/2011/1006/20111006022157183.jpg', 'url' => 'http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5MDE4Njg2MQ== &appmsgid=10000072&itemidx=1&sign=bea6deb75836dbe1249dcf394e8f3c21#wechat_redirect', ), array( 'title' => '平横', 'discription' => '心要多静才能保持如此的平衡', 'picurl' => 'http://news.shangdu.com/304/2009/08/20/images/501_20090820_911.jpg', 'url' => 'http://mp.weixin.qq.com/mp/appmsg/show?__biz=MjM5MDE4Njg2MQ== &appmsgid=10000066&itemidx=1#wechat_redirect', ) ); // outputNews用来返回图文信息 $xml = $this->outputNews($posts); }
运行结果如图4-22所示。
图4-22