微信消息接口的目錄為application\weixin\controller\Index.php。它是微信的開發者接口,用於收發用戶發送給公眾號的消息並自動回復。
微信消息接口的實現代碼如下。
1 <?php 2 namespace app\weixin\controller; 3 use think\Controller; 4 use think\Db; 5 6 define("TOKEN", "fangbei"); 7 class Index extends Controller 8 { 9 public function index{ 10 if (!isset($_GET['echostr'])) { 11 $this->responseMsg; 12 }else{ 13 $this->valid; 14 } 15 } 16 17 // 驗證簽名 18 public function valid 19 { 20 $echoStr = $_GET["echostr"]; 21 $signature = $_GET["signature"]; 22 $timestamp = $_GET["timestamp"]; 23 $nonce = $_GET["nonce"]; 24 $token = TOKEN; 25 $tmpArr = array($token, $timestamp, $nonce); 26 sort($tmpArr); 27 $tmpStr = implode($tmpArr); 28 $tmpStr = sha1($tmpStr); 29 if($tmpStr == $signature){ 30 echo $echoStr; 31 exit; 32 } 33 } 34 35 // 響應 36 public function responseMsg 37 { 38 $postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; 39 if (!empty($postStr)){ 40 $this->logger("R ".$postStr); 41 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_ NOCDATA); 42 $RX_TYPE = trim($postObj->MsgType); 43 44 if (($postObj->MsgType == "event") && ($postObj->Event == "subscribe" || $postObj->Event == "unsubscribe" || $postObj->Event == "TEMPLATE- SENDJOBFINISH")){ 45 // 過濾關注和取消關注事件 46 }else{ 47 // 更新互動記錄 48 Db::name('user')->where('openid',strval($postObj->FromUserName))-> setField('heartbeat', time); 49 } 50 // 消息類型分離 51 switch ($RX_TYPE) 52 { 53 case "event": 54 $result = $this->receiveEvent($postObj); 55 break; 56 case "text": 57 $result = $this->receiveText($postObj); 58 break; 59 default: 60 $result = "unknown msg type: ".$RX_TYPE; 61 break; 62 } 63 $this->logger("T ".$result); 64 echo $result; 65 }else { 66 echo ""; 67 exit; 68 } 69 } 70 71 72 // 接收事件消息 73 private function receiveEvent($object) 74 { 75 $weixin = new \weixin\Wxapi; 76 $openid = strval($object->FromUserName); 77 $content = ""; 78 79 switch ($object->Event) 80 { 81 case "subscribe": 82 $info = $weixin->get_user_info($openid); 83 $municipalities = array("北京", "上海", "天津", "重慶", "香港", "澳門"); 84 $sexes = array("", "男", "女"); 85 $data = array; 86 $data['openid'] = $openid; 87 $data['nickname'] = str_replace("'", "", $info['nickname']); 88 $data['sex'] = $sexes[$info['sex']]; 89 $data['country'] = $info['country']; 90 $data['province'] = $info['province']; 91 $data['city'] = (in_array($info['province'], $municipalities)) ?$info['province'] : $info['city']; 92 $data['scene'] = (isset($object->EventKey) && (stripos(strval ($object->EventKey),"qrscene_")))?str_replace("qrscene_","",$object ->EventKey):"0"; 93 94 $data['headimgurl'] = $info['headimgurl']; 95 $data['subscribe'] = $info['subscribe_time']; 96 $data['heartbeat'] = time; 97 $data['remark'] = $info['remark']; 98 $data['score'] = 1; 99 $data['tagid'] = $info['tagid_list']; 100 Db::name('user')->insert($data); 101 $content = "歡迎關注,".$info['nickname']; 102 break; 103 case "unsubscribe": 104 db('user')->where('openid',$openid)->delete; 105 break; 106 case "CLICK": 107 switch ($object->EventKey) 108 { 109 default: 110 $content = "點擊菜單:".$object->EventKey; 111 break; 112 } 113 break; 114 default: 115 $content = ""; 116 break; 117 } 118 if(is_array($content)){ 119 $result = $this->transmitNews($object, $content); 120 }else{ 121 $result = $this->transmitText($object, $content); 122 } 123 124 return $result; 125 } 126 127 // 接收文本消息 128 private function receiveText($object) 129 { 130 $keyword = trim($object->Content); 131 $openid = strval($object->FromUserName); 132 $content = ""; 133 134 if (strstr($keyword, "文本")){ 135 $content = "這是個文本消息\n".$openid; 136 }else{ 137 $content = date("Y-m-d H:i:s",time)."\n".$openid."技術支持 方倍工作室"; 138 } 139 140 if(is_array($content)){ 141 $result = $this->transmitNews($object, $content); 142 }else{ 143 $result = $this->transmitText($object, $content); 144 } 145 return $result; 146 } 147 148 // 回覆文本消息 149 private function transmitText($object, $content) 150 { 151 if (!isset($content) || empty($content)){ 152 return ""; 153 } 154 $xmlTpl = "<xml> 155 <ToUserName><![CDATA[%s]]></ToUserName> 156 <FromUserName><![CDATA[%s]]></FromUserName> 157 <CreateTime>%s</CreateTime> 158 <MsgType><![CDATA[text]]></MsgType> 159 <Content><![CDATA[%s]]></Content> 160 </xml>"; 161 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time, $content); 162 return $result; 163 } 164 165 // 回復圖文消息 166 private function transmitNews($object, $newsArray) 167 { 168 if(!is_array($newsArray)){ 169 return ""; 170 } 171 $itemTpl = " <item> 172 <Title><![CDATA[%s]]></Title> 173 <Description><![CDATA[%s]]></Description> 174 <PicUrl><![CDATA[%s]]></PicUrl> 175 <Url><![CDATA[%s]]></Url> 176 </item> 177 "; 178 $item_str = ""; 179 foreach ($newsArray as $item){ 180 $item_str .= sprintf($itemTpl, $item['Title'], $item['Description'], $item['PicUrl'], $item['Url']); 181 } 182 $xmlTpl = "<xml> 183 <ToUserName><![CDATA[%s]]></ToUserName> 184 <FromUserName><![CDATA[%s]]></FromUserName> 185 <CreateTime>%s</CreateTime> 186 <MsgType><![CDATA[news]]></MsgType> 187 <ArticleCount>%s</ArticleCount> 188 <Articles> 189 $item_str</Articles> 190 </xml>"; 191 192 $result = sprintf($xmlTpl, $object->FromUserName, $object->ToUserName, time, count($newsArray)); 193 return $result; 194 } 195 196 // 日誌記錄 197 private function logger($log_content) 198 { 199 if(isset($_SERVER['HTTP_APPNAME'])){ // SAE 200 sae_set_display_errors(false); 201 sae_debug($log_content); 202 sae_set_display_errors(true); 203 }else if($_SERVER['REMOTE_ADDR'] != "127.0.0.2"){ // LOCAL 204 $max_size = 1000000; 205 $log_filename = "log.xml"; 206 if(file_exists($log_filename) and (abs(filesize($log_filename)) > $max_size)) {unlink($log_filename);} 207 file_put_contents($log_filename, date('H:i:s')." ".$log_content."\ r\n", FILE_APPEND); 208 } 209 } 210 }
上述接口方法中,實現了微信的Token驗證,事件、菜單和文本消息的接收,以及文本、圖文消息的回復。
根據上述接口,配置微信開發者接口時,其接口為http://www.doucube.com/weixin/index/index,可以簡化為http://www.doucube.com/weixin,Token則為fangbei。設置成功後的效果如圖25-5所示。
圖25-5 開發者接口配置成功