微信公眾平台開發:初體驗


由於俱樂部的需要,最近開始着手微信公眾平台的開發,之前一直都有使用,不過只是簡單的基於關鍵字的自動回復功能而沒有使用開發者模式。這次開始使用開發者模式,注意【開發者模式】和【自動回復功能】不能共存,也就是說一個處於啟用狀態,另一個只能處於停用狀態。其實微信公眾平台的開發和網頁編寫時一樣的,只不過顯示在微信客戶端中而不是瀏覽器網頁界面。

 

一、開發者原理

二、啟用開發者模式

三、一個簡單的例子

 

一、        開發者原理

要想更好的開發微信公眾平台,理解一下原理還是很重要的,如果出現了錯誤這樣也就更容易調試。

 

微信平台有一個服務器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

微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。

timestamp

時間戳

nonce

隨機數

echostr

隨機字符串


開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,成為開發者成功,否則接入失敗。

加密/校驗流程如下:
1. 將token、timestamp、nonce三個參數進行字典序排序
2. 將三個參數字符串拼接成一個字符串進行sha1加密
3. 開發者獲得加密后的字符串可與signature對比,標識該請求來源於微信啟用接口是由代碼中的checkSignature()函數來實現校驗的。

有點亂的話,也沒問題,之后再例子中還會再說。

 

二、        啟用開發者模式

上面說的是開發者的初次驗證和普通消息接收發送的原理,當然這都是在啟用開發者模式之后才管用的,所以現在我們就來說一說如何啟用開發者模式和相關的一些配置。

進入微信公眾平台公眾號的首頁,選擇開發者中心,點擊進入:

 

這里我的已經配置和啟用完畢了,界面如上圖所示。你首先做的是點擊配置,在配置中你需要填寫四個內容:URL、Token、EncodingAESKey、消息加解密方式,URL就是你的服務器的URL,Token就是一個令牌,填寫什么都可以不過一定要記住,因為之后要使用,EncodingAESKey選擇隨機生成即可,加密方式我選擇了明文模式,填好了這四項,確定之后可能失敗,因為我們忘記了一件事情,就是在自己的服務器中要編寫初次驗證的代碼(這個在例子中會有體現),然后確定配置即可。再選擇啟用即可啟用開發者模式。

 

三、        一個簡單的例子

先把測試代碼拋出,然后進行講解:

 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 wechatCallbackapiTest
17 {
18     public function valid()
19     {
20         $echoStr = $_GET["echostr"];
21 
22         //valid signature , option
23         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 environments
32         $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
33 
34           //extract post data
35         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的格式即可。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM