原文:
微信公众平台开发接口PHP SDK完整版
官方提供的SDK只有一个文本消息功能,我们将所有消息的消息类型及事件响应都整理了进来,并且加入日志记录,代码如下:
更新日志:
2013-01-01 版本1.0
2014-03-15 增加图片、视频、语音的内容回复
2014-04-09 增加菜单链接事件
2014-04-10 修改文本回复的判定方法
2014-05-20 增加高级群发消息通知事件
2014-05-26 增加多客服消息及多客服的判定方法
2014-05-27 修改自动回复判定方式
2014-06-20 修复多图文回复的Bug
2014-07-10 增加第三方接口处理样式
2014-08-02 增加Emoji表格的回复处理
2014-10-01 增加自定义菜单扫一扫、发图片、发地理位置处理
2014-10-25 增加消息体签名及加解密的支持
2014-11-07 增加该公众号暂时无法提供服务请稍后再试的兼容
1 <?php 2 /* 3 方倍工作室 4 http://www.cnblogs.com/txw1958/ 5 CopyRight 2014 All Rights Reserved 6 */ 7 8 define("TOKEN", "weixin"); 9 10 $wechatObj = new wechatCallbackapiTest(); 11 if (!isset($_GET['echostr'])) { 12 $wechatObj->responseMsg(); 13 }else{ 14 $wechatObj->valid(); 15 } 16 17 class wechatCallbackapiTest 18 { 19 //验证签名 20 public function valid() 21 { 22 $echoStr = $_GET["echostr"]; 23 $signature = $_GET["signature"]; 24 $timestamp = $_GET["timestamp"]; 25 $nonce = $_GET["nonce"]; 26 $token = TOKEN; 27 $tmpArr = array($token, $timestamp, $nonce); 28 sort($tmpArr); 29 $tmpStr = implode($tmpArr); 30 $tmpStr = sha1($tmpStr); 31 if($tmpStr == $signature){ 32 echo $echoStr; 33 exit; 34 } 35 } 36 37 //响应消息 38 public function responseMsg() 39 { 40 $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; 41 if (!empty($postStr)){ 42 $this->logger("R ".$postStr); 43 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA); 44 $RX_TYPE = trim($postObj->MsgType); 45 46 //消息类型分离 47 switch ($RX_TYPE) 48 { 49 case "event": 50 $result = $this->receiveEvent($postObj); 51 break; 52 case "text": 53 $result = $this->receiveText($postObj); 54 break; 55 case "image": 56 $result = $this->receiveImage($postObj); 57 break; 58 case "location": 59 $result = $this->receiveLocation($postObj); 60 break; 61 case "voice": 62 $result = $this->receiveVoice($postObj); 63 break; 64 case "video": 65 $result = $this->receiveVideo($postObj); 66 break; 67 case "link": 68 $result = $this->receiveLink($postObj); 69 break; 70 default: 71 $result = "unknown msg type: ".$RX_TYPE; 72 break; 73 } 74 $this->logger("T ".$result); 75 echo $result; 76 }else { 77 echo ""; 78 exit; 79 } 80 } 81 82 //接收事件消息 83 private function receiveEvent($object) 84 { 85 $content = ""; 86 switch ($object->Event) 87 { 88 case "subscribe": 89 $content = "欢迎关注方倍工作室 "; 90 $content .= (!empty($object->EventKey))?("\n来自二维码场景 ".str_replace("qrscene_","",$object->EventKey)):""; 91 break; 92 case "unsubscribe": 93 $content = "取消关注"; 94 break; 95 case "SCAN": 96 $content = "扫描场景 ".$object->EventKey; 97 break; 98 case "CLICK": 99 switch ($object->EventKey) 100 { 101 case "COMPANY": 102 $content = array(); 103 $content[] = array("Title"=>"多图文1标题", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 104 break; 105 default: 106 $content = "点击菜单:".$object->EventKey; 107 break; 108 } 109 break; 110 case "LOCATION": 111 $content = "上传位置:纬度 ".$object->Latitude.";经度 ".$object->Longitude; 112 break; 113 case "VIEW": 114 $content = "跳转链接 ".$object->EventKey; 115 break; 116 case "MASSSENDJOBFINISH": 117 $content = "消息ID:".$object->MsgID.",结果:".$object->Status.",粉丝数:".$object->TotalCount.",过滤:".$object->FilterCount.",发送成功:".$object->SentCount.",发送失败:".$object->ErrorCount; 118 break; 119 default: 120 $content = "receive a new event: ".$object->Event; 121 break; 122 } 123 if(is_array($content)){ 124 if (isset($content[0])){ 125 $result = $this->transmitNews($object, $content); 126 }else if (isset($content['MusicUrl'])){ 127 $result = $this->transmitMusic($object, $content); 128 } 129 }else{ 130 $result = $this->transmitText($object, $content); 131 } 132 133 return $result; 134 } 135 136 //接收文本消息 137 private function receiveText($object) 138 { 139 $keyword = trim($object->Content); 140 //多客服人工回复模式 141 if (strstr($keyword, "您好") || strstr($keyword, "你好") || strstr($keyword, "在吗")){ 142 $result = $this->transmitService($object); 143 } 144 //自动回复模式 145 else{ 146 if (strstr($keyword, "文本")){ 147 $content = "这是个文本消息"; 148 }else if (strstr($keyword, "单图文")){ 149 $content = array(); 150 $content[] = array("Title"=>"单图文标题", "Description"=>"单图文内容", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 151 }else if (strstr($keyword, "图文") || strstr($keyword, "多图文")){ 152 $content = array(); 153 $content[] = array("Title"=>"多图文1标题", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 154 $content[] = array("Title"=>"多图文2标题", "Description"=>"", "PicUrl"=>"http://d.hiphotos.bdimg.com/wisegame/pic/item/f3529822720e0cf3ac9f1ada0846f21fbe09aaa3.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 155 $content[] = array("Title"=>"多图文3标题", "Description"=>"", "PicUrl"=>"http://g.hiphotos.bdimg.com/wisegame/pic/item/18cb0a46f21fbe090d338acc6a600c338644adfd.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 156 }else if (strstr($keyword, "音乐")){ 157 $content = array(); 158 $content = array("Title"=>"最炫民族风", "Description"=>"歌手:凤凰传奇", "MusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3", "HQMusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3"); 159 }else{ 160 $content = date("Y-m-d H:i:s",time())."\n技术支持 方倍工作室"; 161 } 162 163 if(is_array($content)){ 164 if (isset($content[0]['PicUrl'])){ 165 $result = $this->transmitNews($object, $content); 166 }else if (isset($content['MusicUrl'])){ 167 $result = $this->transmitMusic($object, $content); 168 } 169 }else{ 170 $result = $this->transmitText($object, $content); 171 } 172 } 173 174 return $result; 175 } 176 177 //接收图片消息 178 private function receiveImage($object) 179 { 180 $content = array("MediaId"=>$object->MediaId); 181 $result = $this->transmitImage($object, $content); 182 return $result; 183 } 184 185 //接收位置消息 186 private function receiveLocation($object) 187 { 188 $content = "你发送的是位置,纬度为:".$object->Location_X.";经度为:".$object->Location_Y.";缩放级别为:".$object->Scale.";位置为:".$object->Label; 189 $result = $this->transmitText($object, $content); 190 return $result; 191 } 192 193 //接收语音消息 194 private function receiveVoice($object) 195 { 196 if (isset($object->Recognition) && !empty($object->Recognition)){ 197 $content = "你刚才说的是:".$object->Recognition; 198 $result = $this->transmitText($object, $content); 199 }else{ 200 $content = array("MediaId"=>$object->MediaId); 201 $result = $this->transmitVoice($object, $content); 202 } 203 204 return $result; 205 } 206 207 //接收视频消息 208 private function receiveVideo($object) 209 { 210 $content = array("MediaId"=>$object->MediaId, "ThumbMediaId"=>$object->ThumbMediaId, "Title"=>"", "Description"=>""); 211 $result = $this->transmitVideo($object, $content); 212 return $result; 213 } 214 215 //接收链接消息 216 private function receiveLink($object) 217 { 218 $content = "你发送的是链接,标题为:".$object->Title.";内容为:".$object->Description.";链接地址为:".$object->Url; 219 $result = $this->transmitText($object, $content); 220 return $result; 221 } 222 223 //回复文本消息 224 private function transmitText($object, $content) 225 { 226 $xmlTpl = "<xml> 227 <ToUserName><![CDATA[%s]]></ToUserName> 228 <FromUserName><![CDATA[%s]]></FromUserName> 229 <CreateTime>%s</CreateTime> 230 <MsgType><![CDATA[text]]></MsgType> 231 <Content><![CDATA[%s]]></Content> 232 </xml>"; 233 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content); 234 return $result; 235 } 236 237 //回复图片消息 238 private function transmitImage($object, $imageArray) 239 { 240 $itemTpl = "<Image> 241 <MediaId><![CDATA[%s]]></MediaId> 242 </Image>"; 243 244 $item_str = sprintf($itemTpl, $imageArray['MediaId']); 245 246 $xmlTpl = "<xml> 247 <ToUserName><![CDATA[%s]]></ToUserName> 248 <FromUserName><![CDATA[%s]]></FromUserName> 249 <CreateTime>%s</CreateTime> 250 <MsgType><![CDATA[image]]></MsgType> 251 $item_str 252 </xml>"; 253 254 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 255 return $result; 256 } 257 258 //回复语音消息 259 private function transmitVoice($object, $voiceArray) 260 { 261 $itemTpl = "<Voice> 262 <MediaId><![CDATA[%s]]></MediaId> 263 </Voice>"; 264 265 $item_str = sprintf($itemTpl, $voiceArray['MediaId']); 266 267 $xmlTpl = "<xml> 268 <ToUserName><![CDATA[%s]]></ToUserName> 269 <FromUserName><![CDATA[%s]]></FromUserName> 270 <CreateTime>%s</CreateTime> 271 <MsgType><![CDATA[voice]]></MsgType> 272 $item_str 273 </xml>"; 274 275 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 276 return $result; 277 } 278 279 //回复视频消息 280 private function transmitVideo($object, $videoArray) 281 { 282 $itemTpl = "<Video> 283 <MediaId><![CDATA[%s]]></MediaId> 284 <ThumbMediaId><![CDATA[%s]]></ThumbMediaId> 285 <Title><![CDATA[%s]]></Title> 286 <Description><![CDATA[%s]]></Description> 287 </Video>"; 288 289 $item_str = sprintf($itemTpl, $videoArray['MediaId'], $videoArray['ThumbMediaId'], $videoArray['Title'], $videoArray['Description']); 290 291 $xmlTpl = "<xml> 292 <ToUserName><![CDATA[%s]]></ToUserName> 293 <FromUserName><![CDATA[%s]]></FromUserName> 294 <CreateTime>%s</CreateTime> 295 <MsgType><![CDATA[video]]></MsgType> 296 $item_str 297 </xml>"; 298 299 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 300 return $result; 301 } 302 303 //回复图文消息 304 private function transmitNews($object, $newsArray) 305 { 306 if(!is_array($newsArray)){ 307 return; 308 } 309 $itemTpl = " <item> 310 <Title><![CDATA[%s]]></Title> 311 <Description><![CDATA[%s]]></Description> 312 <PicUrl><![CDATA[%s]]></PicUrl> 313 <Url><![CDATA[%s]]></Url> 314 </item> 315 "; 316 $item_str = ""; 317 foreach ($newsArray as $item){ 318 $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']); 319 } 320 $xmlTpl = "<xml> 321 <ToUserName><![CDATA[%s]]></ToUserName> 322 <FromUserName><![CDATA[%s]]></FromUserName> 323 <CreateTime>%s</CreateTime> 324 <MsgType><![CDATA[news]]></MsgType> 325 <ArticleCount>%s</ArticleCount> 326 <Articles> 327 $item_str</Articles> 328 </xml>"; 329 330 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), count($newsArray)); 331 return $result; 332 } 333 334 //回复音乐消息 335 private function transmitMusic($object, $musicArray) 336 { 337 $itemTpl = "<Music> 338 <Title><![CDATA[%s]]></Title> 339 <Description><![CDATA[%s]]></Description> 340 <MusicUrl><![CDATA[%s]]></MusicUrl> 341 <HQMusicUrl><![CDATA[%s]]></HQMusicUrl> 342 </Music>"; 343 344 $item_str = sprintf($itemTpl, $musicArray['Title'], $musicArray['Description'], $musicArray['MusicUrl'], $musicArray['HQMusicUrl']); 345 346 $xmlTpl = "<xml> 347 <ToUserName><![CDATA[%s]]></ToUserName> 348 <FromUserName><![CDATA[%s]]></FromUserName> 349 <CreateTime>%s</CreateTime> 350 <MsgType><![CDATA[music]]></MsgType> 351 $item_str 352 </xml>"; 353 354 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 355 return $result; 356 } 357 358 //回复多客服消息 359 private function transmitService($object) 360 { 361 $xmlTpl = "<xml> 362 <ToUserName><![CDATA[%s]]></ToUserName> 363 <FromUserName><![CDATA[%s]]></FromUserName> 364 <CreateTime>%s</CreateTime> 365 <MsgType><![CDATA[transfer_customer_service]]></MsgType> 366 </xml>"; 367 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 368 return $result; 369 } 370 371 //日志记录 372 private function logger($log_content) 373 { 374 if(isset($_SERVER['HTTP_APPNAME'])){ //SAE 375 sae_set_display_errors(false); 376 sae_debug($log_content); 377 sae_set_display_errors(true); 378 }else if($_SERVER['REMOTE_ADDR'] != "127.0.0.1"){ //LOCAL 379 $max_size = 10000; 380 $log_filename = "log.xml"; 381 if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);} 382 file_put_contents($log_filename, date('H:i:s')." ".$log_content."\r\n", FILE_APPEND); 383 } 384 } 385 } 386 ?>