轉:
http://ninghao.net/blog/1441
作者:王皓
發布於:2014-05-30 13:16
更新於:2014-05-31 12:05
我們可以使用 Laravel 框架為微信公眾平台提供一個接口(API),這個接口可以處理微信發送過來的請求,根據這些請求里面的帶的內容,你可以決定怎么樣做出回應,比如返回用戶想要查看的內容,處理用戶想要做的事等等。在你的 Laravel 應用程序做出回應之前,先要判斷一下,這個請求是不是來自微信那里。這篇文章,我們就介紹一下怎么樣判斷請求是不是來自微信,同時也簡單介紹一下 Laravel 這個框架。
微信公眾平台
首先你要做的是申請微信的公眾帳號,目前分成兩種,訂閱號,還有服務號。訂閱號普通人就可以申請,服務號應該需要公司才能申請。服務號比訂閱號可以使用的接口多一些,就是服務號有更多的功能。我申請的是訂閱號,如果有必要的話,去注冊個公司,申請一個服務號也行。
假設你已經通過了公眾帳號(訂閱號或服務號),想要成為微信公眾平台的開發者,你需要給微信提供一個地址,這個地址就應該是你的應用程序上的某個地址,一會兒我們用 Laravel 去創建這個地址。微信會往你提供的這個地址上發出一個請求,在這個請求里面,會包含一些內容,你的應用程序的這個地址,應該返回給微信特定的內容,這個內容已經包含在了微信給你發過來的請求里面,微信收到你的回應以后,如果確定是它想要的東西,這樣,你就可以成為微信的開發者了。
成為微信開發者
其實通過這個驗證是非常簡單的,你只需要把應用接收到的微信發過來的 echostr 這個東西,給它原樣返回去就行了。微信會發送一個 GET 類型的請求到你填寫的地址上,GET 請求就相當於是用戶直接在瀏覽器地址欄上輸入了你的應用的地址,然后按了一下回車。只不過,這個請求帶了一些額外的東西,在你的應用里面,你可以接收到這個請求里帶的這些東西。在 PHP 里面,接收到 GET 請求里的內容,可以訪問 $_GET 這個超級全局變量。比如微信發過來的 GET 請求里面,會包含 echostr,要得到 echostr 對應的內容,可以這樣:
$_GET['echostr']
如果拋開 Laravel 框架,單純用原始的 PHP 代碼的話,可以這樣來通過微信的成為開發者的驗證:
echo $_GET['echostr'];
只需要上面這行代碼。它的意思就是,把微信使用 GET 請求給我們發送過來的 echostr 里面的東西輸出出來。假設這行 php 代碼在你提供的地址的根目錄下,名字是 index.php 。
然后登錄微信公眾平台以后,打開 功能 - 高級功能 - 成為開發者,在這里,會讓你輸入兩樣東西,一個就是微信要把請求發送到的你的應用的地址,另一樣東西叫 token ,你可以隨便怎么去定義這個 token 的內容,微信會用到你在這個 token里的填寫的內容去生成最終的簽名,一會兒我們再詳細介紹一下。
都輸入好以后,點擊 提交,沒有意外的話,你就可以順利成為微信公眾平台的開發者了。
等會兒,前面介紹的方法雖然可以讓你成為開發者,但是我們並不希望這樣做。想像一下,任何人都可以向你的應用的這個地址發送這樣的 GET 請求。所以, 你需要一種方法驗證一下,發送過來的請求是不是來自微信,因為你不想把用戶相關的內容隨便就響應回去。
驗證請求的來源
微信的服務器會把訂閱你的公眾平台的用戶發送到你的微信帳號的信息打個包發到你提供的地址上。你的應用程序接收到微信發過來的信息,處理一下,然后再做出一個響應。當你的程序接收到微信發過來的請求的時候,你得驗證一下這個請求是不是從微信那里發過來的。
這個驗證的過程大概是這樣的,微信向你發送過來的請求里面,帶着幾樣東西,一個微信會生成加密的簽名(一串加密以后的字符串),還有幾樣其它的東西,你的應用程序可以接收到這個請求里面的這些東西的具體的內容,你需要在程序里面,利用這些東西,加上你在微信后台填寫的 token ,去自己生成一個加密的簽名,然后再用這簽名跟微信發送過來的簽名進行對比,如果兩個簽名是一樣的,就說明這個請求是來自微信。這樣你就可以安全的對這個請求做出必要的回應。
下面,我們再從技術的角度去解釋一下這個過程。微信在給你發送的請求里面,會包含三樣東西:
- signature:加密的簽名
- timestamp:時間戳
- nonce:一組隨機的數字
在你第一次提交驗證成為微信開發者的時候,在這個請求里面,還會包含另外一樣東西:
echostr:一組隨機的字符串
signature
這是微信通過特定的方法生成的一組加密的字符串。生成這個東西,用到了 token(你在微信后台自己填寫的),timestamp(請求發生的時間),nonce(一組隨機的數字)。微信會把這幾樣東西排一下順序(字典序),再把排序之后的結果拼成一個字符串,再用 sha1 的方法對這個字符串進行加密,加密以后得到的結果就是這個 signature 。
在我們自己的應用里面,也需要用到同樣的方法,去生成一個自己的 signature,再跟微信那頭生成的 signature 對比一下。一樣的話,說明請求是來自微信的。
在后面,我們再詳細介紹怎么樣使用代碼去實現這個驗證。下面,我們去准備一下應用需要的軟硬件。
買一台服務器
我們就是簡單測試一下,不過也需要一台服務器。早晚你得有這么一台:)可以試試國內的阿里雲之類的雲服務器,月付的話,1G 內存的服務器一個月 70 塊上下,先買一個月試一下。可以自己按照 《CentOS:在阿里雲上運行網站》這個課程自己去配置一下,不過最近阿里雲提供了鏡像市場,雖然沒用過,但覺得想法非常好,就是別人做好的鏡像,你可以直接用,有免費的,有收費的,這些鏡像一般都擁有配置好的環境,你可以根據自己的需求選擇適合自己的鏡像。你把鏡像想成是一塊別人的硬盤就行了,硬盤里面,已經裝好了你需要的東西。
不想麻煩去為網站備案,可以選擇香港服務器與國外的服務器,阿里雲最近也推出了香港節點的服務器,運行在上面的網站是不需要備案的。
你的服務器應該能運行 PHP 應用程序,推薦使用 LAMP 環境,Linux + Apache + Mysql + PHP,或者,你喜歡 Nginx ,可以把 Apahce 換成 Nginx 。注意我們要用的 Laravel ,需要 PHP 5.4 以上的版本。
Laravel 框架
我聽說 Laravel 是一套非常優雅的 PHP 框架,受到了很多非常優秀框架的啟發,比如 Ruby on Rails 。因為 Drupal 8 要來了,它使用了 Symfony 框架,所以就先去看了一下 Symfony ,看介紹的時候說 Laraval 也用到了不少 Symfony 的組件,而且語句優雅,你一定能喜歡上,看到這個廣告語就忍不住去試了一下,打開 Laravel 的網站,我就知道不會錯了。
我是第一次使用框架,覺得 Laravel 很好,用起來特別簡單,了解一些 PHP 的基礎,一點數據庫,一點面向對象的編程方法,基本上就可以去用 Laravel 了。我覺得咱們都應該學一套框架,所以,今年打算出一些 Laravel 的基礎課程,目前基本上已經定稿了,出完了 PHP 基礎以后,就把 Laravel 的基礎也制作出來。
PHP 5.5
Laravel 需要使用 PHP 5.4 以上的版本,先確認一下你的服務器上安裝的 PHP 版本,可以使用命令 php -v 查看一下。如果 PHP 版本低於 PHP 5.4 ,先把舊版的 PHP 刪除掉,重新安裝新版的 PHP。假設你用的是 CentOS 系統,之前使用的是yum 安裝的 PHP,想要移除現在安裝的 PHP,可以這樣:
yum remove php-common
然后再重新安裝一下新版本的 PHP,可以先用 yum 在你的資源庫里面搜索一下:
yum search php
如果你能看到一些 php55 ... 這樣的東西,說明你可以直接使用 yum 安裝 PHP5.5 ,如果看不到的話,你需要手工去安裝必要的資源庫,然后再重新試一下。安裝 PHP 還有必要的擴展:
yum install php55u php55u-json php55u-mcrypt php55u-pdo php55u-mysqlnd
再運行一下 php -v 查看一下 PHP 的版本。
准備 Laravel
Laravel 唯一推薦的安裝方式就是使用 Composer,所以你需要先去安裝一下 Composer。安裝完成以后,輸入命令 composer,你應該可以看到一些命令,說明可以使用 Composer。
安裝 Composer
進入到某個目錄里面,比如你的用戶的主目錄
cd ~
使用 curl 命令去下載 Composer(注:國內訪問速度很慢)
curl -sS https://getcomposer.org/installer | php
完成以后,查看一下目錄里的東西
ls
你會看到這樣一個文件
composer.phar
輸入命令
php composer.phar
你應該能看到一些命令的幫助信息,不過我們不希望每次使用 Composer 的時候,都要使用 php 命令去運行它。你可以把composer.phar 移動到你的系統的環境變量里面的某個目錄下面。這樣你就可以在任何地方使用 composer 命令了。查看系統的環境變量,可以這樣:
echo $PATH
返回的應該是一個目錄的位置的列表,把 composer.phar 放在這里列出的任意一下目錄的下面就行了。我把 composer.phar放到了 /usr/local/bin 下面。
mv composer.phar /usr/local/bin/composer
再試一次輸入 composer 命令,你應該會看到一些命令的幫助信息。現在, 我們就可以使用 Composer 去安裝 Laravel 了。
安裝 Laravel
有了 Composer 以后,我們先進入到你想把 Laravel 放到的那個目錄里面,任何目錄都可以,等會兒我們再去設置虛擬主機。我打算把它放在這個目錄下面:
/var/www/html/we.ninghao.net
先進入到這個目錄:
cd /var/www/html/we.ninghao.net
然后使用 composer 命令去安裝 Laravel
composer create-project laravel/laravel weixin --prefer-dist
這里用的是 composer 的 create-project 命令,去創建一個新的項目,創建的項目基於 Laravel 框架,項目的名字是weixin,這個名字你可以根據自己的需求隨便去命名一下。注意如果你用的是國內的服務器,使用 composer 安裝 Laravel 的過程非常慢,得多忍一會兒了。
完成以后,你會看到在目錄里面,會有一個新的項目目錄,這個目錄的名字就是你在創建 Laravel 項目的時候自己指定的,在我這里,應該就是 weixin 。
Laravel 配置
使用 Laravel 框架開發應用的時候,你的代碼一般都會放在 app 這個目錄下面。比如應用的配置文件,路由,控制器,視圖,模型等等。先去簡單配置一下 Laravel,進入到 app/config 這個目錄下面。
基本
cd weixin/app/config
編輯一下這個目錄下面的 app.php 這個文件
vim app.php
使用 vim 編輯器,去編輯這個文件,按一下小 i 進入到編輯模式,然后找到 'debug' 這個關鍵詞,把它的值修改成'true',意思就是開啟應用的調試功能,注意在正式版的應用里面,需要關掉這個調試功能。
'debug' =>true,
再瀏覽器到 'url' 這個地方,把它的值修改成你的應用程序的地址,我打算把 we.ninghao.net 指向這個應用,所以可以這樣:
'url' => 'http://we.ninghao.net',
你要根據自己的需求,修改這個 url 配置選項的值。另外這個配置文件里面,還有些其它的選項,比如時區,地域等等。
保存並退出這個文件。按下 esc,輸入 wq 並回車。
數據庫
下面,你需要給 Laravel 准備一個數據庫,Laravel 支持很多種數據庫系統,MySQL,Postgres,SQLite,SQL Server。你可以選擇使用這里的任意一種數據庫。一般,我們都是使用 MySQL,先去創建一個 MySQL 數據庫,在命令行里,可以直接創建 MySQL 數據庫,或者你可以使用圖形工作,比如 PHPMyAdmin,或者 Sequel Pro 。
有了數據庫以后,去打開 Laravel 里面的數據庫相關的配置文件:
app/config/database.php
找到 mysql 數據庫相關的配置,像下面這樣去修改一下:
'mysql' => array( 'driver' => 'mysql', 'host' => 'localhost', 'database' => '為 Laravel 准備的數據庫的名字', 'username' => '你的數據庫管理員', 'password' => '你的數據庫管理密碼', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ),
完成以后,保存並退出。
權限
下面,我們還得修改一個目錄的權限(app/storage),你需要給它寫入的權限,一般,我們可以把這個目錄的擁有者修改成你的 Web 服務器使用的用戶,如果你用的是 Apache ,那么這個用戶有可能就是 apache (CentOS)或者 www-data,具體你需要打開 Apache 的配置文件去看一下(httpd.conf)。如果你用的是 Nginx 服務器,參考這篇文章里面的修改目錄和文件權限的部分。
修改目錄的擁有者,可以像這樣:
chown -R apache app/storage
上面這行命令,會把 app 下面的 storage 這個目錄以及它所包含的子目錄的擁有者修改成 apache ,修改完成以后,可以查看一下。
ls -la
虛擬主機
到目前為止,我們基本完成了 Laravel 部分的配置。下面,我們要做的是去在服務器里添加一個虛擬主機,把一個域名綁定到 Laravel 框架里面的 public 這個目錄上,public 這個目錄里包含向用戶公開的東西,樣式表,腳本文件,要用到圖片,還包含一個 index.php 。
如何配置虛擬主機取決於你用的 Web 服務器。Nginx 服務器可以參考這篇文章里的配置虛擬主機部分。Apache 服務器可以參考這篇文章配置虛擬主機。
虛擬主機的目錄應該是 Laravel 里面的 public 這個目錄。比如我的這個目錄是在:
/var/www/html/we.ninghao.net/weixin/public
那么,上面這個地址,就應該是虛擬主機的主目錄。我為這個目錄綁定的域名是 we.ninghao.net。配置好以后,在地址里輸入你的虛擬主機的域名,我這里就是 http://we.ninghao.net ,你應該會看到 Laravel 框架的默認的首頁,上面有一個 Laravel 的標志,還有一行文字:You have arrived 。
創建與微信溝通的接口
下面,我們得去在應用里面創建一個跟微信溝通的接口,這個接口其實就是在應用里面的一個地址,這個地址可以去處理微信的請求,可以對請求做出相應的響應。Laravel 是一套基於 MVC 架構的框架,所以,處理請求用的是 MVC 里面的 C 這部分,C = Controller(控制器)。
注:我們會在 Laravel 基礎課程里面詳細去介紹 Laravel 里面的每個部分。
在 Laravel 里面,控制器也有同個類型,比如 RESTful 類型的控制器,有 Resource 類型的控制器。我打算用 Resource 類型的控制器去處理微信發過來的請求。可能創建 Resource 類型的控制器有點浪費,因為微信應該只會發送兩種請求 GET 和 POST,所以控制器里的其它的方法就有點多余了,不過我們還是去創建一個 Resource 類型的控制器,可以順序演示一樣 Laravel 的 artisan 命令行工具的用法。
創建控制器
先進入到剛才我們創建的 Laravel 項目所在的目錄,在我這里應該是:
/var/www/html/we.ninghao.net/weixin/
然后用 artisan 的 controller:make 命令,去創建一個 Resource 類型的控制器:
php artisan controller:make WeixinController
這條命令創建的控制器的名字是 WeixinController,這條命令會生成一個控制器文件,在你的 app/controllers 目錄下面:
app/controllers/WeixinController.php
路由
有了控制器以后,我們可以去添加一條路由,然后讓這個路由使用剛才創建的那個控制器去處理相應的請求。一條路由就是在應用程序里面,可能被請求的一個地址。在 Laravel 里面,所有的路由都在 app/routes.php 這個文件里面。打開這個文件,然后添加下面這些代碼:
Route::resource('api/v1', 'WeixinController');
上面這行代碼,就是為應用添加了一條路由。api/v1 ,這是路由的地址,WeixinController 就是處理請求這個地址用到的控制器。因為它是一個 Resource 類型的控制器,所以如果訪問 api/v1 這個地址的話,會用控制器里面的 index() 這個方法去處理。
過濾器
在控制器的對應的方法里面,可以去處理微信的請求。不過在控制器的方法做出響應之前, 我們要去驗證一下這個請求是不是來自微信。在 Laravel 里面,可以去給路由或者控制器去添加過濾器,過濾器的作用就是,在請求之前或者之后去做一些驗證,比如用戶是不是已經登錄了。通過了驗證,才會做出回應。在 Laravel 里面,已經包含了幾個基本的過濾器,它們都是在 app/filters.php 文件里面定義的。
下面,我們自己去定義一個過濾器。用這個過濾器過濾掉來源不是微信的請求。打開 app/filters.php 文件,添加下面這幾行代碼:
Route::filter('weixin', function() { // 獲取到微信請求里包含的幾項內容 $signature = Input::get('signature'); $timestamp = Input::get('timestamp'); $nonce = Input::get('nonce'); // ninghao 是我在微信后台手工添加的 token 的值 $token = 'ninghao'; // 加工出自己的 signature $our_signature = array($token, $timestamp, $nonce); sort($our_signature, SORT_STRING); $our_signature = implode($our_signature); $our_signature = sha1($our_signature); // 用自己的 signature 去跟請求里的 signature 對比 if ($our_signature != $signature) { return false; } });
上面這幾行代碼就是去創建了一個叫 weixin 的過濾器,這個過濾器做的事就是,先去獲取到微信請求里面包含的幾項內容,我們需要用到這幾個東西,按照微信的方法加工一個自己的 signature ,然后再用這個 signature 去跟在請求里面包含的signature 去對比,如果不匹配的話,就返回 false 。
在代碼里用到了 Input::get。它就是 Laravel 里面 Input 類的 get 方法,用它可以得到請求里面的包含的具體的內容。
下面,我們可以把這個過濾器用到 WeixinController 這個控制器上。打開這個控制器,然后添加下面這幾行代碼:
public function __construct() { $this->beforeFilter('weixin', array('on' => 'get|post')); }
它的意思就是,在這個控制器的構造函數(實例化類以后立即執行的函數)里面,添加了一個叫 weixin 的過濾器,這個過濾器會應用到所有的 get 和 post 類型的請求上。注意這個 weixin 的過濾器是作為 beforeFilter 添加進來的,也就是在請求之前就要使用這個過濾器。
現在,我們的 WeixinController 這個控制器就有了 weixin 這個過濾器的保護,任何用 GET 或 POST 方法發送過來的請求,都會先去確認一下這個請求是否是來自微信。
成為微信開發者
到目前為止, 我們已經為應用創建了一個跟微信溝通的接口(api/v1),當有請求發送到這個接口的時候,會先去驗證一下這個請求是否是來自微信。如果是的話,才會使用相應的方法去處理這個請求。
成為微信開發者,我們需要在微信公眾平台的后台,提供一個地址,還有一個 token 。token 我設置成了 ninghao。 現在我們可以把 url 設置成創建的這個接口的地址,在我這里應該就是:
http://we.ninghao.net/api/v1
訪問 api/v1 這個地址的時候,是由 WeixinController 這個控制器里面的 index() 方法去處理。所以,我們需要在這個方法里,去返回微信發送過來的 echostr ,這樣才能通過驗證,成為微信公眾平台的開發者。
public function index() { return Input::get('echostr'); }
這樣,WeixinController 這個控制器,現在看起來應該是這個樣子的:
class WeixinController extends \BaseController { public function __construct() { $this->beforeFilter('weixin', array('on' => 'get|post')); } /** * Display a listing of the resource. * * @return Response */ public function index() { return Input::get('echostr'); } // .......... }
下一步
這篇文章里我們介紹了怎么樣成為微信公眾平台的開發者,怎么樣驗證請求是不是來自微信,除此以外,還不能做什么。下一步要做的就是,去設置一些方法,去處理訂閱的用戶從微信里發送的信息,根據這些信息的內容,我們的應用需要做出不同的回應。比如把用戶的微信跟他在我們網站上的帳戶綁定到一塊兒。
名詞
- Laravel:是一套 PHP 框架,你可以用它創建 PHP 應用程序。
- MVC:是設計程序的一種方法,它會把程序按功能分成幾個部分。M 表示 Model (模型),一般用它來表示程序里面的數據。V 表示 View (視圖),展示層面的東西都放到 View 里面。C 表示 Controller (控制器),它里面包含的是處理不同請求的代碼。比如用戶請求訪問你的網站首頁,控制器接受到這個請求以后,從 Model 那里調出數據,然后發送到 View 那里,View 會包裝一下這些數據,把最終的結果顯示給用戶。
- Symfony:是一套 PHP 框架,Drupal 8 里面會使用 Symfony 框架里面的幾個組件,這篇文章里提到的 Laravel 也用到了不少 Symfony 的組件。可以肯定的是 Symfony 是一款優秀的框架。
- Ruby on Rails:是一套用 Ruby 語言寫的框架,你可以使用它快速的創建自己的應用程序。
- 應用:是指 Application ,意思就是應用程序。在這篇文章里,你也可以把 “應用” 看成是一個網站。