HaniBlindBox/server/php/app/common/server/TencentCosUploader.php
2026-01-01 20:46:07 +08:00

172 lines
5.7 KiB
PHP
Raw 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\server;
use Qcloud\Cos\Client;
use Qcloud\Cos\Exception\ServiceResponseException;
use think\facade\Log;
/**
* 腾讯云COS文件上传工具类
*
* 功能说明:
* 1. 支持通过文件路径上传
* 2. 支持直接上传二进制内容
* 3. 自动生成唯一存储路径
* 4. 提供完整的文件访问URL
*/
class TencentCosUploader
{
/** @var Client 腾讯云COS客户端实例 */
private $cosClient;
/** @var string 存储桶名称 */
private $bucket;
/** @var string 存储桶所在地域 */
private $region;
/** @var string 自定义访问域名 */
private $domain;
/**
* 构造函数
*
* @param array $config 配置数组,需包含:
* [
* 'AccessKeyId' => '您的SecretId',
* 'AccessKeySecret' => '您的SecretKey',
* 'Bucket' => '存储桶名称',
* 'Region' => '存储桶地域',
* 'Domain' => '自定义域名'
* ]
*/
public function __construct(array $config)
{
// 初始化基础配置
$this->bucket = $config['Bucket'];
$this->region = $config['Region'];
$this->domain = $config['Domain'];
// 创建COS客户端实例
$this->cosClient = new Client([
'region' => $this->region, // 地域
'schema' => 'https', // 使用HTTPS协议
'credentials' => [ // 鉴权凭证
'secretId' => $config['AccessKeyId'],
'secretKey' => $config['AccessKeySecret'],
],
]);
}
/**
* 通过文件路径上传到COS适合表单上传场景
*
* @param string $tempPath 本地临时文件路径(如:/tmp/upload_xxxx.jpg
* @param string $fileType 文件扩展名jpg
* @param string $prefix 存储路径前缀默认topic
*
* @return array [
* 'cos_key' => 'COS存储路径',
* 'full_url' => '完整访问URL',
* 'location' => 'COS返回的Location'
* ]
*
* @throws \Exception 上传失败时抛出异常
*/
public function uploadFilePath(string $tempPath, string $fileType, string $prefix = 'topic'): array
{
try {
// 生成唯一存储路径(自动包含日期目录)
$cosKey = $this->generateUniqueKey($fileType, $prefix);
// 执行文件上传
$result = $this->cosClient->putObject([
'Bucket' => $this->bucket, // 存储桶
'Key' => $cosKey, // COS存储路径
'Body' => fopen($tempPath, 'rb'), // 以二进制只读方式打开文件
]);
return [
'cos_key' => $cosKey,
'full_url' => $this->domain . $cosKey, // 拼接完整访问地址
'location' => $result['Location'] // COS返回的访问地址
];
} catch (ServiceResponseException $e) {
// 记录详细错误日志
Log::error("COS文件上传失败 | {$e->getStatusCode()} | {$e->getErrorCode()} | {$e->getMessage()}");
throw new \Exception('文件上传失败: ' . $e->getMessage());
}
}
/**
* 直接上传二进制内容到COS适合Base64或内存文件场景
*
* @param mixed $content 二进制内容(支持字符串或资源类型)
* @param string $filePath 指定在COS中的存储路径images/20230101/abc.jpg
*
* @return array [
* 'cos_key' => 'COS存储路径',
* 'full_url' => '完整访问URL',
* 'location' => 'COS返回的Location'
* ]
*
* @throws \Exception 上传失败时抛出异常
*/
public function uploadFile($content, string $filePath): array
{
try {
// 执行二进制内容上传
$result = $this->cosClient->putObject([
'Bucket' => $this->bucket, // 存储桶
'Key' => $filePath, // 指定存储路径
'Body' => $content, // 直接传入二进制内容
]);
return [
'cos_key' => $filePath,
'full_url' => $this->domain . $filePath, // 拼接完整访问地址
'location' => $result['Location'] // COS返回的访问地址
];
} catch (ServiceResponseException $e) {
// 记录详细错误日志
Log::error("COS二进制上传失败 | {$e->getStatusCode()} | {$e->getErrorCode()} | {$e->getMessage()}");
throw new \Exception('二进制上传失败: ' . $e->getMessage());
}
}
/**
* 生成唯一存储路径(私有方法)
*
* 格式:{prefix}/YYYYMMDD/{32位随机字符串}.{ext}
* 示例topic/20230101/7a97e8f7d6e5f4c3b2a1987654321abc.jpg
*
* @param string $fileType 文件扩展名
* @param string $prefix 路径前缀
*
* @return string COS存储路径
*/
private function generateUniqueKey(string $fileType, string $prefix): string
{
$dateSegment = date('Ymd'); // 日期目录
$uniqueName = md5(uniqid(rand(), true)) . '.' . $fileType; // 唯一文件名
return sprintf(
'%s/%s/%s',
trim($prefix, '/'), // 去除前后斜线
$dateSegment,
$uniqueName
);
}
/**
* 获取完整访问URL
*
* @param string $cosKey COS存储路径
* @return string 完整的HTTP访问地址
*/
public function getFullUrl(string $cosKey): string
{
// 示例https://cdn.example.com/topic/20230101/abc.jpg
return $this->domain . $cosKey;
}
}