下面由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 applibraryThinkWechat;
在ThinkWechat.php文件中添加namespace
namespace applibrary;
Class 'applibrarySimpleXMLElement' 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 中去掉thinkmiddlewareSessionInit::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
站長資訊網