Refactoring of the introduction of WeChat message encryption and decryption in Yii 2.0
1. For the implementation of a previous colleague, download the WeChat sample code, add it to the /vender/wx_biz_msg_crypt directory of the current application, and then require in the init() method. as shown in Figure 1
<?php
namespace frontend\controllers;
use Yii;
use frontend\models\http\wx_auth\AccessToken as HttpWxAuthAccessToken;
use WXBizMsgCrypt;
use yii\filters\AccessControl;
use yii\helpers\Json;
use yii\rest\Controller;
use yii\web\NotFoundHttpException;
use yii\web\ServerErrorHttpException;
class WxMsgEventController extends Controller
{
public $redis;
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
];
}
public function init()
{
parent::init();
require __DIR__ . '/../vendor/wx_biz_msg_crypt/wxBizMsgCrypt.php';
$this->redis = Yii::$app->redis;
}
}
2. Search in Githab: WeChat encryption and decryption, and no official WeChat git package is found, and it is confirmed that it cannot be installed based on Composer.
3. Reference Introduce third-party code (Working with third-party code), use the downloaded class library (Using Downloaded Libraries):https://www.yiiframework.com/doc/guide/2.0/zh-cn/tutorial-yii-integration#using-downloaded-libs。
4. Reference:https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md. Example: \Aura\Web\Response\Status. Decided to adjust the class library naming method to meet the PSR-4 standard, and then use Yii’s official autoloader to load these classes automatically. Rename the file name to the same as the class name, and the case is the same.
5. Edit the file: /frontend/vendor/src/wx-biz-msg-crypt/wxbi zmsgcrypt.php, declare namespace: wx\biz\msg\crypt, include_once Delete them all, and other files are also processed in the same way.
<?php
namespace wx\biz\msg\crypt;
/**
* 对公众平台发送给公众账号的消息加解密示例代码.
*
* @copyright Copyright (c) 1998-2014 Tencent Inc.
*/
/**
* 1.第三方回复加密消息给公众平台;
* 2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
*/
class WXBizMsgCrypt
{
}
6. It is important to pay attention to the file: there are 2 classes in pkcs7encoder.php, which need to be split into files: pkcs7encoder.php, prcrypt.php. The file base directory is lowercase letters, which are connected with a middle horizontal bar. as shown in Figure 2
7. Declare the root path alias to the root namespace and edit the application configuration file: /frontend/config/main.php. The namespace is prefixed with lowercase letters and is connected with a forward slash.
return [
'aliases' => [
'@wx/biz/msg/crypt' => '@frontend/vendor/wx-biz-msg-crypt/src',
],
]
8. The implementation file of a previous colleague, edit again, the reference adjustment, use wx\biz\msg\crypt\wxbizmsgcrypt;, and then remove the require in the init() method.
<?php
namespace frontend\controllers;
use Yii;
use frontend\models\http\wx_auth\AccessToken as HttpWxAuthAccessToken;
use wx\biz\msg\crypt\WXBizMsgCrypt;
use yii\filters\AccessControl;
use yii\helpers\Json;
use yii\rest\Controller;
use yii\web\NotFoundHttpException;
use yii\web\ServerErrorHttpException;
class WxMsgEventController extends Controller
{
public $redis;
/**
* {@inheritdoc}
*/
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout', 'signup'],
'rules' => [
[
'actions' => ['signup'],
'allow' => true,
'roles' => ['?'],
],
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['@'],
],
],
],
];
}
public function init()
{
parent::init();
$this->redis = Yii::$app->redis;
}
/**
* 获取验证票据(接收微信服务器推送)
*/
public function actionTicket()
{
//try {
$request = Yii::$app->request;
$requestRawBody = $request->getRawBody();
$requestQueryParams = $request->getQueryParams();
file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketQueryParams.txt', print_r($requestQueryParams, true), LOCK_EX);
file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketRawBody.txt', print_r($requestRawBody, true), LOCK_EX);
$appId = Yii::$app->params['wxOpen']['component']['appId'];
$appSecret = Yii::$app->params['wxOpen']['component']['appSecret'];
$token = Yii::$app->params['wxOpen']['component']['token'];
$encodingAesKey = Yii::$app->params['wxOpen']['component']['symmetricKey'];
$msg = '';
$pc = new WXBizMsgCrypt($token, $encodingAesKey, $appId);
// 解密 xml 数据
$errCode = $pc->decryptMsg($requestQueryParams['msg_signature'], $requestQueryParams['timestamp'], $requestQueryParams['nonce'], $requestRawBody, $msg);
file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketDecrypt.txt', print_r($errCode, true), LOCK_EX);
// 解密成功
if ($errCode == 0) {
$ticketData = $this->xmlToArray($msg);
if (isset($ticketData['ComponentVerifyTicket'])) {
$redisCommandkeyPrefix = Yii::$app->params['redisCommand']['keyPrefix'];
$componentVerifyTicketKey = $redisCommandkeyPrefix . $ticketData['AppId'] . ':component_verify_ticket';
$this->redis->set($componentVerifyTicketKey, $ticketData['ComponentVerifyTicket']);
// 获取第三方平台component_access_token
$this->getComponentAccessToken($appId, $appSecret);
}
}
file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketMsgXml.txt', print_r($msg, true), LOCK_EX);
/*
} catch (\Throwable $th) {
file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketError.txt', print_r($th->getMessage(), true), LOCK_EX);
}
*/
exit('success');
}
9. Adjust the encoding of all files to: UTF-8, run the program again, and view the decrypted data file: ComponentVerifyTicketMsgXML.txt. in line with expectations. as shown in Figure 3
<xml><AppId><![CDATA[wxd98c58b273d21bdf]]></AppId>
<CreateTime>1625124291</CreateTime>
<InfoType><![CDATA[component_verify_ticket]]></InfoType>
<ComponentVerifyTicket><![CDATA[ticket@@@PaPM2hcjK8DPPkW_ZzbaR4DCQtirExq932-BBnxhQg19QWJtIKm3Io0TXsWMqcdv-18WnjkWSiSLNPSoXmqGSA]]></ComponentVerifyTicket>
</xml>


