当微信用户向公众号发送消息时,微信服务器会向公众号配置的服务器URL地址发送请求,并将相关内容包装成一定格式的xml发送到这个服务器;响应时,这个服务器只要回复特定格式的xml字符串给微信服务器,微信服务器即可向微信用户的客户端转发这条回复消息.(假设公众号开发模式已开启,以后的教程,如果没有特别说明,都是如此).如下图:
例如,文本消息的xml结构如下:
<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>
各参数说明如下:
其他消息类型的xml结构详见微信公众号官方文档.
微信暂时能转发的消息类型分为:普通消息和事件推送消息.其中普通消息又分为:文本消息,图片消息,语音消息,视频消息,小视频消息,地理位置消息,链接消息;事件推消息又分为:关注/取消关注事件,扫描带参数二维码事件,上报地理位置事件,自定义菜单事件.
下面偿试接收这些所有消息:
<?php
//文件名: http://szuzsq.tunnel.qydev.com/weixin/index.php
$wechatObj = new wechatCallbackapiTest();
$wechatObj->responseMsg();
class wechatCallbackapiTest {
public function responseMsg() {
//注:微信官方demo是使用$GLOBALS,而我使用的是file_get_contents的形式,来获取转发过来的xml内容.具体php配置不同,应采用不同的形式,请大家注意下,不然后可能粉丝收不到你的公众号回复的消息.
//$str = $GLOBALS["HTTP_RAW_POST_DATA"];
$str = file_get_contents("php://input");
if(!isset($str) || empty($str))
exit("");
libxml_disable_entity_loader(true);
$xml = simplexml_load_string($str, 'SimpleXMLElement', LIBXML_NOCDATA);
switch($xml->MsgType) {
case "text": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n内容:$xml->Content";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "image": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n图片链接:$xml->PicUrl";
$content .= "\n图片ID:$xml->MediaId";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "voice": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n语音ID:$xml->MediaID";
$content .= "\n语音格式:$xml->Format";
$content .= "\n语音识别结果:$xml->Recognition";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "video": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n视频ID:$xml->MediaId";
$content .= "\n视频缩略图ID:$xml->ThumbMediaId";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "shortvideo": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n视频ID:$xml->MediaId";
$content .= "\n视频缩略图ID:$xml->ThumbMediaId";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "location": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n地理位置维度:$xml->Location_X ";
$content .= "\n地理位置经度:$xml->Location_Y ";
$content .= "\n地图缩放大小:$xml->Scale";
$content .= "\n地理位置信息:$xml->Label";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "link": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n消息标题:$xml->Title";
$content .= "\n消息描述:$xml->Description";
$content .= "\n消息链接:$xml->Url";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "event": {
switch($xml->Event) {
case "subscribe": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n事件类型:$xml->Event";
//注:只有在用户还未关注公众号但扫描带参数二维码事件时,微信服务器才会带场景值的关注事件.
//即:普通关注事件只有Event参数.扫描带参数二维码并关注事件还有EventKey,Ticket参数.
$content .= "\n事件KEY值:$xml->EventKey";
$content .= "\n二维码的ticket:$xml->Ticket";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "unsubscribe": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n事件类型:$xml->Event";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "SCAN": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n事件类型:$xml->Event";
$content .= "\n事件KEY值:$xml->EventKey";
$content .= "\n二维码的ticket:$xml->Ticket";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "LOCATION": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n事件类型:$xml->Event";
$content .= "\n地理位置纬度:$xml->Latitude";
$content .= "\n地理位置经度:$xml->Longitude";
$content .= "\n地理位置精度:$xml->Precision";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "CLICK": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n事件类型:$xml->Event";
$content .= "\n事件KEY值:$xml->EventKey";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "VIEW": {
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n事件类型:$xml->Event";
$content .= "\n事件KEY值:$xml->EventKey";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
}
break;
}
}
}
}
?>
效果图,如下:
文本消息
图片消息
语音消息
视频消息
小视频消息
地理位置消息
链接消息
关注事件
以下事件暂时没截到效果图.
微信官方文档里说:"其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许,详细说明请见本页末尾的微信推送消息与事件说明。".我没找着那个说明.也不知道是否微信服务器不能接收回复,还是微信服务器接收回复后不会向公众号服务器转发.如果有同学知道,也请告诉我.不过我用微信公众平台接口调试工具,似乎都返回成功,代码应该是没问题了的.
取消关注事件
扫描带参数二维码事件
上报地理位置事件
自定义菜单事件--点击菜单拉取消息时的事件推送
自定义菜单事件--点击菜单跳转链接时的事件推送