172 lines
5.7 KiB
PHP
172 lines
5.7 KiB
PHP
<?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;
|
||
}
|
||
} |