在 Yii 2.0 中微信消息加解密的引入的重构(调整类库命名方式符合 PSR-4 标准,再使用 Yii 官方的自动加载器来自动加载这些类)
1、之前的某位同事的实现,下载微信示例代码,添加至当前应用的 /vender/wx_biz_msg_crypt 目录下,再在 init() 方法中 require。如图1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <?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、在 GitHab 中搜索:微信加解密,并未发现微信官方的 Git 包,确认无法基于 Composer 安装。
3、参考 引入第三方代码(Working with Third-Party Code),使用下载的类库(Using Downloaded Libraries):https://www.yiiframework.com/doc/guide/2.0/zh-cn/tutorial-yii-integration#using-downloaded-libs。
4、参考:https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md 。例子:\Aura\Web\Response\Status。决定调整类库命名方式符合 PSR-4 标准,再使用 Yii 官方的自动加载器来自动加载这些类。将 文件名 分别重命名为与 类名 相同,且大小写保持一致。
5、编辑文件:/frontend/vendor/src/wx-biz-msg-crypt/WXBizMsgCrypt.php,声明命名空间:wx\biz\msg\crypt,include_once 全部删除,其他文件也如法炮制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <?php namespace wx\biz\msg\crypt; /** * 对公众平台发送给公众账号的消息加解密示例代码. * * @copyright Copyright (c) 1998-2014 Tencent Inc. */ /** * 1.第三方回复加密消息给公众平台; * 2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。 */ class WXBizMsgCrypt { } |
6、需要着重注意的是文件:PKCS7Encoder.php 中存在 2 个类,需要拆分为文件:PKCS7Encoder.php、Prpcrypt.php。文件基目录为小写字母,以中横杠连接。如图2
7、给根命名空间声明一下根路径别名,编辑应用配置文件:/frontend/config/main.php。命名空间前缀为小写字母,以正斜杠连接。
1 2 3 4 5 | return [ 'aliases' => [ '@wx/biz/msg/crypt' => '@frontend/vendor/wx-biz-msg-crypt/src' , ], ] |
8、之前的某位同事的实现文件,再次编辑,引用的调整,use wx\biz\msg\crypt\WXBizMsgCrypt;,再在 init() 方法中 去掉 require。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | <?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、将所有文件的编码调整为:UTF-8,重新运行程序,查看解密出的数据文件:componentVerifyTicketMsgXml.txt。符合预期。如图3
1 2 3 4 5 | <xml><AppId><![CDATA[wxd98c58b273d21bdf]]></AppId> <CreateTime>1625124291</CreateTime> <InfoType><![CDATA[component_verify_ticket]]></InfoType> <ComponentVerifyTicket><![CDATA[ticket@@@PaPM2hcjK8DPPkW_ZzbaR4DCQtirExq932-BBnxhQg19QWJtIKm3Io0TXsWMqcdv-18WnjkWSiSLNPSoXmqGSA]]></ComponentVerifyTicket> </xml> |
近期评论