浏览代码

微信小程序--同城配送

shizhongqi 11 月之前
父节点
当前提交
8f555b5e95

+ 0 - 4
app-hd/controllers/IntraCityController.php

@@ -2,9 +2,6 @@
 
 namespace hd\controllers;
 
-use bizHd\wx\classes\WxOpenClass;
-use common\components\dict;
-use common\components\expressUtil;
 use common\components\util;
 use Yii;
 use biz\shop\classes\ShopClass;
@@ -63,7 +60,6 @@ class IntraCityController extends BaseController
             }
 
             $result = IntraCityExpress::createStore($storeData);
-
             if ($result['errcode'] === 0) {
                 util::success("门店创建成功", $result);
             } else {

+ 117 - 60
common/components/intraCityExpress.php

@@ -5,6 +5,7 @@ namespace common\components;
 use yii\helpers\Json;
 use linslin\yii2\curl;
 use bizHd\wx\classes\WxOpenClass;
+use phpseclib\Crypt\RSA;
 
 class IntraCityExpress
 {
@@ -30,28 +31,79 @@ class IntraCityExpress
         return $merchant;
     }
 
-    private static function generateSign($method, $url, $timestamp, $nonce, $body, $merchant)
+    /**
+     * 使用 WxApi 方式生成微信API签名
+     * @param string $url 请求URL
+     * @param string $appId 小程序AppID
+     * @param int $timestamp 时间戳
+     * @param string $reqData 请求体JSON字符串
+     * @return string 签名字符串
+     */
+    private static function generateWxApiSignature($url, $appId, $timestamp, $reqData)
     {
-        $appId = $merchant['miniAppId'];
-        $serialNo = $merchant['serial_no'];
-        $privateKey = $merchant['private_key']; // Ensure this is the raw private key content
-
-        $parsedUrl = parse_url($url);
-        $path = $parsedUrl['path'] . (isset($parsedUrl['query']) ? '?' . $parsedUrl['query'] : '');
-
-        $message = "{$method}\n{$path}\n{$timestamp}\n{$nonce}\n{$body}\n";
-
-        openssl_sign($message, $signature, $privateKey, 'sha256WithRSAEncryption');
-        $base64Signature = base64_encode($signature);
-
-        return sprintf(
-            'WECHATPAY2-SHA256-RSA2048 appid=%s,timestamp="%d",nonce_str="%s",signature="%s",serial_no="%s"',
-            $appId,
-            $timestamp,
-            $nonce,
-            $base64Signature,
-            $serialNo
-        );
+        // 获取私钥
+        $env = getenv('YII_ENV') == 'production' ? 'production' : 'dev';
+        $privateKeyPath = __DIR__ . '/wxapi/' . $env . '/rsa-private-key.txt';
+        
+        if (!file_exists($privateKeyPath)) {
+            throw new \Exception("私钥文件不存在: {$privateKeyPath}");
+        }
+        
+        $privateKey = file_get_contents($privateKeyPath);
+        if (!$privateKey) {
+            throw new \Exception('无法获取私钥文件');
+        }
+
+        // 构建签名载荷,格式:$url\n$appId\n$timestamp\n$reqData
+        $payload = "$url\n$appId\n$timestamp\n$reqData";
+        
+        // 添加调试日志
+        \Yii::info("签名载荷: " . $payload, 'intracity_signature');
+        \Yii::info("AppID: " . $appId, 'intracity_signature');
+        \Yii::info("Timestamp: " . $timestamp, 'intracity_signature');
+        \Yii::info("URL: " . $url, 'intracity_signature');
+        \Yii::info("ReqData: " . $reqData, 'intracity_signature');
+
+
+
+        
+        // 方案一: 使用 OpenSSL(推荐方式,与微信官方示例一致)
+        // $signature = '';
+        // $result = openssl_sign($payload, $signature, $privateKey, OPENSSL_ALGO_SHA256);
+        // if (!$result) {
+        //     throw new \Exception('OpenSSL签名失败: ' . openssl_error_string());
+        // }
+        // $base64Signature = base64_encode($signature);
+        // \Yii::info("生成的签名: " . $base64Signature, 'intracity_signature');
+        // return $base64Signature;
+            
+
+            
+        // 方案二:使用 RSA SHA256签名
+        try {
+            // 使用RSA SHA256签名
+            // $rsa = new RSA();
+            // $rsa->loadKey($privateKey);
+            // $rsa->setHash("sha256");
+            // $rsa->setMGFHash("sha256");
+            // $signature = $rsa->sign($payload);
+            
+            $rsa = new RSA();
+            $rsa->loadKey($privateKey);
+            $rsa->setSignatureMode(RSA::SIGNATURE_PKCS1); // 明确使用PKCS#1 v1.5
+            $rsa->setHash("sha256");
+            // 不要设置MGF,PKCS#1 v1.5不使用MGF
+            $signature = $rsa->sign($payload);
+            
+            $base64Signature = base64_encode($signature);
+            \Yii::info("phpseclib生成的签名: " . $base64Signature, 'intracity_signature');
+            
+            return $base64Signature;
+            
+        } catch (\Exception $e2) {
+            \Yii::error("所有签名方法都失败 - OpenSSL: " . $e->getMessage() . " phpseclib: " . $e2->getMessage(), 'intracity_signature');
+            throw new \Exception('签名生成失败: OpenSSL和phpseclib都失败');
+        }
     }
 
     /**
@@ -71,22 +123,51 @@ class IntraCityExpress
 
         // 添加access_token到URL
         $urlWithToken = $url . (strpos($url, '?') !== false ? '&' : '?') . 'access_token=' . $accessToken;
-
         $timestamp = time();
-        $nonce = \Yii::$app->security->generateRandomString();
         $body = Json::encode($data);
         if ($body === '[]') {
             $body = '{}';
         }
 
-        //$signature = self::generateSign('POST', $urlWithToken, $timestamp, $nonce, $body, $merchant);
+
+        // ================ 选择哪个 appId  =================
+        // 微信开放平台 id
+//        $open = \biz\wx\classes\WxOpenClass::getByCondition(['style' => dict::getDict('ptStyle', 'hd')]);
+//        if (empty($open)) {
+//            util::fail('没有找到平台信息');
+//        }
+//        $component_app_id = $open['appId'];
+//        $appId = $component_app_id;
+
+        // 当前小程序的Appid
+        $appId = $merchant['miniAppId'] ?? util::fail('app-id 出错');
+
+
+
+        // 方式一: 使用WxApi方式处理请求 ============================
+        // try {
+        //     $wxApi = new \common\components\wxapi\WxApi($appId);
+        //     $result = $wxApi->request($url, $data);
+        //     return $result;
+        // } catch (\Exception $e) {
+        //     // 如果WxApi方式失败,回退到简单方式
+        //     util::fail('error');
+        // }
+
+
+        // 方式二: 自己处理请求 ============================
+        $signature = self::generateWxApiSignature($url, $appId, $timestamp, $body);
+        // 构建请求头,包含微信API签名所需的头部
+        $headers = [
+            'Content-Type: application/json',
+            'Accept: application/json',
+            'Wechatmp-Appid: ' . $appId,
+            'Wechatmp-TimeStamp: ' . $timestamp,
+            'Wechatmp-Signature: ' . $signature
+        ];
 
         $response = $curl->setOption(CURLOPT_POSTFIELDS, $body)
-            ->setOption(CURLOPT_HTTPHEADER, [
-                'Content-Type: application/json',
-                'Accept: application/json',
-                //'Authorization: ' . $signature
-            ])
+            ->setOption(CURLOPT_HTTPHEADER, $headers)
             ->post($urlWithToken);
 
         // 确保响应是字符串格式再进行JSON解码
@@ -97,25 +178,6 @@ class IntraCityExpress
         return Json::decode($response, true);
     }
 
-    public static function emptyRequest($url, $accessToken)
-    {
-        $curl = new curl\Curl();
-
-        // 添加access_token到URL
-        $urlWithToken = $url . (strpos($url, '?') !== false ? '&' : '?') . 'access_token=' . $accessToken;
-
-        $response = $curl->setOption(CURLOPT_POSTFIELDS, Json::encode(new \stdClass()))
-            ->setOption(CURLOPT_HTTPHEADER, ['Content-Type: application/json'])
-            ->post($urlWithToken);
-
-        // 确保响应是字符串格式再进行JSON解码
-        if (is_array($response)) {
-            return $response;
-        }
-        
-        return Json::decode($response, true);
-    }
-
     // ==================== API URL常量 ====================
     const API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin/express/intracity';
 
@@ -159,16 +221,15 @@ class IntraCityExpress
             $merchant = self::getMerchant();
         }
         
-//        $re = self::applyStore($merchant, $ptStyle);
-//        if (!is_array($re)) {
-//            $re = Json::decode($re, true);
-//        }
-//        if ($re['errcode'] != 0) {
-//            return $re;
-//        }
+        $re = self::applyStore($merchant, $ptStyle);
+        if (!is_array($re)) {
+            $re = Json::decode($re, true);
+        }
+        if ($re['errcode'] != 0) {
+            return $re;
+        }
 
         $accessToken = self::getAccessToken($merchant, $ptStyle);
-        
         $data = [
             'out_store_id' => $storeData['out_store_id'],
             'store_name' => $storeData['store_name'],
@@ -222,7 +283,6 @@ class IntraCityExpress
         }
         
         $accessToken = self::getAccessToken($merchant, $ptStyle);
-        
         $data = [
             'out_store_id' => $outStoreId,
         ];
@@ -243,9 +303,7 @@ class IntraCityExpress
         }
 
         $accessToken = self::getAccessToken($merchant, $ptStyle);
-
         return self::sendRequest(self::API_APPLY_STORE, new \stdClass(), $accessToken, $merchant);
-        //return self::getRequest(self::API_APPLY_STORE, $accessToken);
     }
 
 
@@ -264,7 +322,6 @@ class IntraCityExpress
         }
         
         $accessToken = self::getAccessToken($merchant, $ptStyle);
-        
         $data = [
             'out_store_id' => $orderData['out_store_id'],
             'store_order_id' => $orderData['store_order_id'], // 注意:文档是 store_order_id,不是 out_order_id

+ 1 - 0
common/components/miniUtil.php

@@ -680,6 +680,7 @@ class miniUtil
         $component_app_id = $open['appId'];
         $componentAccessToken = wxUtil::getComponentAccessToken($open);
         $appId = $merchant['miniAppId'];
+        //$appId = $open['appId']; // TODO 要换回来
         if ($ptStyle == 1) {
             $miniAccessToken = $merchant['miniAccessToken'];
             $miniAccessTokenTime = $merchant['miniAccessTokenTime'];

+ 316 - 0
common/components/wxapi/WxApi.php

@@ -0,0 +1,316 @@
+<?php
+
+/**
+ * 封装微信api签名安全类
+ */
+
+namespace common\components\wxapi;
+
+
+use phpseclib\Crypt\RSA;
+use Yii;
+use yii\base\ErrorException;
+
+class WxApi
+{
+
+    private $appId;
+    private $aes;
+    private $rsa;
+    private $cert;
+    private $url;
+
+    public function __construct($appId)
+    {
+        $this->appId = $appId;
+
+        $this->aes['sn'] = getenv('AES_SN');
+        $this->aes['key'] = getenv('AES_KEY');
+
+        $this->rsa['sn'] = getenv('RSA_SN');
+        $env =  getenv('YII_ENV') == 'production' ? 'production' : 'dev';
+        $this->rsa['rsa-public-key'] = file_get_contents(__DIR__ . '/' . $env . '/rsa-public-key.txt');
+        $this->rsa['rsa-private-key'] = file_get_contents(__DIR__. '/' . $env . '/rsa-private-key.txt');
+
+        $this->cert['sn'] = getenv('CERT_SN');
+        $this->cert['cert-key'] = file_get_contents(__DIR__ . '/' . $env . '/api.cer');
+    }
+
+    /**
+     * Name:对外方法用于所有微信api的请求方法
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 9:51
+     * @param $url
+     * @param $req
+     * @throws ErrorException
+     * @throws \Exception
+     */
+    public function request($url, $req)
+    {
+//        $accessToken = '';
+        $this->url = $url;
+        $urls = $url;// . "?access_token=" . $accessToken;
+        //1.数据加密
+        $newRe = $this->getRequestParam($url, $req);
+        //2.获取签名
+        $signature = $this->getSignature($newRe);
+        //本地验签 非必需
+        $checkLocalSig = $this->checkLocalSignature($newRe, $signature);
+        if (!$checkLocalSig) {
+            throw new ErrorException('本地验签错误');
+        }
+        $appId = $this->appId;
+        $headerArray = ['Wechatmp-Appid:' . $appId, 'Wechatmp-TimeStamp:' . $newRe['ts'], 'Wechatmp-Signature:' . $signature];
+        $data = $this->curlPost($urls, $newRe['reqData'], $headerArray);
+        $headers = $this->httpParseHeaders($data['header']);
+        $body = json_decode($data['body'], true);
+        //请求平台报错
+        if (isset($body['errcode'])) {
+            throw new ErrorException($body['errmsg']);
+        }
+        // 3.响应参数验签 目前存在问题
+        $vertify = $this->vertifyResponse($data);
+        //4.参数解密
+        return $this->jM($headers['Wechatmp-TimeStamp'], $body);
+    }
+
+    /**
+     * Name:获取accessToken
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 9:15
+     */
+//    public function getAccessToken()
+//    {
+//        $qr = new MiniHelper();
+//        return $qr->getAccessToken();
+//    }
+
+    /**
+     * Name:post请求
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 9:19
+     * @param $url
+     * @param $field
+     * @param $header
+     * @return array
+     */
+    public function curlPost($url, $field, $header)
+    {
+        $headerArray = array("Content-type:application/json;charset=utf-8", "Accept:application/json");
+        $headerArray = array_merge($headerArray, $header);
+        $curl = curl_init();
+        curl_setopt($curl, CURLOPT_HTTPHEADER, $headerArray);
+        curl_setopt($curl, CURLOPT_URL, $url);
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($curl, CURLOPT_POST, 1);
+        curl_setopt($curl, CURLOPT_POSTFIELDS, $field);
+        //输出响应头部
+        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($curl, CURLOPT_HEADER, true);
+        $str = curl_exec($curl);
+        $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
+        $headers = substr($str, 0, $headerSize);
+        $body = substr($str, $headerSize);
+        curl_close($curl);
+       return ['body' => $body, 'header' => $headers];
+    }
+
+    /**
+     * Name:对外方法用于所有微信api的请求通道
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 9:21
+     * @param $url
+     * @param $req
+     * @return array
+     * @throws \Exception
+     */
+    public function getRequestParam($url, $req)
+    {
+        $key = base64_decode($this->aes['key']);
+        $sn = $this->aes['sn'];
+        $appId = $this->appId;
+        $time = time();
+        //16位随机字符
+        $nonce = rtrim(base64_encode(random_bytes(16)), '=');
+        $addReq = ["_n" => $nonce, "_appid" => $appId, "_timestamp" => $time];
+        $realReq = array_merge($addReq, $req);
+        $realReq = json_encode($realReq);
+        //额外参数
+        $aad = $url . "|" . $appId . "|" . $time . "|" . $sn;
+        //12位随机字符
+        $iv = random_bytes(12);
+        $cipher = openssl_encrypt($realReq, "aes-256-gcm", $key, OPENSSL_RAW_DATA, $iv, $tag, $aad);
+        $iv = base64_encode($iv);
+        $data = base64_encode($cipher);
+        $authTag = base64_encode($tag);
+        $reqData = ["iv" => $iv, "data" => $data, "authtag" => $authTag];
+        //校验本地加密是否正确 非必须
+        // $checkParam = $this->checkParam($key, $authTag, $iv, $data, $aad);
+        return ['ts' => $time, 'reqData' => json_encode($reqData)];
+    }
+
+
+    /**
+     * Name:请求前本地验签
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 9:57
+     * @param $key
+     * @param $authTag
+     * @param $iv
+     * @param $data
+     * @param $aad
+     */
+    private function checkParam($key, $authTag, $iv, $data, $aad)
+    {
+        $iv = base64_decode($iv);
+        $data = base64_decode($data);
+        $authTag = base64_decode($authTag);
+        return openssl_decrypt($data, "aes-256-gcm", $key, OPENSSL_RAW_DATA, $iv, $authTag, $aad);
+    }
+
+    /**
+     * Name:获取签名
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 10:03
+     * @param array $newRe
+     */
+    private function getSignature(array $newRe)
+    {
+        $time = $newRe['ts'];
+        $key = $this->rsa['rsa-private-key'];
+        $url = $this->url;
+        $appId = $this->appId;
+        $reqData = $newRe['reqData'];
+        $payload = "$url\n$appId\n$time\n$reqData";
+        $rsa = new RSA();
+        $rsa->loadKey($key);
+        $rsa->setHash("sha256");
+        $rsa->setMGFHash("sha256");
+        $signature = $rsa->sign($payload);
+        return base64_encode($signature);
+    }
+
+    /**
+     * Name:请求前本地验签
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 10:11
+     * @param array $newRe
+     * @param string $signature
+     */
+    private function checkLocalSignature(array $newRe, string $signature)
+    {
+        $signature = base64_decode($signature);
+        $rsaPubKey = $this->rsa['rsa-public-key'];
+        $appId = $this->appId;
+        $url = $this->url;
+        $time = $newRe['ts'];
+        $reqData = $newRe['reqData'];
+        $payload = "$url\n$appId\n$time\n$reqData";
+        $payload = utf8_encode($payload);
+        $rsa = new RSA();
+        $rsa->loadKey($rsaPubKey);
+        $rsa->setHash("sha256");
+        $rsa->setMGFHash("sha256");
+        return $rsa->verify($payload, $signature);
+    }
+
+    /**
+     * Name:解析头部信息
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 10:28
+     * @param $headerString
+     * @return array
+     */
+    private function httpParseHeaders($headerString)
+    {
+        $headers = [];
+        $lines = explode("\r\n", $headerString);
+        foreach ($lines as $line) {
+            $line = trim($line);
+            if (!empty($line)) {
+                $parts = explode(':', $line, 2);
+                $key = trim($parts[0]);
+                $value = isset($parts[1]) ? trim($parts[1]) : '';
+                $headers[$key] = $value;
+            }
+        }
+        return $headers;
+    }
+
+    /**
+     * Name:解密参数
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 10:31
+     * @param $ts
+     * @param $body
+     * @return mixed|null
+     * @throws ErrorException
+     */
+    private function jM($ts, $body)
+    {
+        $url = $this->url;
+        $appId = $this->appId;
+        $sn = $this->aes['sn'];
+        $aad = $url . '|' . $appId . '|' . $ts . '|' . $sn;
+        $key = $this->aes['key'];
+        $key = base64_decode($key);
+        $iv = base64_decode($body['iv']);
+        $data = base64_decode($body['data']);
+        $authTag = base64_decode($body['authtag']);
+        $result = openssl_decrypt($data, "aes-256-gcm", $key, OPENSSL_RAW_DATA, $iv, $authTag, $aad);
+        if (!$result) {
+            throw new ErrorException();
+        }
+        $result = json_decode($result, true);
+        return $result;
+
+    }
+
+    /**
+     * Name:验证响应值
+     * User: zcw
+     * Date: 2023/7/14
+     * Time: 11:16
+     * @param $data
+     */
+    private function vertifyResponse($data)
+    {
+        $headers = $this->httpParseHeaders($data['header']);
+        $nowTime = time();
+        $reTime = $headers['Wechatmp-TimeStamp'];
+        $appId = $this->appId;
+        $cert = $this->cert;
+        $sn = $cert['sn'];
+        $key = $cert['cert-key'];
+        $url = $this->url;
+        if ($appId != $headers['Wechatmp-Appid'] || $nowTime - $reTime > 300){
+            throw new \ErrorException('返回值安全字段校验失败');
+        }
+        if ($sn == $headers['Wechatmp-Serial']) {
+            $signature = $headers['Wechatmp-Signature'];
+        } elseif ($sn == $headers['Wechatmp-Serial-Deprecated']) {
+            $signature = $headers['Wechatmp-Signature-Deprecated'];
+        } else {
+            throw new \ErrorException('返回值sn不匹配');
+        }
+        $reData = $data['body'];
+        $payload = "$url\n$appId\n$reTime\n$reData";
+        $payload = utf8_encode($payload);
+        $signature = base64_decode($signature);
+        $rsa = new RSA();
+        $rsa->loadKey($key);
+        $rsa->setHash("sha256");
+        $rsa->setMGFHash("sha256");
+        return $rsa->verify($payload, $signature);
+    }
+
+}

+ 24 - 0
common/components/wxapi/dev/api.cer

@@ -0,0 +1,24 @@
+-----BEGIN CERTIFICATE-----
+MIID9DCCAtygAwIBAgIUaB2siFbrXAjAu0mf0XMmZP24CcIwDQYJKoZIhvcNAQEL
+BQAwbTELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUd1YW5nRG9uZzERMA8GA1UEBwwI
+U2hlblpoZW4xEDAOBgNVBAoMB1RlbmNlbnQxEDAOBgNVBAsMB1RlbmNlbnQxEzAR
+BgNVBAMMCnRzbTAwMDAwMDYwHhcNMjMwNTAxMDkxMTQyWhcNMzMwNDI4MDkxMTQy
+WjCBmDEeMBwGCSqGSIb3DQEJARYPd2VpeGlubXBAcXEuY29tMRswGQYDVQQDDBJ3
+eGU0Njc1YmFiMjk5YTUyZjcxFTATBgNVBAoMDFRlbmNlbnQgSW5jLjEOMAwGA1UE
+CwwFV3hnTXAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlHdWFuZ0RvbmcxETAPBgNV
+BAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwc+s
+dYmkqOwcmgoAKFupwKkke0rF9ZBdsm9hImgeVtIqvdMu0gDQA+hGQCKGbNZSlH87
+wo3F+Q/p61n5XxhMPkHHCttazeO0o56JiJopi69WT/VCvG7Zim8ZQkWpsdCDpwNM
+nwL4LudYN5oyDIdMTsCWur+eFA4MOde9ZEkELzFXjl0n9A0sZDiprFoJTab5uTRq
+qeoTvPjKQVIw+LHFN0ETV5M8UYIunfuFeg5bHGAN+6WaTtiQfZhPnH9Oq0G4ucn5
+6TX4lSTk/p/lLiNDri+UTiEeZlX8nL4MHXmXyQagtC4gC1kzbwIwLP4zaVgmu029
+dCVKa54HrDGbcLh3kwIDAQABo2AwXjAdBgNVHQ4EFgQUoiWZD9zdi4DNVWijaaw9
+bromeScwHwYDVR0jBBgwFoAURM1183H4z2eJGmP5z/zWI7tjRZAwDAYDVR0TAQH/
+BAIwADAOBgNVHQ8BAf8EBAMCBsAwDQYJKoZIhvcNAQELBQADggEBAAWP97onRATH
+V/mEezri7R5Ow9dX9BRIOvuAmpWwHlaTRtVrgi9VObIB2wbiSX6aMd1s6P9Tv+hn
+VYgbuRMXaSBjc6mrsAWyeMmZsEMGeqrZRqDyBB0fYLyYPhTFpReZ01pfvv47uBn1
+Rs0kQlOcLVNtPr3y/5yPjR5AT1Gvq1A2zDoVtGQm1Fbn1YhNiBxDfz8g6UgIWAOk
+ZL+Qa7iDQtMu+pOvclK3QaRLBeKx7MeRqzN/UNjnD9HLhs5j39AGIIQGAWtI0xBb
+JXqDqv5rivxJbHXsIPtof+XuvaD8JIWO2HchTHvdPhfQNGYjZAoBU6PvKVDmyhr9
+HDfJJ5hF6dY=
+-----END CERTIFICATE-----

+ 27 - 0
common/components/wxapi/dev/rsa-private-key.txt

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAtdlBLbHTdWlEPy3r7WArWTg4ccTi6hPAiQ0MxFnZsGqBX0A+
+qhAufc25S0eF0zYj2r9EODoO/L9qfyzkQDNcRtSZ16uTzLByUQEKTCMI+JtqDpE1
+fqkdVfV7ZhkBDTn9pGLu9qjqclNVdfAwgYpVfy07kbt37YEUGm7ekWXGZf3A1bil
+psbr4RZ7OoCacanfTxan2S1puoASaHd/DUblHPPPaDgoLNVNzFBklvkXyyn9HN9O
+kE+HPCQ7ZAKZEnVOQogJmgi3yksXJZ1n9hUT3Mye8t1U1boGKvp+fXx7fCP4J2Rs
+ULm7m7XnzUEifsFxKmKpaCJF9t+/CZxboevhxwIDAQABAoIBAHkiZ5CQzFOB87xC
+Us6lKTsdgDwI8z8KOU8SKlcBo0kpKVTR7uxKKy4SREQpOLQhdHDayA7MXf9vYvmk
+Zcd+bxGfvXs1CBdp0jyzfLCLBgbVQCjEAeaFsMz54WF5doHhB1zhql0U2Fefu2X8
+wdMI2zsEXpINVy4WtdWF1Sz1ptt4tWMS7hxGd1AkBRJEwtiCoesH4UrnJL9wpYWQ
+OWbARIlxWE1PQuj9pzOtpqq11kPE20pDvT7IGLtc5AZ/eVCrA+3sOlm7to6kzVfJ
+Ze15m3spc2x7pJbxrRUzFdsxsCQcYvvFSU83kJ6bcmgY5e4lnEn7DtR3NZIw6o7B
+neC45cECgYEA5YAdsUJSSxnzW3bq/Hlk8JQl/TigxoA0sdNKuhRFPBjY1DOuEbV7
+zG8XYTukPOtFDhK4OwTab1TwHEmxrw7SLrEUhiyaL/vItuc0WvuUilSIUViZmXo7
+YvA4fyG5/JNnItR7EdVk3rPM4pqZXZt1IAy818tufcMZykjFLiAbjD0CgYEAytiV
+FWxbXkO3bhIOzupN4OejDGA66ycHX1Oa1OHGcA34KYP24Dv0mJPw2S447725T5cV
+KKP2DtQr0lWjtx0Vy/cP6sl8IiJSXILE0wxs4BqypiNY+hBZ+b4EaEOmSCzr5D20
+pCeKiA1qifxPxfjzZ2bJp6zmA1mv7SfJ09gXslMCgYA+csshlcNgzjHrHIO6qamu
+0RE5QzR0byRnkvANjEB+puAxddKS3QhPy5bYDWuWbAqBVtSssphhnQItIFxqHyVQ
+MT09eVuHXQLzyhvz+eskbPYe9HXvTlRkiqtE5L+AG/f/gUPvyVpGQzSoIJtE3m1T
+iEPGkIODUxhsc7q7316/nQKBgQDDTActmyfU+CmRBj3PpfLZSOvIrJXNdcQ5WYtG
+zyF5HVoCzpVQiykSBc3rq/8Rg375TCMI/+OVn12Zou5/DLfBqtteWCL10kmt3BGY
+iOwCUHIUVxABouCd/P7NS+S6tNVg6LAVJCTSnOgodg5wMyJWObaJg4PpUd553McK
++ZDHFQKBgBNzAOiftV1sb6mA28Tcxb6KO4uyhGnN4QQCTDrY+lr0MzH8O5gEe7DA
+3QaY9RPZXODi+aJj2hKfVjac1I0LbadtUVNVUNm6RPjG8wTTCCC8kUsbTA8ZzuX8
+fgq3Ob8AygNGXUEbbctY9fnmN4MRGwczFYOhZdDe76hRs/huNtON
+-----END RSA PRIVATE KEY-----

+ 1 - 0
common/components/wxapi/dev/rsa-public-key.txt

@@ -0,0 +1 @@
+-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtdlBLbHTdWlEPy3r7WAr WTg4ccTi6hPAiQ0MxFnZsGqBX0A+qhAufc25S0eF0zYj2r9EODoO/L9qfyzkQDNc RtSZ16uTzLByUQEKTCMI+JtqDpE1fqkdVfV7ZhkBDTn9pGLu9qjqclNVdfAwgYpV fy07kbt37YEUGm7ekWXGZf3A1bilpsbr4RZ7OoCacanfTxan2S1puoASaHd/DUbl HPPPaDgoLNVNzFBklvkXyyn9HN9OkE+HPCQ7ZAKZEnVOQogJmgi3yksXJZ1n9hUT 3Mye8t1U1boGKvp+fXx7fCP4J2RsULm7m7XnzUEifsFxKmKpaCJF9t+/CZxboevh xwIDAQAB -----END PUBLIC KEY-----

+ 2 - 1
composer.json

@@ -37,7 +37,8 @@
         "baidu/aip-sdk": "dev-master",
         "picqer/php-barcode-generator": "v0.3",
         "getuilaboratory/getui-pushapi-php-client-v2":"dev-master",
-        "shishaoqi/meituan-flash-purchase": "v1.1.0"
+        "shishaoqi/meituan-flash-purchase": "v1.1.0",
+        "phpseclib/phpseclib": "~2.0"
     },
     "require-dev": {
         "yiisoft/yii2-codeception": "~2.0.5",

+ 1 - 1
env.php

@@ -3,7 +3,7 @@
  * Setup application environment
  */
 
-$dotenv = \Dotenv\Dotenv::create(__DIR__);
+$dotenv = \Dotenv\Dotenv::createImmutable(__DIR__);
 $dotenv->load();
 
 defined('YII_DEBUG') or define('YII_DEBUG', getenv('YII_DEBUG') === 'true');