讀古今文學網 > 微信公眾平台開發:從零基礎到ThinkPHP5高性能框架實踐 > 25.4.1 微信消息接口實現 >

25.4.1 微信消息接口實現

微信消息接口的目錄為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 開發者接口配置成功