您现在的位置是: 网站首页> PHP> Laravel Laravel
Laravel 搭建微信公众号遇到的问题及解决方案
Smile 2020-10-15 14:19:49 PHP Laravel 阅读:2354
简介最近在使用Laravel框架搭建个微信公众号时遇到各种问题,踩了很多坑,调试了很久以及网上查询收集资料才解决遇到的这些问题,下面记录了搭建时遇到的问题以及相应的解决办法
1、先去微信官方获取一个测试微信号,测试微信号已经开通了接口,直接用即可 传送门
2、首先去网上自行下载微信公众号 wx_sample.php 示例文件,在下载官方示例代码中是没有这个文件的,内容如下
<?php
/**
* wechat php test
*/
//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
$wechatObj->valid();
class wechatCallbackapiTest
{
public function valid()
{
$echoStr = $_GET["echostr"];
//valid signature , option
if($this->checkSignature()){
echo $echoStr;
exit;
}
}
public function responseMsg()
{
//get post data, May be due to the different environments
$postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
//extract post data
if (!empty($postStr)){
/* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
the best way is to check the validity of xml by yourself */
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
if(!empty( $keyword ))
{
$msgType = "text";
$contentStr = "Welcome to wechat world!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}else{
echo "Input something...";
}
}else {
echo "";
exit;
}
}
private function checkSignature()
{
// you must define TOKEN by yourself
if (!defined("TOKEN")) {
throw new Exception('TOKEN is not defined!');
}
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
// use SORT_STRING rule
sort($tmpArr, SORT_STRING);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}
?>
3、把这个示例文件封装到 Laravel 的控制器中,结果如下
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Http\Controllers\Controller;
class WxchatController extends Controller
{
const TOKEN = 'weixin';//微信验证token
public function index()
{
if(isset($_GET['echostr'])){
$this->valid(); //使用valid方法
}else{
$this->responseMsg();//回复用户消息
}
}
//验证消息
public function valid()
{
$echoStr = $_GET["echostr"];
if($this->checkSignature()){
echo $echoStr;
exit;
}else{
echo "error";
exit;
}
}
//处理消息
public function responseMsg()
{
//get post data, May be due to the different environments
$postStr = file_get_contents("php://input");
// $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
//extract post data
if (!empty($postStr)){
/* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
the best way is to check the validity of xml by yourself */
libxml_disable_entity_loader(true);
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
$fromUsername = $postObj->FromUserName;
$toUsername = $postObj->ToUserName;
$keyword = trim($postObj->Content);
$time = time();
$textTpl = "<xml>
<ToUserName><![CDATA[%s]]></ToUserName>
<FromUserName><![CDATA[%s]]></FromUserName>
<CreateTime>%s</CreateTime>
<MsgType><![CDATA[%s]]></MsgType>
<Content><![CDATA[%s]]></Content>
<FuncFlag>0</FuncFlag>
</xml>";
if(!empty( $keyword ))
{
$msgType = "text";
$contentStr = "Welcome to wechat world!";
$resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
echo $resultStr;
}else{
echo "Input something...";
}
}else {
echo "";
exit;
}
}
//验证签名
private function checkSignature()
{
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = self::TOKEN;
$tmpArr = array($token, $timestamp, $nonce);
sort($tmpArr);
$tmpStr = implode( $tmpArr );
$tmpStr = sha1( $tmpStr );
if( $tmpStr == $signature ){
return true;
}else{
return false;
}
}
}
注:PHP7抛弃了HTTP_RAW_POST_DATA,所以这会导致微信公众号API接口提示“该公众号无法提供服务,请稍后重试”,这是一个采坑点,要获取post数据可以用php://input代替,注释$postStr = $GLOBALS["HTTP_RAW_POST_DATA"]; 改成 $postStr = file_get_contents("php://input");
4、接下来注册 Laravel 路由,如下
Route::any('/wechat', 'WxchatController@index')->name('wechat');
注:这里一定要用 Route::any, 因为微信服务端认证的时候是 GET, 微信服务端通过你的服务器向用户发消息时是 POST,之前我用Route::get,导致微信服务端认证成功,接收回复用户消息却提示“该公众号无法提供服务,请稍后重试”
5、在App\Http\Middleware\VerifyCsrfToken里,将该请求路径去除CSRF TOKEN的保护,如下
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
'wechat',
];
}
注:因为微信服务端通过你的服务器向用户发消息时是POST方式,因Laravel自身提供的请求保卫机制,必须符合csrf token的验证,对方发来的post请求才会被接受,所以这里我们需要将微信验证接入的路由路径如上排除在外
6、在微信公众号后台配置接口如下,验证token接入,如下
注:token令牌应该与WxchatController.php中配置的令牌一致。点击提交,如果提示“提交成功”,那么就接入成功了。如果提示“配置失败”就仔细检查一下配置信息是否正确,代码是否有问题
很赞哦! (0)