基於 laravel 開發微信公衆號 composer 擴展包

在這裏插入圖片描述

1. 開通微信公衆號:訂閱號 php

到微信公衆號開通我的訂閱號,並查看相關開發文檔,並瞭解消息管理中的被動回覆用戶信息。html

2. 實現對接微信公衆號功能laravel

對接代碼git

signature = $_GET["signature"];timestamp = GET["timestamp"];_GET["timestamp"];G​ET["timestamp"];nonce     = GET["nonce"];_GET["nonce"];G​ET["nonce"];echostr   = $_GET["echostr"];
token=′leeprinceSubscription′;token = 'leeprinceSubscription';token=′leeprinceSubscription′;tmpArr = array(token, $timestamp, $nonce); sort(tmpArr, SORT_STRING);
tmpStr=implode(tmpStr = implode(tmpStr=implode(tmpArr);
tmpStr=sha1(tmpStr = sha1(tmpStr=sha1(tmpStr);
if (tmpStr == $signature) {  // 微信服務器在驗證業務服務器地址的有效性時,包含 echostr 參數,以後微信服務器與業務服務器的交互再也不包含此參數。  if (empty(echostr)) {
/**
     * 開始處理業務
     */
    return true;
} else {
    // 若確認這次GET請求來自微信服務器,請原樣返回echostr參數內容. 此處只能使用 echo,使用 return 失敗。
    echo $echostr;
}
} else {
return false;
}

在 「微信公衆號->開發->基本配置->服務器配置」 中配置信息,其中服務器地址(URL)要能被外網訪問,第一次配置會傳入 echostr 參數進行服務器地址的有效校驗,以後微信服務器與業務服務器的交互再也不包含此參數。能夠正確提交即檢驗成功,以後啓動該服務配置。後面能夠在「管理->消息管理」中查看用戶給公衆號發的消息。web

補充:基於內網開發的可使用 ngrok 進行內網穿透。ngrok 會分配 http 和 https
的臨時連接供你使用的。(mac使用:/Applications/ngrok http 80)其中 「Web Interface」的本地連接
http://127.0.0.1:4040 是 web 頁面用於查看 ngrok 轉發的信息
ngrok by @inconshreveable                                       (Ctrl+C to quit)

Session Status                online
Session Expires               7 hours, 59 minutes
Version                       2.3.35
Region                        United States (us)
Web Interface                 http://127.0.0.1:4040
Forwarding                    http://6a33d7ab.ngrok.io -> http://localhost:80
Forwarding                    https://6a33d7ab.ngrok.io -> http://localhost:80

Connections                   ttl     opn     rt1     rt5     p50     p90
                              0       0       0.00    0.00    0.00    0.00

3. 構建微信公衆號對接功能到 composer 擴展包中編程

在項目(個人本地項目路徑是:xxx/www/composer/laravel-wechat 此處爲了更好在下文說明)中執行 composer init。本地沒有 composer 的自行去官網下載吧。json

`> composer init
Package name (<vendor>/<name>) [leeprince/laravel-wechat]:
Description []: This is laravel WeChat composer
Author [leeprince <leeprince@foxmail.com>, n to skip]:
Minimum Stability []:
Package Type (e.g. library, project, metapackage, composer-plugin) []: library
License []: MITsass

Define your dependencies.服務器

Would you like to define your dependencies (require) interactively [yes]?
Search for a package:
Would you like to define your dev dependencies (require-dev) interactively [yes]?
Search for a package: 微信

{

"name": "leeprince/laravel-wechat",
"description": "This is laravel WeChat composer",
"type": "library",
"license": "MIT",
"authors": \[
    {
        "name": "leeprince",
        "email": "leeprince@foxmail.com"
    }
\],
"require": {}

}

Do you confirm generation [yes]?
Would you like the vendor directory added to your .gitignore [yes]? `

在 composer.json 文件中添加自動加載配置

`"autoload": {

"psr-4": {
    "LeePrince\\\\WeChat\\\\": "./src/"
}

}`

執行 composer update 更新獲取依賴的最新版本

4. laravel 項目集成本地基於微信公衆號開發 composer 組件包

在已經下載好的 laravel 項目(個人本地路徑是:xxx/www/laravel69)中配置 composer laravel-wechat 擴展的本地倉庫的相對路徑或者絕對路徑

composer config repositories.leeprince path ../composer/laravel\-wechat

增長新的依賴包到當前項目的 ./vendor/ 中

composer require leeprince/laravel\-wechat:dev\-master

5. 編寫服務提供者,並註冊到 laravel 的服務提供者中

這是將該 composer leeprince/laravel-wechat 擴展包集成到 laravel 的第一步

在 laravel-wechat 項目的 ./src 路徑下 編寫服務提供者 WeChatServiceProvider 並繼承 laravel 的服務提供者。注意命名空間爲:namespace LeePrince\WeChat; 該服務提供者用於加載自定義組件中的全部服務

`<?php
/**
* [服務提供者爲 laravel 提供該組件的全部服務]
*
* @Author leeprince:2020-03-22 19:05
*/

namespace LeePrince\WeChat;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;

class WeChatServiceProvider extends ServiceProvider
{

...

}`

在 laravel 項目的 ./config/app.php 中註冊該 composer 擴展包的服務提供者

/**
 * 引入 composer 組件中的服務提供者
 */
// 自定義服務提供者 - 基於微信公衆號開發的 composer 組件
LeePrince\WeChat\WeChatServiceProvider::class,

6. 【核心服務:路由】

在 ./src/Route/route.php 中編寫路由

Router::any('hello', function() {
   dump('hello world');
});

在服務提供者 WeChatServiceProvider boot() 方法中加載路由

/**
 * [引導服務:該方法在全部服務提供者被註冊之後纔會被調用]
 *
 * @Author  leeprince:2020-03-22 19:55
 */
public function boot()
{
    $this->loadRoutes();
}

/**
 * [加載路由]
 *
 * @Author  leeprince:2020-03-23 00:28
 */
private function loadRoutes()
{
    Route::group(['namespace' => 'LeePrince\WeChat\Http\Controllers', 'prefix' => 'wechat'], function() {
        $this->loadRoutesFrom(__DIR__.'/Route/route.php');
    });
}

7. 【核心服務:控制器】

在./src/Http/Controllers/WxSubscriptionController.php.php 中編寫控制器。因爲上一步已經加載了路由,因此編寫的控制器能夠當即生效。

<?php

namespace LeePrince\WeChat\Http\Controllers;

use Illuminate\Http\Request;

/**
 * [微信公衆號 - 訂閱號接受微信服務驗證、接受微信從訂閱號發送過來的信息並自動回覆]
 *
 * @Author  leeprince:2020-03-22 20:06
 * @package LeePrince\WeChat\Http\Controllers
 */
class WxSubscriptionController extends Controller
{
    /**
     * [自動回覆微信公衆號信息]
     *
     * @Author  leeprince:2020-03-24 01:10
     * @param Request $request
     * @return \Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        /**
         * 開始處理業務
         */
        $signature = $request->input("signature");
        $timestamp = $request->input("timestamp");
        $nonce     = $request->input("nonce");
        $echostr   = $request->input("echostr");

        $token  = 'leeprinceSubscription';
        $tmpArr = array($token, $timestamp, $nonce);
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        if ($tmpStr == $signature) {
            // 微信服務器在驗證業務服務器地址的有效性時,包含 echostr 參數,以後微信服務器與業務服務器的交互再也不包含此參數。
            if (empty($echostr)) {
                /**
                 * 開始處理業務
                 */

                // 回覆信息
                // 接收微信發送的參數
                $postObj =file_get_contents('php://input');
                $postArr = simplexml_load_string($postObj,"SimpleXMLElement",LIBXML_NOCDATA);
                if (empty($postArr)) {
                    return response('XML消息爲空!');
                }
                //消息內容
                $content = $postArr->Content;
                //接受者
                $toUserName = $postArr->ToUserName;
                //發送者
                $fromUserName = $postArr->FromUserName;
                //獲取時間戳
                $time = time();

                //回覆消息內容; 補充:想更加只能能夠經過接入機器人自動回覆。好比圖靈機器人:http://www.tuling123.com
                $content = "[PrinceProgramming] - 編程是一門藝術\n歡迎您,您的消息是: $content\n";
                //回覆文本消息的格式:把百分號(%)符號替換成一個做爲參數進行傳遞的變量
                $info = sprintf("<xml>
                  <ToUserName><![CDATA[%s]]></ToUserName>
                  <FromUserName><![CDATA[%s]]></FromUserName>
                  <CreateTime>%s</CreateTime>
                  <MsgType><![CDATA[text]]></MsgType>
                  <Content><![CDATA[%s]]></Content>
                </xml>", $fromUserName, $toUserName, $time, $content);

                return response($info);
            } else {
                // 若確認這次GET請求來自微信服務器,請原樣返回echostr參數內容. 此處只能使用 echo,使用 return 失敗。
                echo $echostr;
            }
        } else {
            return response('false');
        }

    }
}

8.【擴展服務:中間件】

測試經過後繼續完善代碼提取檢測簽名部分到中間件中做爲請求過濾,這裏是用的是路由中間件。須要在 WeChatServiceProvider 服務提供者中加載路由中間件到路由中。

<?php
/**
 * [服務提供者爲 laravel 提供該組件的全部服務]
 *
 * @Author  leeprince:2020-03-22 19:05
 */

namespace LeePrince\WeChat;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Route;

class WeChatServiceProvider extends ServiceProvider
{
    // 中間件組
    private $middlewareGroups = [];

    // 路由中間件
    private $routeMiddleware = [
        'wechat.subscription.CheckSignture' => \LeePrince\WeChat\Http\Middleware\CheckSignture::class,
    ];

    /**
     * [註冊服務:register 方法中,你只須要將服務綁定到服務容器中。而不要嘗試在 register 方法中註冊任何監聽器,路由,或者其餘任何功能。不然,你可能會意外地使用到還沒有加載的服務提供者提供的服務。]
     *
     * @Author  leeprince:2020-03-22 19:56
     */
    public function register()
    {

    }

    /**
     * [引導服務:該方法在全部服務提供者被註冊之後纔會被調用]
     *
     * @Author  leeprince:2020-03-22 19:55
     */
    public function boot()
    {
        $this->syncMiddlewareToRouter();
    }

    /**
     * 將中間件的當前狀態同步到路由器
     *
     * @return void
     */
    private function syncMiddlewareToRouter()
    {
        foreach ($this->middlewareGroups as $key => $middleware) {
            Route::middlewareGroup($key, $middleware);
            // $this->router->middlewareGroup($key, $middleware);
        }

        foreach ($this->routeMiddleware as $key => $middleware) {
            Route::aliasMiddleware($key, $middleware);
        }
    }
}

9.【擴展服務:視圖】

在 ./src/Resources/views/view.blade.php 中編寫視圖文件。

在 ./src/Resources/ 下的目錄結構爲

Resources
    js
    lang
    sass
    views

view.blade.php 文件
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
    </head>
    <body>
        <div class="content">
            LeePrince
            <br>
            [PrinceProgramming] - 編程是一種藝術
            <hr>
        </div>
    </body>
</html>

在 WeChatServiceProvider 服務提供者中加載視圖文件並設置命名空間

在 ./src/Resources/ 下的目錄結構爲

Resources
    js
    lang
    sass
    views

view.blade.php 文件
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>
    </head>
    <body>
        <div class="content">
            LeePrince
            <br>
            [PrinceProgramming] - 編程是一種藝術
            <hr>
        </div>
    </body>
</html>

attachments-2020-08-YnIk2Mpf5f40793996a1c.jpg

相關文章
相關標籤/搜索