sdkAppId = $config['sdkAppId']; $this->secretKey = $config['secretKey']; \think\facade\Log::info('TencentImService初始化 - sdkAppId: ' . $this->sdkAppId . ', secretKey长度: ' . strlen($this->secretKey)); } /** * @notes 生成UserSig(使用腾讯云官方算法) * @param string $userId * @param int $expire * @return string|false */ private function generateUserSig(string $userId, int $expire = 86400) { try { $api = new TLSSigAPIv2($this->sdkAppId, $this->secretKey); $userSig = $api->genUserSig($userId, $expire); \think\facade\Log::info('UserSig生成成功 - userId: ' . $userId . ', sig长度: ' . strlen($userSig)); return $userSig; } catch (\Exception $e) { \think\facade\Log::error('生成UserSig失败: ' . $e->getMessage()); return false; } } /** * @notes 导入单个账号到IM * @param string $userId 用户ID * @param string $nick 昵称(可选) * @param string $faceUrl 头像URL(可选) * @return array|false */ public function importAccount(string $userId, string $nick = '', string $faceUrl = '') { try { \think\facade\Log::info('开始导入IM账号 - userId: ' . $userId . ', nick: ' . $nick . ', sdkAppId: ' . $this->sdkAppId); // 生成管理员UserSig $adminUserSig = $this->generateUserSig($this->adminIdentifier); if (!$adminUserSig) { throw new \Exception('生成管理员UserSig失败'); } \think\facade\Log::info('管理员UserSig生成成功'); // 构建请求URL $random = rand(0, 4294967295); $url = sprintf( 'https://console.tim.qq.com/v4/im_open_login_svc/account_import?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json', $this->sdkAppId, $this->adminIdentifier, urlencode($adminUserSig), $random ); \think\facade\Log::info('请求URL构建完成'); // 构建请求体 $data = [ 'UserID' => $userId ]; if ($nick) { $data['Nick'] = $nick; } if ($faceUrl) { $data['FaceUrl'] = $faceUrl; } \think\facade\Log::info('请求数据: ' . json_encode($data, JSON_UNESCAPED_UNICODE)); // 发送请求 $result = $this->httpPost($url, json_encode($data)); \think\facade\Log::info('HTTP响应: ' . substr($result, 0, 500)); if (!$result) { throw new \Exception('请求失败:无响应'); } $response = json_decode($result, true); if (!$response) { throw new \Exception('响应解析失败:' . substr($result, 0, 200)); } \think\facade\Log::info('响应解析成功: ' . json_encode($response, JSON_UNESCAPED_UNICODE)); // 检查响应状态 if ($response['ActionStatus'] !== 'OK') { $errorMsg = sprintf( '导入账号失败 - ErrorCode: %s, ErrorInfo: %s', $response['ErrorCode'] ?? 'unknown', $response['ErrorInfo'] ?? '未知错误' ); throw new \Exception($errorMsg); } return [ 'success' => true, 'userId' => $userId, 'message' => '账号导入成功' ]; } catch (\Exception $e) { $errorMsg = sprintf( '导入IM账号失败 - userId: %s, error: %s', $userId, $e->getMessage() ); \think\facade\Log::error($errorMsg); return [ 'success' => false, 'userId' => $userId, 'message' => $e->getMessage() ]; } } /** * @notes 批量导入账号 * @param array $accounts 账号列表 [['userId' => 'xxx', 'nick' => 'xxx', 'faceUrl' => 'xxx'], ...] * @return array */ public function batchImportAccounts(array $accounts): array { $results = []; foreach ($accounts as $account) { $userId = $account['userId'] ?? ''; $nick = $account['nick'] ?? ''; $faceUrl = $account['faceUrl'] ?? ''; if (!$userId) { continue; } $result = $this->importAccount($userId, $nick, $faceUrl); $results[] = $result; } return $results; } /** * @notes 删除账号 * @param array $userIds 用户ID列表 * @return array|false */ public function deleteAccounts(array $userIds) { try { // 生成管理员UserSig $adminUserSig = $this->generateUserSig($this->adminIdentifier); if (!$adminUserSig) { throw new \Exception('生成管理员UserSig失败'); } // 构建请求URL $random = rand(0, 4294967295); $url = sprintf( 'https://console.tim.qq.com/v4/im_open_login_svc/account_delete?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json', $this->sdkAppId, $this->adminIdentifier, urlencode($adminUserSig), $random ); // 构建请求体 $data = [ 'DeleteItem' => array_map(function($userId) { return ['UserID' => $userId]; }, $userIds) ]; // 发送请求 $result = $this->httpPost($url, json_encode($data)); if (!$result) { throw new \Exception('请求失败'); } $response = json_decode($result, true); if (!$response) { throw new \Exception('响应解析失败'); } // 检查响应状态 if ($response['ActionStatus'] !== 'OK') { throw new \Exception($response['ErrorInfo'] ?? '删除账号失败'); } return [ 'success' => true, 'message' => '账号删除成功' ]; } catch (\Exception $e) { \think\facade\Log::error('删除IM账号失败', [ 'userIds' => $userIds, 'error' => $e->getMessage() ]); return [ 'success' => false, 'message' => $e->getMessage() ]; } } /** * @notes 发送HTTP POST请求 * @param string $url * @param string $data * @return string|false */ private function httpPost(string $url, string $data) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($data) ]); $result = curl_exec($ch); $error = curl_error($ch); curl_close($ch); if ($error) { \think\facade\Log::error('HTTP请求失败', [ 'url' => $url, 'error' => $error ]); return false; } return $result; } }