由于俱樂部的需要,最近開始著手微信公眾平臺的開發,之前一直都有使用,不過只是簡單的基于關鍵字的自動回復功能而沒有使用開發者模式。這次開始使用開發者模式,注意【開發者模式】和【自動回復功能】不能共存,也就是說一個處于啟用狀態,另一個只能處于停用狀態。其實微信公眾平臺的開發和網頁編寫時一樣的,只不過顯示在微信客戶端中而不是瀏覽器網頁界面。
一、開發者原理
二、啟用開發者模式
三、一個簡單的例子
一、 開發者原理
要想更好的開發微信公眾平臺,理解一下原理還是很重要的,如果出現了錯誤這樣也就更容易調試。

微信平臺有一個服務器A用于與手機微信客戶端通訊(接收和發送消息),如果啟用開發者模式,還需要一個服務器B(需要自己準備),服務器A接收客戶端發來的消息a,并將消息a發送給服務器B,在服務器B中對消息進行處理返回消息b(這里便是開發者主要要實現的功能)給服務器A,微信平臺的服務器A再將消息b發給客戶端,這就是大體的消息發送和回應的原理。
以上描述的是在已經成為開發者之后,公眾號的關注者發送消息時的情景。
在初次申請成為開發者時,你需要準備的是一個服務器(我使用的是SAE),然后需要在公眾號中配置一下,主要也就是告訴公眾號(處于服務器A中)你的服務器在哪里(服務器B的URL)以及其他信息。之后就需要一個初次驗證,也就是讓服務器A和服務器B相互熟悉熟悉,畢竟以后要一起工作啦。
開發模式成為開發者時的消息校驗原理
在開發者首次提交驗證申請時,微信服務器將發送GET請求到填寫的URL上,并且帶上四個參數(signature、timestamp、nonce、echostr),開發者通過對簽名(即signature)的效驗,來判斷此條消息的真實性。此后,每次開發者接收用戶消息的時候,微信也都會帶上前面三個參數(signature、timestamp、nonce)訪問開發者設置的URL。
開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,成為開發者成功,否則接入失敗。
加密/校驗流程如下:
1. 將token、timestamp、nonce三個參數進行字典序排序
2. 將三個參數字符串拼接成一個字符串進行sha1加密
3. 開發者獲得加密后的字符串可與signature對比,標識該請求來源于微信啟用接口是由代碼中的checkSignature()函數來實現校驗的。
有點亂的話,也沒問題,之后再例子中還會再說。
二、啟用開發者模式
上面說的是開發者的初次驗證和普通消息接收發送的原理,當然這都是在啟用開發者模式之后才管用的,所以現在我們就來說一說如何啟用開發者模式和相關的一些配置。
進入微信公眾平臺公眾號的首頁,選擇開發者中心,點擊進入:

這里我的已經配置和啟用完畢了,界面如上圖所示。你首先做的是點擊配置,在配置中你需要填寫四個內容:URL、Token、EncodingAESKey、消息加解密方式,URL就是你的服務器的URL,Token就是一個令牌,填寫什么都可以不過一定要記住,因為之后要使用,EncodingAESKey選擇隨機生成即可,加密方式我選擇了明文模式,填好了這四項,確定之后可能失敗,因為我們忘記了一件事情,就是在自己的服務器中穴ky"http://www.it165.net/qq/" target="_blank" html' target='_blank'>class="keylink">qqx4NC0s/W0ztHp1qS1xLT6wuujqNXiuPbU2sD919PW0Lvh09DM5c/Wo6mjrMi7uvPIt7aoxeTWw7y0v8mho9TZ0aHU8cb008O8tL/JxvTTw7+qt6LV38Sjyr2hozwvcD4KCjxwPjxzdHJvbmc+yP2hoiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOwo8L3N0cm9uZz48c3Ryb25nPtK7uPa88rWltcTA/dfTPC9zdHJvbmc+PC9wPgo8cD7PyLDRsuLK1LT6wuvF17P2o6zIu7rzvfjQ0L2yveKjujwvcD4KCjxwcmUgY2xhc3M9"brush:java;"> 1 <?php 2 /** 3 * wechat php test 4 * update time: 20150114 5 */ 6 7 //define your token 8 define("TOKEN", "weixin"); 9 $wechatObj = new wechatCallbackapiTest();10 if (isset($_GET['echostr'])) {11 $wechatObj->valid();12 }else{13 $wechatObj->responseMsg();14 }15 16 class wechatCallbackapiTest17 {18 public function valid()19 {20 $echoStr = $_GET["echostr"];21 22 //valid signature , option23 if($this->checkSignature()){24 echo $echoStr;25 exit;26 }27 }28 29 public function responseMsg()30 {31 //get post data, May be due to the different environments32 $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];33 34 //extract post data35 if (!empty($postStr)){36 37 $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);38 $fromUsername = $postObj->FromUserName;39 $toUsername = $postObj->ToUserName;40 $keyword = trim($postObj->Content);41 $time = time();42 $textTpl = "<xml>43 <ToUserName><![CDATA[%s]]></ToUserName>44 <FromUserName><![CDATA[%s]]></FromUserName>45 <CreateTime>%s</CreateTime>46 <MsgType><![CDATA[%s]]></MsgType>47 <Content><![CDATA[%s]]></Content>48 <FuncFlag>0</FuncFlag>49 </xml>"; 50 if(!empty( $keyword ))51 {52 $msgType = "text";53 $contentStr = "Welcome to wechat world!";54 $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);55 echo $resultStr;56 }else{57 echo "Input something...";58 }59 60 }else {61 echo "";62 exit;63 }64 }65 66 private function checkSignature()67 {68 $signature = $_GET["signature"];69 $timestamp = $_GET["timestamp"];70 $nonce = $_GET["nonce"];71 $token = TOKEN;72 $tmpArr = array($token, $timestamp, $nonce);73 sort($tmpArr, SORT_STRING);74 $tmpStr = implode( $tmpArr );75 $tmpStr = sha1( $tmpStr );76 77 if( $tmpStr == $signature ){78 return true;79 }else{80 return false;81 }82 }83 }84 85 ?>
我之前定義的Token是“weixin”所以在代碼中也要定義相應的Token,有了之前的原理說明我們知道,如果是在開發者首次提交驗證申請時,微信服務器將發送GET請求到填寫的URL上,并且帶上四個參數(signature、timestamp、nonce、echostr),開發者通過對簽名(即signature)的效驗,來判斷此條消息的真實性。我們通過GET中是否含echostr來判斷是不是首次提交驗證申請,如果是,我們調用$wechatObj->valid()來驗證消息的真實性,驗證的方法在前面已經提到過,具體的代碼在checkSignature()中。
如果消息并不是提交驗證申請,那么,我們調用$wechatObj->responseMsg()來回應用戶發送的文本消息,回應的文本是“Welcome to wechat world!”。
下面簡要的說一下responseMsg()這個函數,它主要功能是用戶發送非空的文本,返回給用戶一個文本“Welcome to wechat world!”:
1. 獲取post數據,存入$postStr中;
2. 如果非空,解析$postStr,存入對象$postObj中;
3. 通過$postObj獲取$fromUsername(發送方)、$toUsername(接收方)、$keyword(關鍵字)、$time(時間);
說到這里,不得不提一下微信端的服務器A和我們自己的服務器B之間發送的消息是怎樣的,絕不僅僅是用戶在客戶端發送的字符串,而是XML數據包的格式,下面是一個例子:
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>1348831860</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[this is a test]]></Content> <FuncFlag>0</FuncFlag></xml>
標簽依次記錄接收方、發送方、創建時間、消息類型、消息內容。無論是A發送給B,還是B發送給A都是以此格式發送,當B準備好數據發送給A時,B的發送方就是之前的接收方,接收方就是之前的發送方,時間不變,類型也是text,內容成為“Welcome to wechat world!”,對應的代碼就是:
1 $fromUsername = $postObj->FromUserName; 2 $toUsername = $postObj->ToUserName; 3 $keyword = trim($postObj->Content); 4 $time = time(); 5 $textTpl = "<xml> 6 <ToUserName><![CDATA[%s]]></ToUserName> 7 <FromUserName><![CDATA[%s]]></FromUserName> 8 <CreateTime>%s</CreateTime> 9 <MsgType><![CDATA[%s]]></MsgType>10 <Content><![CDATA[%s]]></Content>11 <FuncFlag>0</FuncFlag>12 </xml>"; 13 if(!empty( $keyword ))14 {15 $msgType = "text";16 $contentStr = "Welcome to wechat world!";17 $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);18 echo $resultStr;19 }else{20 echo "Input something...";21 }xml格式的信息就好比填空題試卷,A填完之后發給B,B修改填空題的答案之后再發給A,開發者要做的就是處理接受的數據得到新的數據,并把新的數據填到試卷上。
代碼寫完之后發布在服務器B上,然后配置好微信公眾平臺,使得微信平臺服務器A和服務器B相互連接。啟用開發者模式,客戶端發送任何文本消息就可以接收到“Welcome to wechat world!”的信息啦。其他形式的消息也是如此,只不過更改一下XML的格式即可。
PHP編程鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答