當用戶發送消息給公眾號時(或某些特定的用戶操作引發的事件推送時),會產生一個POST請求,開發者可以在響應包(Get)中返回特定XML結構,來對該消息進行響應(現支持回復文本、圖片、圖文、語音、視頻、音樂)。嚴格來說,發送被動響應消息其實並不是一種接口,而是對微信服務器發過來消息的一次回復。
微信服務器在將用戶的消息發給公眾號的開發者服務器地址(開發者中心處配置)后,微信服務器在五秒內收不到響應會斷掉連接,並且重新發起請求,總共重試三次,如果在調試中,發現用戶無法收到響應的消息,可以檢查是否消息處理超時。關於重試的消息排重,有msgid的消息推薦使用msgid排重。事件類型消息推薦使用FromUserName + CreateTime 排重。
如果開發者希望增強安全性,可以在開發者中心處開啟消息加密,這樣,用戶發給公眾號的消息以及公眾號被動回復用戶消息都會繼續加密(但),詳見被動回復消息加解密說明。
假如服務器無法保證在五秒內處理並回復,必須做出下述回復,這樣微信服務器才不會對此作任何處理,並且不會發起重試(這種情況下,可以使用客服消息接口進行異步回復),否則,將出現嚴重的錯誤提示。詳見下面說明:
1、(推薦方式)直接回復success 2、直接回復空串(指字節長度為0的空字符串,而不是XML結構體中content字段的內容為空)
一旦遇到以下情況,微信都會在公眾號會話中,向用戶下發系統提示“該公眾號暫時無法提供服務,請稍后再試”:
1、開發者在5秒內未回復任何內容 2、開發者回復了異常數據,比如JSON數據等
另外,請注意,回復圖片等多媒體消息時需要預先通過素材管理接口上傳臨時素材到微信服務器,可以使用素材管理中的臨時素材,也可以使用永久素材。
各消息類型需要的XML數據包結構如下。
目錄
代碼:
<?php
//
// 響應用戶消息
// 微信公眾賬號響應給用戶的不同消息類型
//
/* 思路:
1.定義token
2.實例化api接口對象
3.如果有$_GET['echostr'],通過驗證后原樣返回,用於接口驗證
4.如果不存在就走responseMsg()
5.如果不存在post數據,打印出空字符串,退出
6.如果有post數據,根據post接收到的字符串將其實例化成一個XML對象
7.然后對用戶發送來的數據類型進行判斷,走不同的分支去處理
8.如果是文本信息,根據獲取到keywords屬性進行判斷,有文本,圖文,多圖文,音樂等等,如果是語音,視頻,圖片,返回自定義內容,目前是返回用戶原數據
官方文檔地址:https://mp.weixin.qq.com/wiki/1/6239b44c206cab9145b1d52c67e6c551.html
*/
define("TOKEN", "zhouqi");
$wechatObj = new wechatCallbackapiTest();
if (!isset($_GET['echostr'])) {
$wechatObj->responseMsg();
}else{
$wechatObj->valid();
}
class wechatCallbackapiTest
{
public function valid()
{
$echoStr = $_GET["echostr"];
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode($tmpArr);
$tmpStr = sha1($tmpStr);
if($tmpStr == $signature){
return true;
}else{
return false;
}
}
public function responseMsg()
{
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
if (!empty($postStr)){
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$RX_TYPE = trim($postObj->MsgType);
//用戶發送的消息類型判斷
switch ($RX_TYPE)
{
case "text":
$result = $this->receiveText($postObj);
break;
case "image":
$result = $this->receiveImage($postObj);
break;
case "voice":
$result = $this->receiveVoice($postObj);
break;
case "video":
$result = $this->receiveVideo($postObj);
break;
default:
$result = "unknow msg type: ".$RX_TYPE;
break;
}
echo $result;
}else {
echo "";
exit;
}
}
private function receiveText($object)
{
$keyword = trim($object->Content);
if($keyword == "文本"){
//回復文本消息
$content = "這是個文本消息";
$result = $this->transmitText($object, $content);
}
else if($keyword == "圖文" || $keyword == "單圖文"){
//回復單圖文消息
$content = array();
$content[] = array("Title"=>"單圖文標題",
"Description"=>"單圖文內容",
"PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg",
"Url" =>"http://m.cnblogs.com/?u=txw1958");
$result = $this->transmitNews($object, $content);
}
else if($keyword == "多圖文"){
//回復多圖文消息
$content = array();
$content[] = array("Title"=>"多圖文1標題", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
$content[] = array("Title"=>"多圖文2標題", "Description"=>"", "PicUrl"=>"http://d.hiphotos.bdimg.com/wisegame/pic/item/f3529822720e0cf3ac9f1ada0846f21fbe09aaa3.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
$content[] = array("Title"=>"多圖文3標題", "Description"=>"", "PicUrl"=>"http://g.hiphotos.bdimg.com/wisegame/pic/item/18cb0a46f21fbe090d338acc6a600c338644adfd.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958");
$result = $this->transmitNews($object, $content);
}
else if($keyword == "音樂"){
//回復音樂消息
$content = array("Title"=>"最炫民族風",
"Description"=>"歌手:鳳凰傳奇",
"MusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3",
"HQMusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3");
$result = $this->transmitMusic($object, $content);
}
return $result;
}
private function receiveImage($object)
{
//回復圖片消息
$content = array("MediaId"=>$object->MediaId);
$result = $this->transmitImage($object, $content);;
return $result;
}
private function receiveVoice($object)
{
//回復語音消息
$content = array("MediaId"=>$object->MediaId);
$result = $this->transmitVoice($object, $content);;
return $result;
}
private function receiveVideo($object)
{
//回復視頻消息
$content = array("MediaId"=>$object->MediaId, "ThumbMediaId"=>$object->ThumbMediaId, "Title"=>"", "Description"=>"");
$result = $this->transmitVideo($object, $content);;
return $result;
}
/*
* 回復文本消息
*/
private function transmitText($object, $content)
{
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[%s]]></Content>
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time(), $content);
return $result;
}
/*
* 回復圖片消息
*/
private function transmitImage($object, $imageArray)
{
$itemTpl = "<Image>
<MediaId><![CDATA[%s]]></MediaId>
</Image>";
$item_str = sprintf($itemTpl, $imageArray['MediaId']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
$item_str
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time());
return $result;
}
/*
* 回復語音消息
*/
private function transmitVoice($object, $voiceArray)
{
$itemTpl = "<Voice>
<MediaId><![CDATA[%s]]></MediaId>
</Voice>";
$item_str = sprintf($itemTpl, $voiceArray['MediaId']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[voice]]></MsgType>
$item_str
</xml>";
$result = sprintf($textTpl, $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']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[video]]></MsgType>
$item_str
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time());
return $result;
}
/*
* 回復圖文消息
*/
private function transmitNews($object, $arr_item)
{
if(!is_array($arr_item))
return;
$itemTpl = " <item>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<PicUrl><![CDATA[%s]]></PicUrl>
<Url><![CDATA[%s]]></Url>
</item>
";
$item_str = "";
foreach ($arr_item as $item)
$item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']);
$newsTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[news]]></MsgType>
<Content><![CDATA[]]></Content>
<ArticleCount>%s</ArticleCount>
<Articles>
$item_str</Articles>
</xml>";
$result = sprintf($newsTpl, $object->FromUserName, $object->ToUserName, time(), count($arr_item));
return $result;
}
/*
* 回復音樂消息
*/
private function transmitMusic($object, $musicArray)
{
$itemTpl = "<Music>
<Title><![CDATA[%s]]></Title>
<Description><![CDATA[%s]]></Description>
<MusicUrl><![CDATA[%s]]></MusicUrl>
<HQMusicUrl><![CDATA[%s]]></HQMusicUrl>
</Music>";
$item_str = sprintf($itemTpl, $musicArray['Title'], $musicArray['Description'], $musicArray['MusicUrl'], $musicArray['HQMusicUrl']);
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[music]]></MsgType>
$item_str
</xml>";
$result = sprintf($textTpl, $object->FromUserName, $object->ToUserName, time());
return $result;
}
}
?>