微信公眾平臺開發介面PHPSDK完整版
官方提供的SDK只有一個文字訊息功能,我們將所有訊息的訊息型別及事件響應都整理了進來,並且加入日誌記錄,程式碼如下:
更新日誌:
2013-01-01 版本1.0,包含Token驗證及基本訊息介面的收發
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 增加該公眾號暫時無法提供服務請稍後再試的相容
2014-12-20 移除高階群發訊息通知事件,必要性不大
2015-02-23 移除訊息體簽名及加解密的支援,必要性不大
2015-04-07 優化客服模式和自動回覆模式的判定
2015-05-16 優化日誌記錄,相容SAE和自有主機
1 <?php 2 /* 3 方倍工作室 http://www.fangbei.org/ 4 CopyRight 2015 All Rights Reserved 5 */ 6 7 define("TOKEN", "weixin"); 8 9 $wechatObj = new wechatCallbackapiTest(); 10 if (!isset($_GET[`echostr`])) { 11 $wechatObj->responseMsg(); 12 }else{ 13 $wechatObj->valid(); 14 } 15 16 class wechatCallbackapiTest 17 { 18 //驗證簽名 19 public function valid() 20 { 21 $echoStr = $_GET["echostr"]; 22 $signature = $_GET["signature"]; 23 $timestamp = $_GET["timestamp"]; 24 $nonce = $_GET["nonce"]; 25 $token = TOKEN; 26 $tmpArr = array($token, $timestamp, $nonce); 27 sort($tmpArr, SORT_STRING); 28 $tmpStr = implode($tmpArr); 29 $tmpStr = sha1($tmpStr); 30 if($tmpStr == $signature){ 31 echo $echoStr; 32 exit; 33 } 34 } 35 36 //響應訊息 37 public function responseMsg() 38 { 39 $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; 40 if (!empty($postStr)){ 41 $this->logger("R ".$postStr); 42 $postObj = simplexml_load_string($postStr, `SimpleXMLElement`, LIBXML_NOCDATA); 43 $RX_TYPE = trim($postObj->MsgType); 44 45 if (($postObj->MsgType == "event") && ($postObj->Event == "subscribe" || $postObj->Event == "unsubscribe")){ 46 //過濾關注和取消關注事件 47 }else{ 48 49 } 50 51 //訊息型別分離 52 switch ($RX_TYPE) 53 { 54 case "event": 55 $result = $this->receiveEvent($postObj); 56 break; 57 case "text": 58 if (strstr($postObj->Content, "第三方")){ 59 $result = $this->relayPart3("http://www.fangbei.org/test.php".`?`.$_SERVER[`QUERY_STRING`], $postStr); 60 }else{ 61 $result = $this->receiveText($postObj); 62 } 63 break; 64 case "image": 65 $result = $this->receiveImage($postObj); 66 break; 67 case "location": 68 $result = $this->receiveLocation($postObj); 69 break; 70 case "voice": 71 $result = $this->receiveVoice($postObj); 72 break; 73 case "video": 74 $result = $this->receiveVideo($postObj); 75 break; 76 case "link": 77 $result = $this->receiveLink($postObj); 78 break; 79 default: 80 $result = "unknown msg type: ".$RX_TYPE; 81 break; 82 } 83 $this->logger("T ".$result); 84 echo $result; 85 }else { 86 echo ""; 87 exit; 88 } 89 } 90 91 //接收事件訊息 92 private function receiveEvent($object) 93 { 94 $content = ""; 95 switch ($object->Event) 96 { 97 case "subscribe": 98 $content = "歡迎關注方倍工作室 "; 99 $content .= (!empty($object->EventKey))?(" 來自二維碼場景 ".str_replace("qrscene_","",$object->EventKey)):""; 100 break; 101 case "unsubscribe": 102 $content = "取消關注"; 103 break; 104 case "CLICK": 105 switch ($object->EventKey) 106 { 107 case "COMPANY": 108 $content = array(); 109 $content[] = array("Title"=>"方倍工作室", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 110 break; 111 default: 112 $content = "點選選單:".$object->EventKey; 113 break; 114 } 115 break; 116 case "VIEW": 117 $content = "跳轉連結 ".$object->EventKey; 118 break; 119 case "SCAN": 120 $content = "掃描場景 ".$object->EventKey; 121 break; 122 case "LOCATION": 123 $content = "上傳位置:緯度 ".$object->Latitude.";經度 ".$object->Longitude; 124 break; 125 case "scancode_waitmsg": 126 if ($object->ScanCodeInfo->ScanType == "qrcode"){ 127 $content = "掃碼帶提示:型別 二維碼 結果:".$object->ScanCodeInfo->ScanResult; 128 }else if ($object->ScanCodeInfo->ScanType == "barcode"){ 129 $codeinfo = explode(",",strval($object->ScanCodeInfo->ScanResult)); 130 $codeValue = $codeinfo[1]; 131 $content = "掃碼帶提示:型別 條形碼 結果:".$codeValue; 132 }else{ 133 $content = "掃碼帶提示:型別 ".$object->ScanCodeInfo->ScanType." 結果:".$object->ScanCodeInfo->ScanResult; 134 } 135 break; 136 case "scancode_push": 137 $content = "掃碼推事件"; 138 break; 139 case "pic_sysphoto": 140 $content = "系統拍照"; 141 break; 142 case "pic_weixin": 143 $content = "相簿發圖:數量 ".$object->SendPicsInfo->Count; 144 break; 145 case "pic_photo_or_album": 146 $content = "拍照或者相簿:數量 ".$object->SendPicsInfo->Count; 147 break; 148 case "location_select": 149 $content = "傳送位置:標籤 ".$object->SendLocationInfo->Label; 150 break; 151 default: 152 $content = "receive a new event: ".$object->Event; 153 break; 154 } 155 156 if(is_array($content)){ 157 if (isset($content[0][`PicUrl`])){ 158 $result = $this->transmitNews($object, $content); 159 }else if (isset($content[`MusicUrl`])){ 160 $result = $this->transmitMusic($object, $content); 161 } 162 }else{ 163 $result = $this->transmitText($object, $content); 164 } 165 return $result; 166 } 167 168 //接收文字訊息 169 private function receiveText($object) 170 { 171 $keyword = trim($object->Content); 172 //多客服人工回覆模式 173 if (strstr($keyword, "請問在嗎") || strstr($keyword, "線上客服")){ 174 $result = $this->transmitService($object); 175 return $result; 176 } 177 178 //自動回覆模式 179 if (strstr($keyword, "文字")){ 180 $content = "這是個文字訊息"; 181 }else if (strstr($keyword, "表情")){ 182 $content = "中國:".$this->bytes_to_emoji(0x1F1E8).$this->bytes_to_emoji(0x1F1F3)." 仙人掌:".$this->bytes_to_emoji(0x1F335); 183 }else if (strstr($keyword, "單圖文")){ 184 $content = array(); 185 $content[] = array("Title"=>"單圖文標題", "Description"=>"單圖文內容", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 186 }else if (strstr($keyword, "圖文") || strstr($keyword, "多圖文")){ 187 $content = array(); 188 $content[] = array("Title"=>"多圖文1標題", "Description"=>"", "PicUrl"=>"http://discuz.comli.com/weixin/weather/icon/cartoon.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 189 $content[] = array("Title"=>"多圖文2標題", "Description"=>"", "PicUrl"=>"http://d.hiphotos.bdimg.com/wisegame/pic/item/f3529822720e0cf3ac9f1ada0846f21fbe09aaa3.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 190 $content[] = array("Title"=>"多圖文3標題", "Description"=>"", "PicUrl"=>"http://g.hiphotos.bdimg.com/wisegame/pic/item/18cb0a46f21fbe090d338acc6a600c338644adfd.jpg", "Url" =>"http://m.cnblogs.com/?u=txw1958"); 191 }else if (strstr($keyword, "音樂")){ 192 $content = array(); 193 $content = array("Title"=>"最炫民族風", "Description"=>"歌手:鳳凰傳奇", "MusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3", "HQMusicUrl"=>"http://121.199.4.61/music/zxmzf.mp3"); 194 }else{ 195 $content = date("Y-m-d H:i:s",time())." OpenID:".$object->FromUserName." 技術支援 方倍工作室"; 196 } 197 198 if(is_array($content)){ 199 if (isset($content[0])){ 200 $result = $this->transmitNews($object, $content); 201 }else if (isset($content[`MusicUrl`])){ 202 $result = $this->transmitMusic($object, $content); 203 } 204 }else{ 205 $result = $this->transmitText($object, $content); 206 } 207 return $result; 208 } 209 210 //接收圖片訊息 211 private function receiveImage($object) 212 { 213 $content = array("MediaId"=>$object->MediaId); 214 $result = $this->transmitImage($object, $content); 215 return $result; 216 } 217 218 //接收位置訊息 219 private function receiveLocation($object) 220 { 221 $content = "你傳送的是位置,經度為:".$object->Location_Y.";緯度為:".$object->Location_X.";縮放級別為:".$object->Scale.";位置為:".$object->Label; 222 $result = $this->transmitText($object, $content); 223 return $result; 224 } 225 226 //接收語音訊息 227 private function receiveVoice($object) 228 { 229 if (isset($object->Recognition) && !empty($object->Recognition)){ 230 $content = "你剛才說的是:".$object->Recognition; 231 $result = $this->transmitText($object, $content); 232 }else{ 233 $content = array("MediaId"=>$object->MediaId); 234 $result = $this->transmitVoice($object, $content); 235 } 236 return $result; 237 } 238 239 //接收視訊訊息 240 private function receiveVideo($object) 241 { 242 $content = array("MediaId"=>$object->MediaId, "ThumbMediaId"=>$object->ThumbMediaId, "Title"=>"", "Description"=>""); 243 $result = $this->transmitVideo($object, $content); 244 return $result; 245 } 246 247 //接收連結訊息 248 private function receiveLink($object) 249 { 250 $content = "你傳送的是連結,標題為:".$object->Title.";內容為:".$object->Description.";連結地址為:".$object->Url; 251 $result = $this->transmitText($object, $content); 252 return $result; 253 } 254 255 //回覆文字訊息 256 private function transmitText($object, $content) 257 { 258 if (!isset($content) || empty($content)){ 259 return ""; 260 } 261 262 $xmlTpl = "<xml> 263 <ToUserName><![CDATA[%s]]></ToUserName> 264 <FromUserName><![CDATA[%s]]></FromUserName> 265 <CreateTime>%s</CreateTime> 266 <MsgType><![CDATA[text]]></MsgType> 267 <Content><![CDATA[%s]]></Content> 268 </xml>"; 269 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), $content); 270 271 return $result; 272 } 273 274 //回覆圖文訊息 275 private function transmitNews($object, $newsArray) 276 { 277 if(!is_array($newsArray)){ 278 return ""; 279 } 280 $itemTpl = " <item> 281 <Title><![CDATA[%s]]></Title> 282 <Description><![CDATA[%s]]></Description> 283 <PicUrl><![CDATA[%s]]></PicUrl> 284 <Url><![CDATA[%s]]></Url> 285 </item> 286 "; 287 $item_str = ""; 288 foreach ($newsArray as $item){ 289 $item_str .= sprintf($itemTpl, $item[`Title`], $item[`Description`], $item[`PicUrl`], $item[`Url`]); 290 } 291 $xmlTpl = "<xml> 292 <ToUserName><![CDATA[%s]]></ToUserName> 293 <FromUserName><![CDATA[%s]]></FromUserName> 294 <CreateTime>%s</CreateTime> 295 <MsgType><![CDATA[news]]></MsgType> 296 <ArticleCount>%s</ArticleCount> 297 <Articles> 298 $item_str </Articles> 299 </xml>"; 300 301 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time(), count($newsArray)); 302 return $result; 303 } 304 305 //回覆音樂訊息 306 private function transmitMusic($object, $musicArray) 307 { 308 if(!is_array($musicArray)){ 309 return ""; 310 } 311 $itemTpl = "<Music> 312 <Title><![CDATA[%s]]></Title> 313 <Description><![CDATA[%s]]></Description> 314 <MusicUrl><![CDATA[%s]]></MusicUrl> 315 <HQMusicUrl><![CDATA[%s]]></HQMusicUrl> 316 </Music>"; 317 318 $item_str = sprintf($itemTpl, $musicArray[`Title`], $musicArray[`Description`], $musicArray[`MusicUrl`], $musicArray[`HQMusicUrl`]); 319 320 $xmlTpl = "<xml> 321 <ToUserName><![CDATA[%s]]></ToUserName> 322 <FromUserName><![CDATA[%s]]></FromUserName> 323 <CreateTime>%s</CreateTime> 324 <MsgType><![CDATA[music]]></MsgType> 325 $item_str 326 </xml>"; 327 328 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 329 return $result; 330 } 331 332 //回覆圖片訊息 333 private function transmitImage($object, $imageArray) 334 { 335 $itemTpl = "<Image> 336 <MediaId><![CDATA[%s]]></MediaId> 337 </Image>"; 338 339 $item_str = sprintf($itemTpl, $imageArray[`MediaId`]); 340 341 $xmlTpl = "<xml> 342 <ToUserName><![CDATA[%s]]></ToUserName> 343 <FromUserName><![CDATA[%s]]></FromUserName> 344 <CreateTime>%s</CreateTime> 345 <MsgType><![CDATA[image]]></MsgType> 346 $item_str 347 </xml>"; 348 349 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 350 return $result; 351 } 352 353 //回覆語音訊息 354 private function transmitVoice($object, $voiceArray) 355 { 356 $itemTpl = "<Voice> 357 <MediaId><![CDATA[%s]]></MediaId> 358 </Voice>"; 359 360 $item_str = sprintf($itemTpl, $voiceArray[`MediaId`]); 361 $xmlTpl = "<xml> 362 <ToUserName><![CDATA[%s]]></ToUserName> 363 <FromUserName><![CDATA[%s]]></FromUserName> 364 <CreateTime>%s</CreateTime> 365 <MsgType><![CDATA[voice]]></MsgType> 366 $item_str 367 </xml>"; 368 369 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 370 return $result; 371 } 372 373 //回覆視訊訊息 374 private function transmitVideo($object, $videoArray) 375 { 376 $itemTpl = "<Video> 377 <MediaId><![CDATA[%s]]></MediaId> 378 <ThumbMediaId><![CDATA[%s]]></ThumbMediaId> 379 <Title><![CDATA[%s]]></Title> 380 <Description><![CDATA[%s]]></Description> 381 </Video>"; 382 383 $item_str = sprintf($itemTpl, $videoArray[`MediaId`], $videoArray[`ThumbMediaId`], $videoArray[`Title`], $videoArray[`Description`]); 384 385 $xmlTpl = "<xml> 386 <ToUserName><![CDATA[%s]]></ToUserName> 387 <FromUserName><![CDATA[%s]]></FromUserName> 388 <CreateTime>%s</CreateTime> 389 <MsgType><![CDATA]></MsgType> 390 $item_str 391 </xml>"; 392 393 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 394 return $result; 395 } 396 397 //回覆多客服訊息 398 private function transmitService($object) 399 { 400 $xmlTpl = "<xml> 401 <ToUserName><![CDATA[%s]]></ToUserName> 402 <FromUserName><![CDATA[%s]]></FromUserName> 403 <CreateTime>%s</CreateTime> 404 <MsgType><![CDATA[transfer_customer_service]]></MsgType> 405 </xml>"; 406 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time()); 407 return $result; 408 } 409 410 //回覆第三方介面訊息 411 private function relayPart3($url, $rawData) 412 { 413 $headers = array("Content-Type: text/xml; charset=utf-8"); 414 $ch = curl_init(); 415 curl_setopt($ch, CURLOPT_URL, $url); 416 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 417 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 418 curl_setopt($ch, CURLOPT_POST, 1); 419 curl_setopt($ch, CURLOPT_POSTFIELDS, $rawData); 420 $output = curl_exec($ch); 421 curl_close($ch); 422 return $output; 423 } 424 425 //位元組轉Emoji表情 426 function bytes_to_emoji($cp) 427 { 428 if ($cp > 0x10000){ # 4 bytes 429 return chr(0xF0 | (($cp & 0x1C0000) >> 18)).chr(0x80 | (($cp & 0x3F000) >> 12)).chr(0x80 | (($cp & 0xFC0) >> 6)).chr(0x80 | ($cp & 0x3F)); 430 }else if ($cp > 0x800){ # 3 bytes 431 return chr(0xE0 | (($cp & 0xF000) >> 12)).chr(0x80 | (($cp & 0xFC0) >> 6)).chr(0x80 | ($cp & 0x3F)); 432 }else if ($cp > 0x80){ # 2 bytes 433 return chr(0xC0 | (($cp & 0x7C0) >> 6)).chr(0x80 | ($cp & 0x3F)); 434 }else{ # 1 byte 435 return chr($cp); 436 } 437 } 438 439 //日誌記錄 440 private function logger($log_content) 441 { 442 if(isset($_SERVER[`HTTP_APPNAME`])){ //SAE 443 sae_set_display_errors(false); 444 sae_debug($log_content); 445 sae_set_display_errors(true); 446 }else if($_SERVER[`REMOTE_ADDR`] != "127.0.0.1"){ //LOCAL 447 $max_size = 1000000; 448 $log_filename = "log.xml"; 449 if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)){unlink($log_filename);} 450 file_put_contents($log_filename, date(`Y-m-d H:i:s`)." ".$log_content." ", FILE_APPEND); 451 } 452 } 453 } 454 ?>
本程式在新浪雲、阿里雲、騰訊雲、百度雲 均測試通過。
不會使用,或者使用出錯的朋友,請參考微信開發入門教程,地址:http://www.cnblogs.com/txw1958/p/wechat-tutorial.html
相關文章
- 微信公眾平臺介面APIAPI
- 1.PHP微信公眾平臺開發(一) 配置介面PHP
- C#微信公眾平臺開發—高階群發介面C#
- 微信公眾平臺開發入門
- Senparc.Weixin.MP SDK 微信公眾平臺開發教程(三):微信公眾平臺開發驗證
- 微信公眾平臺開發JS-SDK開發(影像介面例項)JS
- 微信公眾平臺JSSDK分享介面開發(PHP實現)JSPHP
- 微信公眾平臺通用介面API指南API
- PHP微信公眾平臺開發視訊PHP
- 微信公眾平臺開發(十一) 功能整合
- 微信公眾平臺完整開發教程 by ZTalk
- 微信公眾平臺開發(六) 翻譯功能開發
- 微信公眾平臺開發之店鋪類
- 基於 PHP 的微信公眾平臺開發PHP
- 2.PHP微信公眾平臺開發(二) 公眾平臺示例程式碼分PHP
- 微信公眾介面開發介紹
- 微信公眾平臺開發(四) 簡單回覆功能開發
- 微信公眾平臺搭建與開發揭祕.pdf
- 微信公眾平臺開發(77) 圖片下載
- 微信公眾平臺開發(九) 資料庫操作資料庫
- 6.PHP微信公眾平臺開發 - 翻譯功能開發PHP
- 微信公眾平臺開發(五) 天氣預報功能開發
- 微信公眾平臺開發(七) 聊天機器人功能開發機器人
- 微信公眾平臺開發(八) 自定義選單功能開發
- 微信公眾平臺開發(81) 2014新年微信賀卡
- 微信公眾平臺SDK for node
- 微信公眾號定時群發平臺
- Senparc.Weixin.MP SDK 微信公眾平臺開發教程(八):通用介面說明
- 移動開發:微信公眾平臺訊息介面-java-jsp版(轉)移動開發JavaJS
- 9.微信公眾平臺開發 - 資料庫操作資料庫
- ***wechat-php-sdk微信公眾平臺php開發包PHP
- java開發微信公眾平臺(一)-- 伺服器配置Java伺服器
- 微信公眾平臺開發(十二) 傳送客服訊息
- 微信公眾平臺開發(十) 訊息回覆總結
- 7.PHP微信公眾平臺開發 聊天機器人開發PHP機器人
- 4.PHP微信公眾平臺開發 - 簡單回覆功能開發PHP
- Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十一):高階介面說明
- Senparc.Weixin.MP SDK 微信公眾平臺開發教程(十):多客服介面說明