微信消息接口的目录为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'])){ // SAE200 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"){ // LOCAL204 $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 开发者接口配置成功