logger->info('Wechat API: Requesting session key', ['code' => $code]); $url = $this->config->getLoginUrl() . '?appid=' . $this->config->getAppId() . '&secret=' . $this->config->getAppSecret() . '&js_code=' . $code . '&grant_type=authorization_code'; $this->curl->get($url); $response = $this->curl->getBody(); $result = json_decode($response, true); $this->logger->info('Wechat API: Session key response', ['url' => $url,'response' => $result]); if (isset($result['errcode'])) { $this->logger->error('Wechat API: Failed to get session key', ['error' => $result]); throw new LocalizedException(__('获取微信session_key失败: %1', $result['errmsg'])); } return $result; } /** * 解密微信小程序用户数据 * * @param string $encryptedData 加密数据 * @param string $iv 初始向量 * @param string $sessionKey 会话密钥 * @return array * @throws LocalizedException */ public function decryptData($encryptedData, $iv, $sessionKey) { $this->logger->info('Wechat API: Attempting to decrypt data'); if (strlen($sessionKey) != 24) { $this->logger->error('Wechat API: Session key length error'); throw new LocalizedException(__('会话密钥长度错误')); } $aesKey = base64_decode($sessionKey); if (strlen($iv) != 24) { $this->logger->error('Wechat API: IV length error'); throw new LocalizedException(__('初始向量长度错误')); } $aesIV = base64_decode($iv); $aesCipher = base64_decode($encryptedData); $result = openssl_decrypt( $aesCipher, 'AES-128-CBC', $aesKey, OPENSSL_RAW_DATA, $aesIV ); if (!$result) { $this->logger->error('Wechat API: Data decryption failed'); throw new LocalizedException(__('数据解密失败')); } $dataObj = json_decode($result, true); if (!$dataObj) { $this->logger->error('Wechat API: Decrypted data format error'); throw new LocalizedException(__('解密数据格式错误')); } if ($dataObj['watermark']['appid'] != $this->config->getAppId()) { $this->logger->error('Wechat API: Data source error', ['expected' => $this->config->getAppId(), 'actual' => $dataObj['watermark']['appid']]); throw new LocalizedException(__('数据来源错误')); } $this->logger->info('Wechat API: Data decrypted successfully'); return $dataObj; } /** * 解析微信小程序手机号(本地解密方式) * * @param string $encryptedData 加密的手机号数据 * @param string $iv 初始向量 * @param string $code 微信登录临时凭证 * @return string * @throws LocalizedException */ public function getPhoneNumberByDecrypt($encryptedData, $iv, $code) { $this->logger->info('Wechat API: Requesting phone number via local decryption', ['code' => $code]); // 获取session_key $sessionData = $this->getSessionKey($code); if (!isset($sessionData['session_key'])) { $this->logger->error('Wechat API: Failed to get session key'); throw new LocalizedException(__('获取会话密钥失败')); } // 解密手机号 $decryptedData = $this->decryptData($encryptedData, $iv, $sessionData['session_key']); if (!isset($decryptedData['phoneNumber'])) { $this->logger->error('Wechat API: Failed to parse phone number'); throw new LocalizedException(__('解析手机号失败')); } $this->logger->info('Wechat API: Phone number obtained via local decryption'); return $decryptedData['phoneNumber']; } /** * 通过微信API获取用户手机号 * * @param string $code 手机号获取凭证 * @return string * @throws LocalizedException */ public function getPhoneNumberByApi($code) { try { $this->logger->info('Wechat API: Requesting phone number via API', ['code' => $code]); // 获取access_token $accessToken = $this->getAccessToken(); // 构建请求URL $url = $this->config->getPhoneNumberUrl() . '?access_token=' . $accessToken; // 构建请求数据 $requestData = [ 'code' => $code ]; // 发送POST请求 $this->curl->addHeader('Content-Type', 'application/json'); $this->curl->post($url, json_encode($requestData)); // 获取响应 $response = $this->curl->getBody(); $result = json_decode($response, true); $this->logger->info('Wechat API: Phone number API response', ['response' => $result]); // 检查错误 if (isset($result['errcode']) && $result['errcode'] != 0) { $this->logger->error('Wechat API: Failed to get phone number', ['error' => $result]); throw new LocalizedException(__('获取手机号失败: %1', $result['errmsg'])); } // 检查返回数据 if (!isset($result['phone_info']['phoneNumber'])) { $this->logger->error('Wechat API: Phone number data missing in response'); throw new LocalizedException(__('手机号数据获取失败')); } $this->logger->info('Wechat API: Phone number obtained via API'); return $result['phone_info']['phoneNumber']; } catch (\Exception $e) { $this->logger->error('Wechat API: Error when getting phone number', ['exception' => $e->getMessage()]); throw new LocalizedException(__('获取手机号时发生错误: %1', $e->getMessage())); } } /** * 获取微信access_token * * @return string * @throws LocalizedException */ private function getAccessToken() { $this->logger->info('Wechat API: Requesting access token'); $url = $this->config->getApiUrl() . '/cgi-bin/token?grant_type=client_credential' . '&appid=' . $this->config->getAppId() . '&secret=' . $this->config->getAppSecret(); $this->curl->get($url); $response = $this->curl->getBody(); $result = json_decode($response, true); $this->logger->info('Wechat API: Access token response', ['response' => $result]); if (isset($result['errcode'])) { $this->logger->error('Wechat API: Failed to get access token', ['error' => $result]); throw new LocalizedException(__('获取access_token失败: %1', $result['errmsg'])); } if (!isset($result['access_token'])) { $this->logger->error('Wechat API: Access token missing in response'); throw new LocalizedException(__('access_token获取失败')); } $this->logger->info('Wechat API: Access token obtained successfully'); return $result['access_token']; } }