Files

226 lines
7.7 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\common\library\live\message\provider;
use app\common\library\live\message\ProviderInterface;
use app\common\library\live\message\Result;
use app\common\model\config\System;
use aliyun\LiveMessage;
/**
* 阿里云互动消息服务商适配器
* 基于 \aliyun\LiveMessage 实现统一接口
*/
class Aliyun implements ProviderInterface
{
/**
* @var LiveMessage 阿里云 SDK 实例
*/
protected $sdk;
/**
* 构造函数,从配置 aliyun_message 读取阿里云相关参数并实例化 SDK
*/
public function __construct()
{
$config = System::getConfig('aliyun_message');
$appId = (is_array($config) && isset($config['app_id'])) ? $config['app_id'] : '';
$appKey = (is_array($config) && isset($config['app_key'])) ? $config['app_key'] : '';
$appSign = (is_array($config) && isset($config['app_sign'])) ? $config['app_sign'] : '';
$accessKeyId = (is_array($config) && isset($config['access_key_id'])) ? $config['access_key_id'] : '';
$accessKeySecret = (is_array($config) && isset($config['access_key_secret'])) ? $config['access_key_secret'] : '';
$dataCenter = (is_array($config) && !empty($config['data_center'])) ? $config['data_center'] : 'cn-shanghai';
$this->sdk = new LiveMessage($appId, $appKey, $appSign, $accessKeyId, $accessKeySecret, $dataCenter);
}
/**
* 发送消息到群组
* @param string $groupId 群组ID
* @param string $body 消息体
* @param int $msgType 消息类型(业务 type 映射后的阿里云 MsgType
* @param string $senderId 发送者ID
* @param string $senderMeta 发送者扩展信息
* @param string $msgTid 消息唯一标识
* @return Result data 含 msg_tid
*/
public function send($groupId, $body, $msgType = 10001, $senderId = '', $senderMeta = '', $msgTid = '')
{
// 若未传入 senderId,使用系统默认(管理员发送场景)
if ($senderId === '') {
$senderId = 'system';
}
$result = $this->sdk->sendGroupMessage($groupId, $body, $msgType, $senderId, $senderMeta, $msgTid);
if ($result['success']) {
return Result::success([
'msg_tid' => isset($result['data']['msg_tid']) ? $result['data']['msg_tid'] : '',
], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 撤回/删除消息
* @param string $groupId 群组ID
* @param string $msgTid 阿里云消息唯一标识
* @return Result
*/
public function del($groupId, $msgTid)
{
$result = $this->sdk->deleteGroupMessage($groupId, $msgTid);
if ($result['success']) {
return Result::success($result['data'], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 获取群组在线用户
* 对于超过 2000 人的超级大群,返回 success=false 且 error='SuperLargeGroup',业务层可降级处理
* @param string $groupId 群组ID
* @param int $pageSize 每页数量(10-30,阿里云实际限制)
* @param int $nextPageToken 下一页起始位置
* @return Result data 含 total、list、next_page_token、has_more
*/
public function getOnlineUser($groupId, $pageSize = 20, $nextPageToken = 0)
{
$result = $this->sdk->listGroupUsers($groupId, $pageSize, $nextPageToken);
if ($result['success']) {
$data = $result['data'];
$userIds = [];
if (isset($data['user_list']) && is_array($data['user_list'])) {
foreach ($data['user_list'] as $user) {
if (isset($user['user_id'])) {
$userIds[] = $user['user_id'];
}
}
}
return Result::success([
'total' => count($userIds),
'list' => $userIds,
'next_page_token' => isset($data['next_page_token']) ? $data['next_page_token'] : 0,
'has_more' => isset($data['has_more']) ? $data['has_more'] : false,
], $result['raw']);
}
// 超级大群特殊错误码,保持与接口约定一致
if ($result['error_code'] === 'SuperLargeGroup') {
return Result::fail('SuperLargeGroup', $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 获取客户端登录鉴权信息
* 实现 token = sha256(appId + appKey + userId + nonce + timestamp + role)
* @param string $userId 用户ID(需过滤,仅保留 A-Z a-z 0-9 -,最长 64 字节)
* @param string $role 角色(admin 或空字符串)
* @return Result data 含 app_id、app_sign、auth、app_token
*/
public function getLoginAuth($userId, $role = '')
{
$appId = $this->sdk->getAppId();
$appKey = $this->sdk->getAppKey();
// userId 过滤:仅保留 [A-Za-z0-9-],最长 64 字节
$filteredUserId = $this->filterUserId($userId);
if ($filteredUserId === '') {
return Result::fail('userId 无效,过滤后为空', null);
}
// nonce 生成:AK- + md5(uniqid(mt_rand, true))
$nonce = 'AK-' . md5(uniqid(mt_rand(), true));
// timestamp:当前时间 + 86400 秒
$timestamp = time() + 86400;
// role 仅允许 admin 或空字符串
$role = ($role === 'admin') ? 'admin' : '';
// 计算 token
$token = hash('sha256', $appId . $appKey . $filteredUserId . $nonce . $timestamp . $role);
$data = [
'app_id' => $appId,
'app_sign' => $this->sdk->getAppSign(),
'auth' => [
'nonce' => $nonce,
'timestamp' => $timestamp,
'role' => $role,
'user_id' => $filteredUserId,
],
'app_token' => $token,
];
return Result::success($data, null);
}
/**
* 创建群组
* @param string $groupId 群组ID
* @param string $groupName 群组名称
* @param string $groupMeta 群组扩展信息
* @return Result
*/
public function createGroup($groupId, $groupName = '', $groupMeta = '')
{
$result = $this->sdk->createGroup($groupId, $groupName, $groupMeta);
if ($result['success']) {
return Result::success($result['data'], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 删除群组
* @param string $groupId 群组ID
* @param string $operatorId 操作者ID(可选)
* @return Result
*/
public function deleteGroup($groupId, $operatorId = '')
{
$result = $this->sdk->deleteGroup($groupId, $operatorId);
if ($result['success']) {
return Result::success($result['data'], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 获取底层 SDK 实例(供扩展调用,如 listGroups
* @return LiveMessage
*/
public function getSdk()
{
return $this->sdk;
}
/**
* 过滤 userId,仅保留 [A-Za-z0-9-],最长 64 字节
* @param string $userId 原始用户ID
* @return string
*/
protected function filterUserId($userId)
{
$filtered = preg_replace('/[^A-Za-z0-9\-]/', '', (string)$userId);
// 截断到 64 字节
if (strlen($filtered) > 64) {
$filtered = substr($filtered, 0, 64);
}
return $filtered;
}
}