詳解TP中怎麼引入ThinkWechat.php並列印日誌

藏色散人
發布: 2021-08-17 09:03:52
轉載
2045 人瀏覽過

下面由thinkphp框架教學欄位來介紹給大家關於TP中怎麼引入ThinkWechat.php以及怎麼列印日誌到日誌文件,希望對需要的朋友有幫助!

基於Thinkphp6的微信公眾號互動訊息開發

#看完thinkPHP實戰,我從github下載了書中的程式碼,準備運行一下微信公眾號開發的程式。
可是,因為書中使用的是ThinkPHP3.2.3,而最新版本已經是6.0.X,反正我對ThinkPHP不熟悉,就下載了最新版來使用。我預料到因為版本不同,程式運行會有問題。我想的是,遇到一個解決一個吧。沒想到,我遇到了很多困難,兩天了才把程式跑起來。最後也更改了框架的一點點程式碼。

閒話少說,我依序羅列下遇到的困難吧。

如何在TP中引入ThinkWechat.php

書中是把ThinkWechat.php放在/Application/Home/Library下的。但TP6已經沒有Application,我就在/app下新建了library目錄,將檔案放入其中。

在Index.php中需要引入該檔案

use app\library\ThinkWechat;

在ThinkWechat.php檔案中加入namespace

namespace app\library;

Class 'app\library\SimpleXMLElement' not found

一開始,百度說是要在環境上安裝php7- xml. 我的macmini需要用brew來安裝,很久沒用brew,brew update慢死了,按照百度的帖子,替換了阿里雲的鏈接。
結果還是不行。弄brew弄了幾個小時。後來不知道怎麼發現,原來tp6裡面用了namespace,所以在使用SimpleXMLElement的時候,要在檔案開頭寫如下語句
use SimpleXMLElement;

#TP6怎麼列印日誌到日誌文件

因為是和微信公眾號進行交互,我不知道有什麼辦法方便調試,試過了微信提供的接口調試工具,但是也僅僅能夠檢查參數設置是否正確。於是我用了最笨的列印日誌的方法。
要列印日誌需要在TP6中做以下設定:

在config/log.php 中

1.設定日誌記錄等級

'level' => [' emergency'],

我調試時幾乎把所有的level值都寫到這裡了。

1.設定日誌保存目錄

'path' => App()->getRuntimePath() .'/log',

#2.然後在程式中使用下面的語句即時寫入日誌檔案

Log::write('index _get session id before set ID '. Session::getId(), 'notice');

#追蹤測試公眾號後,輸入999,可以收到正常回覆。輸入1 程式則退出

這個問題卡了我大半天! !

一開始,我以為是返回給微信平台的response 有問題,因為我在ThinkWechat.php中打印了很多日誌,發現只要我輸入除999以外的信息,data2xml方法總是不能完全執行,日誌在
$node = dom_import_simplexml($child);之後就無法列印。

我一直以為是$node->appendChild($node->ownerDocument->createCDATASection($value));
這句程式碼執行有問題。
因此也從《微信公眾平台開發》一書中找到透過設定xml模板中,用sprintf方法取代模板中的變數來產生response的xml。

這樣做的結果是,我能在日誌中看到response xml 成功生成,但是輸入1仍然沒有得到我期望的回复,應該是沒有任何回复,顯示“該公眾號暫時無法提供服務,請稍後再試”,並且才程序也是立即退出了。

後來我發現,自己隨便寫的程序,比如公眾號每次都回復用戶輸入的信息,像應聲桶那樣,就沒有問題,程序也不退出。我突然想著會不會是跟session有關?因為原始碼中用到了session來實現使用者的註冊和登入。
我看了下TP6的開發文檔,果然,裡面寫到session預設是沒初始化的。這裡我有點欲哭無淚。

依照文件說明,我開啟了session:

1.在app/middleware.php 中去掉\think\middleware\SessionInit::class的註解。

2.並且把程式碼中的session_start()去掉。因為TP6只支援透過Session類別方法和session助手函數來操作session. 不支援一切的session_xx 函數。

Session 開啟之後,程式不再退出。但出現新的問題,輸入999後再輸入1,公眾號正確回覆請輸入用戶名,但輸入用戶名後的回覆卻和輸入999一樣。提示輸入1註冊,輸入2登入。而正確的應該是提示輸入使用者名稱。

這時,我發現runtime/session目錄中產生了多個session檔。對於同一個使用者來說,應該只有一個session檔案才是正確的。相當於使用者每一次和公眾號交互,都有一個新的session檔案產生,這樣就沒辦法取得使用者先前輸入的資訊。

百度後發現這個原因是

session是儲存在伺服器端的,那麼區別每個使用者的session就需要使用客戶端的cookie,微信伺服器是不發送cookie到開發者伺服器,所以基於cookie的session無法使用。
但是只要為每個使用者設定一個唯一的session_id,也可以達到相同的效果。
每個人微訊號是唯一的,所以我們可以使用微訊號作為使用者的session_id,也可以將其md5加密後使用。

我打算用FromUserName的值作為sessionid。也就是每個使用者自己的openid。不過TP6 不支援session_id()方法來設定sessionid。我後來看文件發現可以用Session::setId來設定SessionID,但是不知道為什麼每次還是會產生不同的sessionID。

網路上說可以就用openid,我發現每次微信公眾號向伺服器發來的url確實都會附帶openid,我就在session.php配置了openid,希望TP6每次用請求中的openid作為sessionid。不過仍然沒有生效。

TP6的session.php有如下配置:

SESSION_ID的提交變數,解決flash上傳跨域
'var_session_id' => 'openid',

查看了下框架的setId,原始碼如下

public function setId($id = null): void { $this->id = is_string($id) && strlen($id) === 32 && ctype_alnum($id) ? $id : md5(microtime (true).session_create_id()); }
登入後複製

原來sessionid必須為32位包含字母數字的字串,如果不滿足要求(openid長度為28位),就用目前時間作為sessionid,所以我把setId改為下面的樣子,然後在index方法中印出sessionid,發現每次都是一樣的。

public function setId($id = null): void { $this->id = is_string($id) && strlen(md5($id)) === 32 && ctype_alnum(md5($id)) ? md5($id) : md5(microtime (true).session_create_id()); }
登入後複製

運行了程序,一切正常,感覺太美好了。

這時,我想之前遇到的這麼多問題,應該跟xml response沒有關係。於是我又用回以前的ThinkWechat.php,卻發現runtime/session目錄中沒有產生session檔。

檢查後才發現,原始的ThinkWechat.php的response方法最後是

exit($xml->asXML());

#而TP6官方文件有以下提醒:

注意,Session寫入資料的操作會在請求結束的時候統一進行本地化存儲,所以不要在寫入Session資料之後使用exit等中斷操作,可能會導致Session沒有正常寫入。

因此我把exit語句改為return $xml->asXML();這時session檔案正常生成,公眾號回覆的訊息也正確了。

PS 程式碼已託管在github上

https://github.com/sarawang9012/thinkwechat

相關推薦:最新的10個thinkphp影片教學

以上是詳解TP中怎麼引入ThinkWechat.php並列印日誌的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:segmentfault.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!