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'] ]; } }