You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
237 lines
8.2 KiB
237 lines
8.2 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | Niucloud-admin 企业快速开发的多应用管理平台
|
|
// +----------------------------------------------------------------------
|
|
// | 官方网址:https://www.niucloud.com
|
|
// +----------------------------------------------------------------------
|
|
// | niucloud团队 版权所有 开源版本可自由商用
|
|
// +----------------------------------------------------------------------
|
|
// | Author: Niucloud Team
|
|
// +----------------------------------------------------------------------
|
|
|
|
namespace app\service\admin\upload;
|
|
|
|
use app\service\core\sys\CoreConfigService;
|
|
use core\base\BaseAdminService;
|
|
use core\exception\AdminException;
|
|
|
|
/**
|
|
* 对象存储直传服务类
|
|
*/
|
|
class DirectUploadService extends BaseAdminService
|
|
{
|
|
/**
|
|
* 获取上传凭证
|
|
* @param string $file_type 文件类型
|
|
* @param string $file_name 文件名
|
|
* @return array
|
|
*/
|
|
public function getUploadCredentials($file_type = 'image', $file_name = '')
|
|
{
|
|
// 获取存储配置
|
|
$config_data = (new CoreConfigService())->getConfig('STORAGE');
|
|
if (empty($config_data) || empty($config_data['value'])) {
|
|
throw new AdminException('存储配置未设置');
|
|
}
|
|
|
|
$storage_config = $config_data['value'];
|
|
if (is_string($storage_config)) {
|
|
$storage_config = json_decode($storage_config, true);
|
|
}
|
|
|
|
if (empty($storage_config)) {
|
|
throw new AdminException('存储配置格式错误');
|
|
}
|
|
|
|
$default_storage = $storage_config['default'] ?? 'local';
|
|
if ($default_storage == 'local') {
|
|
throw new AdminException('本地存储不支持直传');
|
|
}
|
|
|
|
if (!isset($storage_config[$default_storage])) {
|
|
throw new AdminException('存储配置错误');
|
|
}
|
|
|
|
$config = $storage_config[$default_storage];
|
|
|
|
// 生成文件路径
|
|
$file_path = $this->generateFilePath($file_type, $file_name);
|
|
|
|
// 根据不同存储类型获取凭证
|
|
switch ($default_storage) {
|
|
case 'tencent':
|
|
return $this->getTencentCredentials($config, $file_path, $file_type);
|
|
case 'aliyun':
|
|
return $this->getAliyunCredentials($config, $file_path, $file_type);
|
|
default:
|
|
throw new AdminException('不支持的存储类型');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取腾讯云COS直传凭证
|
|
* @param array $config 配置信息
|
|
* @param string $file_path 文件路径
|
|
* @param string $file_type 文件类型
|
|
* @return array
|
|
*/
|
|
private function getTencentCredentials($config, $file_path, $file_type)
|
|
{
|
|
// 检查必要的配置
|
|
$required_keys = ['bucket', 'region', 'access_key', 'secret_key'];
|
|
foreach ($required_keys as $key) {
|
|
if (empty($config[$key])) {
|
|
throw new AdminException("腾讯云配置缺少必要参数: {$key}");
|
|
}
|
|
}
|
|
|
|
// 生成策略
|
|
$expired = time() + 3600; // 1小时过期
|
|
$policy = [
|
|
'expiration' => gmdate('Y-m-d\TH:i:s.000\Z', $expired),
|
|
'conditions' => [
|
|
['bucket' => $config['bucket']],
|
|
['starts-with' => '$key', $file_path]
|
|
]
|
|
];
|
|
|
|
// 根据文件类型设置大小限制
|
|
$max_size = $this->getMaxFileSize($file_type);
|
|
if ($max_size > 0) {
|
|
$policy['conditions'][] = ['content-length-range', 0, $max_size];
|
|
}
|
|
|
|
$policy_encoded = base64_encode(json_encode($policy));
|
|
$signature = hash_hmac('sha1', $policy_encoded, $config['secret_key'], true);
|
|
$signature_encoded = base64_encode($signature);
|
|
|
|
return [
|
|
'storage_type' => 'tencent',
|
|
'upload_url' => "https://{$config['bucket']}.cos.{$config['region']}.myqcloud.com",
|
|
'credentials' => [
|
|
'policy' => $policy_encoded,
|
|
'q-sign-algorithm' => 'sha1',
|
|
'q-ak' => $config['access_key'],
|
|
'q-key-time' => time() . ';' . $expired,
|
|
'q-signature' => $signature_encoded,
|
|
],
|
|
'file_path' => $file_path,
|
|
'domain' => $config['domain'] ?? "https://{$config['bucket']}.cos.{$config['region']}.myqcloud.com",
|
|
'max_size' => $max_size,
|
|
'expired' => $expired
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取阿里云OSS直传凭证
|
|
* @param array $config 配置信息
|
|
* @param string $file_path 文件路径
|
|
* @param string $file_type 文件类型
|
|
* @return array
|
|
*/
|
|
private function getAliyunCredentials($config, $file_path, $file_type)
|
|
{
|
|
// 检查必要的配置
|
|
$required_keys = ['bucket', 'endpoint', 'access_key', 'secret_key'];
|
|
foreach ($required_keys as $key) {
|
|
if (empty($config[$key])) {
|
|
throw new AdminException("阿里云配置缺少必要参数: {$key}");
|
|
}
|
|
}
|
|
|
|
$expired = time() + 3600; // 1小时过期
|
|
$dir = dirname($file_path) . '/';
|
|
|
|
// 生成策略
|
|
$policy = [
|
|
'expiration' => gmdate('Y-m-d\TH:i:s.000\Z', $expired),
|
|
'conditions' => [
|
|
['starts-with' => '$key', $dir],
|
|
]
|
|
];
|
|
|
|
// 根据文件类型设置大小限制
|
|
$max_size = $this->getMaxFileSize($file_type);
|
|
if ($max_size > 0) {
|
|
$policy['conditions'][] = ['content-length-range', 0, $max_size];
|
|
}
|
|
|
|
$policy_encoded = base64_encode(json_encode($policy));
|
|
$signature = base64_encode(hash_hmac('sha1', $policy_encoded, $config['secret_key'], true));
|
|
|
|
return [
|
|
'storage_type' => 'aliyun',
|
|
'upload_url' => "https://{$config['bucket']}.{$config['endpoint']}",
|
|
'credentials' => [
|
|
'OSSAccessKeyId' => $config['access_key'],
|
|
'policy' => $policy_encoded,
|
|
'signature' => $signature,
|
|
'key' => $file_path,
|
|
'success_action_status' => '200',
|
|
],
|
|
'file_path' => $file_path,
|
|
'domain' => $config['domain'] ?? "https://{$config['bucket']}.{$config['endpoint']}",
|
|
'max_size' => $max_size,
|
|
'expired' => $expired
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 生成文件路径
|
|
* @param string $file_type 文件类型
|
|
* @param string $file_name 文件名
|
|
* @return string
|
|
*/
|
|
private function generateFilePath($file_type, $file_name = '')
|
|
{
|
|
$type_dir_map = [
|
|
'image' => 'upload/attachment/image',
|
|
'video' => 'upload/attachment/video',
|
|
'document' => 'upload/attachment/document'
|
|
];
|
|
|
|
$dir = $type_dir_map[$file_type] ?? 'upload/attachment/file';
|
|
$date_dir = date('Y/m/d');
|
|
|
|
if (empty($file_name)) {
|
|
$file_name = uniqid() . '_${filename}'; // ${filename} 将被前端替换
|
|
}
|
|
|
|
return $dir . '/' . $date_dir . '/' . $file_name;
|
|
}
|
|
|
|
/**
|
|
* 根据文件类型获取最大文件大小
|
|
* @param string $file_type 文件类型
|
|
* @return int 字节数,0表示不限制
|
|
*/
|
|
private function getMaxFileSize($file_type)
|
|
{
|
|
$size_map = [
|
|
'image' => 10 * 1024 * 1024, // 10MB
|
|
'video' => 500 * 1024 * 1024, // 500MB
|
|
'document' => 50 * 1024 * 1024, // 50MB
|
|
];
|
|
|
|
return $size_map[$file_type] ?? 10 * 1024 * 1024;
|
|
}
|
|
|
|
/**
|
|
* 确认上传完成
|
|
* @param array $data 文件信息
|
|
* @return array
|
|
*/
|
|
public function confirmUpload($data)
|
|
{
|
|
// 这里可以将文件信息保存到附件表,供后续管理使用
|
|
// 暂时直接返回文件URL,实际项目中可以根据需要保存到数据库
|
|
|
|
return [
|
|
'url' => $data['file_url'],
|
|
'name' => $data['file_name'],
|
|
'size' => $data['file_size'],
|
|
'type' => $data['file_type'],
|
|
'storage_type' => $data['storage_type']
|
|
];
|
|
}
|
|
}
|