274 lines
8.5 KiB
PHP
274 lines
8.5 KiB
PHP
<?php
|
|
|
|
namespace app\common\service;
|
|
|
|
/**
|
|
* 腾讯云IM服务类
|
|
* Class TencentImService
|
|
* @package app\common\service
|
|
*/
|
|
class TencentImService
|
|
{
|
|
private $sdkAppId;
|
|
private $secretKey;
|
|
private $adminIdentifier = 'administrator'; // 管理员账号
|
|
|
|
public function __construct()
|
|
{
|
|
$config = config('project.trtc');
|
|
$this->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;
|
|
}
|
|
}
|