本節書摘來自華章計算機《微信公衆平台開發:從零基礎到thinkphp5高性能架構實踐》一書中的第3章,第3.3節,作者 方倍工作室,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。
單擊進入配置頁面,可以看到目前有伺服器配置資訊,狀态為未啟用,如圖3-20所示。

單擊“修改配置”按鈕,進入修改頁面,如圖3-21所示。
在彈出的提示框中單擊“确定”按鈕,相關參數填寫成功,如圖3-23所示。
再單擊右上角的“啟用”按鈕,啟用伺服器的配置。系統彈出提示框,詢問“是否确定開啟伺服器配置”,如圖3-24所示。
單擊“确定”按鈕,将啟用伺服器配置。
如果單擊按鈕後,上方提示“token驗證失敗”,可以重試幾次,微信伺服器有時不穩定也會造成這樣的情況,并不是程式本身有問題。啟用成功後的界面如圖3-25所示。
這樣就成功配置并啟用了伺服器。
送出url和token的時候,有時會碰到送出不成功的情況,具體有以下幾種。
1.請求url逾時
這種情況一般是由于伺服器網速或響應速度太慢。此時可以先重試幾次或者等一段時間再試,如果還是這樣,則需要考慮更換速度更快、性能更好的伺服器。
2.系統發生錯誤,請稍後重試
這種情況一般是由于微信伺服器短時間内的異常引起的,一般重試或者過一段時間嘗試即可。
3.token驗證失敗
這種情況需要具體分析驗證過程被卡在哪一個環節了。此時可以通過調用變量$_server來擷取伺服器和執行環境資訊,以便進行分析。
這裡需要使用以下兩個元素。
$_server['remote_addr']:來訪者的ip位址,此處為微信伺服器的ip位址。
$_server['query_string']:查詢請求字元串,此處為微信伺服器發過來的get請求字元串。
将以上兩個變量記錄到日志中。函數定義如下。
上面代碼中,當環境為sae時,使用sae的調試函數sae_debug()将内容記錄到日志中。而在具有讀寫權限的空間下,使用file_put_contents()函數把字元串寫入檔案。
然後在程式的資料處理之前調用該函數,記錄資訊,代碼如下。
當送出url和token驗證的時候,程式目錄下應當生成一個log.xml檔案。内容類似如下。
下面可以得出初步結論。
沒有生成日志檔案:微信伺服器沒有通路到你的伺服器,需要先檢查你的伺服器是否可以通過公網通路,以及url路徑是否正确并且可以通路。如果可以通過公網通路,而微信伺服器不能通路,那麼可能是防火牆攔截了80端口或微信伺服器的ip位址,也可能是伺服器所在區域與微信伺服器通信不暢,需要更換伺服器。
已經生成日志檔案:檢視remote_addr和query_string的内容是否與上述類似。确認signature、timestamp、nonce、echostr等4個參數都有值。如果這些都沒有問題,則檢查程式中定義的token值是否與送出的一緻,再檢查程式流程及資料處理是否與官方文檔描述的一緻。
如果确定以上均沒有問題,可以使用下面章節中的微信調試器進行測試,它提供了更為寬松的校驗方式,并且可以實時輸出目前的xml資料供調試時參考。
在上面的例子中,已經嵌入了一個簡單的時間查詢功能,發送一個問号“?”就能回複目前的時間,如圖3-26所示。
這個功能是基于下面的代碼實作的。
上述代碼在收到消息後,判斷消息内容是否為問号(包括英文輸入狀态下的問号和中文輸入狀态下的問号),如果包含,則将目前時間(包括年月日時分秒)作為回複内容,構造成一個消息回複給使用者。這樣公衆号就實作了目前時間的自動回複。
下面結合3.3.3節的代碼來分析微信公衆平台的消息互動原理。下面的代碼基于微信公衆平台官方示例代碼修改完善而成。
首先看一下代碼的結構。
第2~5行是注釋部分。
第7行使用define()函數定義常量,常量名稱為token,常量的值為weixin,這個值就是在啟用開發模式時填寫的token。
第15~75行定義了一個類wechatcallbackapitest,并在類中定義了3個方法valid()、checksignature()和responsemsg()。
第8~13行為程式執行語句。第8行執行個體化了一個類對象。在第9行中,判斷是否有get請求有echostr變量,如果有,則執行valid()方法,否則執行responsemsg()方法。
下面分析微信消息互動流程。
送出url和token申請驗證的時候,微信伺服器将發送get請求到填寫的url上,并且帶上4個參數(signature、timestamp、nonce、echostr)。get請求類似如下。
上述請求的參數說明如表3-1所示。
這個get請求是包含echostr變量的,是以執行valid()方法。在該方法中,又調用了校驗簽名方法checksignature()。如果簽名校驗為真,則原樣輸出變量$echostr的值。
加密/校驗流程如下。
1)将token、timestamp、nonce等3個參數進行字典序排序,見第33~34行。
2)将3個參數字元串拼接成一個字元串進行sha1加密,見第35~36行。
3)開發者獲得加密後的字元串可與signature對比,辨別該請求來源于微信,見第38~42行。
發送問号的時候,微信伺服器也會帶上前面3個參數(signature、timestamp、nonce)通路開發者設定的url,同時還會将消息的xml資料包post到url上。xml格式類似如下。
而消息請求不包含echostr變量,是以将執行響應消息方法responsemsg()。
響應消息方法首先接收上述原始post資料,見第47行。
然後它将資料載入對象中,對象名為simplexmlelement,libxml_nocdata?表示将cdata合并為文本節點,代碼中第50行實作此功能。
第51~54行取得xml類對象的值,并賦給新的變量,注意發送方變為接收方,接收方變為發送方。
第55~62行構造要回複的xml資料包。
第63行判斷發送過來的關鍵字是不是問号。
第64~65行設定回複的消息類型為text,内容為目前年月日時分秒。
第66~67行封裝回複的xml資料包,并且向微信伺服器輸出。xml格式如下。
這樣使用者就會收到回複的消息,效果如圖3-26所示。
在圖3-21中,微信公衆平台在配置伺服器時,提供了3種加解密模式供開發者選擇,即“明文模式”、“相容模式”、“安全模式(推薦)”。選擇“相容模式”和“安全模式(推薦)”前,需在開發者中心填寫aes對稱加密算法的消息加解密密鑰encodingaeskey。公衆号用此密鑰對收到的密文消息體進行解密,回複消息體也用此密鑰加密。
明文模式:維持現有模式,沒有适配加解密新特性,消息體明文收發,預設設定為明文模式。
相容模式:公衆平台發送消息内容将同時包括明文和密文,消息包長度增加到原來的3倍左右;公衆号回複明文或密文均可,不影響現有消息收發;開發者可在此模式下進行調試。
安全模式(推薦):公衆平台發送消息體的内容隻含有密文,公衆号回複的消息體也為密文,建議開發者在調試成功後使用此模式收發消息。
消息體加解密的實作過程如下。
假設本次的開發配置中url為
接口程式中需要配置以下3個參數。
當使用者向公衆号發送消息時,微信公衆号将會在url中帶上signature、timestamp、nonce、encrypt_type、msg_signature等參數,類似如下。
同時向該接口推送如下xml消息,即一個已加密的消息。
這時程式需要從url中獲得以下參數。這些參數将用于加解密過程。
接口程式收到消息後,先進行解密,解密部分代碼如下。
解密完成後,把解密内容又傳回給$poststr,這是為了将消息中解密後的内容和明文模式時的消息統一,友善後續處理。解密後的xml如下。
對消息在自己的原有的代碼流程中處理,完成之後,一個要回複的文本消息如下。
把上述消息加密,傳回給微信公衆号,加密過程如下。
加密後的内容如下。
這樣一個安全模式下的加解密消息就完成了。
完整的代碼如下。