Nachdem ich mir die ThinkPHP-Übungen angesehen hatte, lud ich den Code im Buch von Github herunter und bereitete mich darauf vor, das für öffentliche WeChat-Konten entwickelte Programm auszuführen.
Da das Buch jedoch ThinkPHP3.2.3 verwendet und die neueste Version bereits 6.0.X ist, bin ich mit ThinkPHP ohnehin nicht vertraut, also habe ich die neueste Version heruntergeladen, um sie zu verwenden. Ich habe erwartet, dass es aufgrund der unterschiedlichen Versionen zu Problemen beim Ausführen des Programms kommen würde. Meiner Meinung nach sollten wir jedes Problem einzeln lösen. Unerwarteterweise stieß ich auf große Schwierigkeiten und es dauerte zwei Tage, bis ich das Programm zum Laufen brachte. Schließlich habe ich ein wenig Code im Framework geändert.
Lassen Sie mich ohne weitere Umschweife die Schwierigkeiten auflisten, auf die ich gestoßen bin.
So führen Sie ThinkWechat.php in TP ein
Im Buch befindet sich ThinkWechat.php unter /Application/Home/Library. Aber TP6 verfügt nicht mehr über Application, also habe ich unter /app ein neues Bibliotheksverzeichnis erstellt und die Dateien darin abgelegt.
Sie müssen diese Datei in Index.php einführen
use applibraryThinkWechat;
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',
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
namespace applibrary;
Klasse 'applibrarySimpleXMLElement' nicht gefunden
Zuerst sagte Baidu, dass php7-xml in der Umgebung installiert werden sollte. Brew habe ich schon lange nicht mehr verwendet Extrem langsam. Laut Baidus Beitrag wurde der Link zu Alibaba Cloud ersetzt. 🎜Das Ergebnis funktioniert immer noch nicht. Ich habe es mehrere Stunden lang gebraut. Ich weiß nicht, wie ich später herausgefunden habe, dass Namespace in TP6 verwendet wird. Wenn Sie also SimpleXMLElement verwenden, müssen Sie die folgende Anweisung am Anfang der Datei schreiben🎜use SimpleXMLElement;
🎜🎜🎜Wie Um Protokolle in einer Protokolldatei in TP6 zu drucken🎜🎜 🎜Da ich mit dem offiziellen WeChat-Konto interagiere, weiß ich nicht, wie ich das Debuggen erleichtern kann. Ich habe das von WeChat bereitgestellte Schnittstellen-Debugging-Tool ausprobiert, aber es konnte nur überprüfen, ob das Parametereinstellungen waren korrekt. Also habe ich die dümmste Methode zum Drucken von Protokollen verwendet. 🎜Um Protokolle zu drucken, müssen Sie die folgenden Einstellungen in TP6 vornehmen: 🎜🎜In config/log.php 🎜1. Legen Sie die Protokollierungsstufe fest 🎜'level' => ['emergency'],
🎜 🎜 Beim Debuggen habe ich hier fast alle Levelwerte geschrieben. 🎜1. Legen Sie das Protokollspeicherverzeichnis fest 🎜'path' => App()->getRuntimePath() .'/log',
🎜2 die Protokolldatei des Programms🎜Log::write('index _get session id before set ID '. Session::getId(), 'notice');
🎜🎜🎜Nachdem Sie dem offiziellen Testkonto gefolgt sind, geben Sie ein 999, Sie können eine normale Antwort erhalten. Geben Sie 1 ein und das Programm wird beendet🎜🎜🎜Dieses Problem beschäftigt mich fast den ganzen Tag! ! 🎜🎜Zuerst dachte ich, es gäbe ein Problem mit der an die WeChat-Plattform zurückgegebenen Antwort, weil ich viele Protokolle in ThinkWechat.php gedruckt habe und festgestellt habe, dass die data2xml-Methode dies nicht konnte, solange ich andere Informationen als 999 eingegeben habe vollständig ausgeführt werden und die Protokolle in 🎜 $node = dom_import_simplexml($child);
waren, können danach nicht mehr gedruckt werden. 🎜🎜Ich dachte immer, es wäre $node->appendChild($node->ownerDocument->createCDATASection($value));
🎜Bei der Ausführung dieses Codes liegt ein Problem vor. 🎜So habe ich auch aus dem Buch „WeChat Public Platform Development“ herausgefunden, dass durch Festlegen der XML-Vorlage die Sprintf-Methode zum Ersetzen der Variablen in der Vorlage verwendet wird, um die Antwort-XML zu generieren. 🎜🎜Das Ergebnis ist, dass ich im Protokoll sehen kann, dass die Antwort-XML erfolgreich generiert wurde, die Eingabe von 1 jedoch immer noch nicht die erwartete Antwort ergab. Es sollte keine Antwort erfolgen und es wurde angezeigt: „Dieses offizielle Konto ist vorübergehend nicht verfügbar.“ Um Dienste bereitzustellen, warten Sie bitte. „Versuchen Sie es erneut“ und das Programm wurde sofort beendet. 🎜🎜Später stellte ich fest, dass es keine Probleme geben würde und das Programm nicht beendet werden würde, wenn ich beiläufig ein Programm schreibe, z. B. ein öffentliches Konto, das jedes Mal auf die vom Benutzer eingegebenen Informationen reagiert, z. B. einen Antwort-Bucket. Ich fragte mich plötzlich, ob es vielleicht mit der Sitzung zusammenhängt? Weil die Sitzung im Quellcode verwendet wird, um die Benutzerregistrierung und -anmeldung zu implementieren. 🎜Ich habe mir die Entwicklungsdokumentation von TP6 angesehen und dort steht tatsächlich, dass die Sitzung nicht standardmäßig initialisiert wird. Mir ist hier zum Weinen zumute. 🎜🎜Den Dokumentationsanweisungen folgend habe ich die Sitzung geöffnet: 🎜🎜1. Entfernen Sie den Kommentar von thinkmiddlewareSessionInit::class
in app/middleware.php. 🎜🎜2. Und entfernen Sie session_start() im Code. Da TP6 nur Betriebssitzungen über Sitzungsklassenmethoden und Sitzungshilfsfunktionen unterstützt, werden nicht alle session_xx-Funktionen unterstützt. 🎜🎜Nachdem die Sitzung geöffnet wurde, wird das Programm nicht mehr beendet. Nach der Eingabe von 999 ist jedoch ein neues Problem aufgetreten. Das offizielle Konto hat korrekt geantwortet, aber die Antwort nach der Eingabe des Benutzernamens war dieselbe wie bei der Eingabe von 999. Wenn Sie dazu aufgefordert werden, geben Sie 1 ein, um sich zu registrieren, und 2, um sich anzumelden. Die richtige Lösung sollte die Aufforderung zur Eingabe eines Benutzernamens sein. 🎜Zu diesem Zeitpunkt stellte ich fest, dass im Laufzeit-/Sitzungsverzeichnis mehrere Sitzungsdateien generiert wurden. Für denselben Benutzer sollte es nur eine korrekte Sitzungsdatei geben. Dies entspricht der Generierung einer neuen Sitzungsdatei jedes Mal, wenn der Benutzer mit dem offiziellen Konto interagiert, sodass die zuvor vom Benutzer eingegebenen Informationen nicht abgerufen werden können.
Baidu entdeckte später, dass der Grund dafür darin liegt, dass
Sitzungen auf der Serverseite gespeichert werden. Daher müssen Client-Cookies verwendet werden, um die Sitzungen jedes Benutzers zu unterscheiden. Der WeChat-Server sendet keine Cookies an den Entwicklerserver, also an Sitzungen auf Cookies basierende Cookies können nicht genutzt werden.
Aber solange für jeden Benutzer eine eindeutige Sitzungs-ID festgelegt ist, kann der gleiche Effekt erzielt werden.
Jede WeChat-ID ist einzigartig, daher können wir die WeChat-ID als Sitzungs-ID des Benutzers oder nach MD5-Verschlüsselung verwenden.
Ich habe vor, den Wert von FromUserName als Sitzungs-ID zu verwenden. Das heißt, die eigene OpenID jedes Benutzers. TP6 unterstützt jedoch nicht die Methode session_id() zum Festlegen der Sitzungs-ID. Später habe ich die Dokumentation gelesen und festgestellt, dass Session::setId zum Festlegen der SessionID verwendet werden kann, aber ich weiß nicht, warum immer noch jedes Mal eine andere SessionID generiert wird.
Im Internet steht, dass Sie openid verwenden können. Ich habe festgestellt, dass jedes Mal, wenn die vom öffentlichen WeChat-Konto an den Server gesendete URL openid enthält, openid in session.php konfiguriert wurde, in der Hoffnung, dass TP6 die openid verwendet die Anfrage jedes Mal als Sitzungs-ID. Aber es zeigte immer noch keine Wirkung.
TP6s session.php hat die folgende Konfiguration:
SESSION_IDs Übermittlungsvariable löst das Problem des domänenübergreifenden Flash-Uploads'var_session_id' => 'openid',
'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();
rrreee
Es stellt sich heraus, dass die Sitzungs-ID eine 32-Bit-Zeichenfolge mit alphanumerischen Zeichen sein muss. Wenn sie die Anforderungen nicht erfüllt (OpenID-Länge beträgt 28 Bit), wird die aktuelle Zeit als verwendet die Sitzungs-ID, also habe ich die Set-ID wie folgt geändert, und dann wird die Sitzungs-ID in der Indexmethode gedruckt und es wird festgestellt, dass sie jedes Mal gleich ist.