Jelajahi Sumber

[智价云] 关注服务号信息更新

public 3 hari lalu
induk
melakukan
1a6f9e516e
1 mengubah file dengan 99 tambahan dan 26 penghapusan
  1. 99 26
      app/Http/Controllers/Api/Wechat/OfficialNotify.php

+ 99 - 26
app/Http/Controllers/Api/Wechat/OfficialNotify.php

@@ -21,15 +21,15 @@ class OfficialNotify extends Controller
         if ($_SERVER['REQUEST_METHOD'] === 'GET') {
             return $this->checkSignature();
         }
-        
+
         // 2. 处理微信事件推送(POST请求)
         if ($_SERVER['REQUEST_METHOD'] === 'POST') {
             return $this->handleEvent($EmployeeOpenidModel);
         }
-        
+
         return 'success';
     }
-    
+
     /**
      * 处理微信事件
      */
@@ -38,44 +38,48 @@ class OfficialNotify extends Controller
         // 获取微信推送的原始数据
         $xmlData = file_get_contents('php://input');
         $xml = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);
-        
+
         if (!$xml) {
             return 'success';
         }
-        
+        $xmlData = $this->xmlToArray($xmlData);
+        $response_data_xml = $this->decryptMsg($xmlData['Encrypt']);
+        $response_data = $this->xmlToArray($response_data_xml);
+        Log::info('wechat_subscribe_info', '微信公众号事件,解密内容', ['xmlData' => $xmlData, 'response_data' => $response_data]);
+
         // 提取关键信息
-        $fromUsername = (string)$xml->FromUserName;  // 用户的公众号OpenID
-        $toUsername = (string)$xml->ToUserName;      // 公众号原始ID
-        $event = (string)$xml->Event;                 // 事件类型
-        $eventKey = (string)$xml->EventKey;           // 事件KEY值(扫码关注时会有)
-        
-        // 记录日志,方便调试
-        Log::info('wechat_subscribe_info', '微信关注事件', [
-            'FromUserName' => $fromUsername, 
-            'ToUserName' => $toUsername, 
-            'event' => $event, 
-            'eventKey' => $eventKey
-        ]);
-        
+        $fromUsername = (string)$response_data['FromUserName'];  // 用户的公众号OpenID
+        $toUsername = (string)$response_data['ToUserName'];      // 公众号原始ID
+        $event = (string)$response_data['Event'];                 // 事件类型
+
         // 处理关注事件
         if ($event == 'subscribe') {
             try {
                 // 尝试获取用户UnionID
                 $Official = new Official();
                 $official_user_info = $Official->getApp()->user->get($fromUsername);
+                Log::info('wechat_subscribe_info', '微信公众号事件,获取用户信息', ['FromUserName' => $fromUsername, 'response_data' => $official_user_info]);
                 $unionid = isset($official_user_info['unionid']) ? $official_user_info['unionid'] : '';
-                
+
                 if ($unionid) {
                     // 1. 有UnionID,直接绑定公众号OpenID
                     $user_open_data = $EmployeeOpenidModel->where(['unionid' => $unionid])->first();
                     if ($user_open_data) {
                         $user_open_data->official_openid = $fromUsername;
                         $user_open_data->save();
-                        Log::info('wechat_subscribe_success', '绑定成功', ['unionid' => $unionid, 'openid' => $fromUsername]);
+                    } else {
+                        //新增记录
+                        $insert_data = [
+                            'unionid' => $unionid,
+                            'official_openid' => $fromUsername,
+                            'insert_time' => time(),
+                            'type' => 1
+                        ];
+                        $EmployeeOpenidModel->insertGetId($insert_data);
                     }
                 } else {
                     Log::info('wechat_subscribe_error', '获取UnionID失败', [
-                        'data' => $fromUsername, 
+                        'data' => $fromUsername,
                         'request_data' => $official_user_info
                     ]);
                 }
@@ -85,11 +89,56 @@ class OfficialNotify extends Controller
                 ]);
             }
         }
-        
+
         // 重要:必须返回success
         return 'success';
     }
 
+    /**
+     * 解密消息
+     */
+    private function decryptMsg($encrypt)
+    {
+        try {
+            // Base64解码
+            $encrypted = base64_decode($encrypt);
+            $encodingAesKey = config('wechat.openplat.aes_key', '');
+            $appId = config('wechat.openplat.app_id', '');
+            // 解密
+            $key = base64_decode($encodingAesKey . '=');
+            $iv = substr($key, 0, 16);
+
+            $decrypted = openssl_decrypt(
+                $encrypted,
+                'AES-256-CBC',
+                $key,
+                OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,
+                $iv
+            );
+
+            // 去除填充的字符
+            $pad = ord(substr($decrypted, -1));
+            $decrypted = substr($decrypted, 0, -$pad);
+
+            // 解析内容
+            $content = substr($decrypted, 16); // 去掉16个随机字节
+            $xmlLen = unpack('N', substr($content, 0, 4))[1];
+
+            // 验证AppId
+            $appId = substr($content, 4 + $xmlLen);
+            if ($appId != $appId) {
+                Log::error('wechat_appid_error', 'AppId不匹配', ['got' => $appId, 'expect' => $appId]);
+                return false;
+            }
+
+            // 返回XML内容
+            return substr($content, 4, $xmlLen);
+        } catch (\Exception $e) {
+            Log::error('wechat_decrypt_error', '解密异常', ['error' => $e->getMessage()]);
+            return false;
+        }
+    }
+
     /**
      * 验证服务器地址有效性
      */
@@ -99,20 +148,44 @@ class OfficialNotify extends Controller
         $timestamp = $_GET["timestamp"] ?? '';
         $nonce = $_GET["nonce"] ?? '';
         $echostr = $_GET["echostr"] ?? '';
-        
+
         if (!$signature || !$timestamp || !$nonce) {
             return 'Invalid request';
         }
-        
+
         $token = config('wechat.openplat.token', 'your_token_here');
         $tmpArr = [$token, $timestamp, $nonce];
         sort($tmpArr, SORT_STRING);
         $tmpStr = sha1(implode($tmpArr));
-        
+
         if ($tmpStr == $signature) {
             return $echostr;  // 验证成功,返回echostr
         } else {
             return 'Invalid signature';
         }
     }
-}
+
+    /**
+     * XML转数组
+     * @param string $xml XML字符串
+     * @return array
+     */
+    private function xmlToArray($xml)
+    {
+        // 禁止引用外部xml实体
+        libxml_disable_entity_loader(true);
+
+        // 加载XML字符串
+        $xmlObject = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
+
+        if (!$xmlObject) {
+            return [];
+        }
+
+        // 将SimpleXMLElement对象转换为JSON,再转换为数组
+        $json = json_encode($xmlObject);
+        $array = json_decode($json, true);
+
+        return $array ?: [];
+    }
+}