Files
nl-admin-api/app/Service/common/upload/QcloudStorageService.php

82 lines
3.1 KiB
PHP
Raw Normal View History

2026-08-10 18:32:06 +08:00
<?php
namespace App\Service\common\upload;
use App\BaseApp\BaseNotAuthService;
use App\Service\common\oss\OssStorageInterface;
use App\Service\common\UtilsService;
use Illuminate\Support\Facades\Http;
/**
* 腾讯云 COS简易 PUTAuthorization 签名 v5
*/
class QcloudStorageService extends BaseNotAuthService implements OssStorageInterface
{
protected array $config = [];
public function withConfig(array $config): static
{
$this->config = $config;
return $this;
}
public function uploadImage($filePath, string $key): bool|array
{
return $this->uploadFile($filePath, $key);
}
public function uploadVideo($filePath, string $key): bool|array
{
return $this->uploadFile($filePath, $key);
}
/**
* COS 对象上传Sign Algorithm=sha1
*/
private function uploadFile($filePath, string $key): bool|array
{
$secretId = (string) ($this->config['access_key'] ?? '');
$secretKey = (string) ($this->config['secret_key'] ?? '');
$bucket = (string) ($this->config['bucket'] ?? '');
$region = (string) ($this->config['region'] ?? '');
$domain = rtrim((string) ($this->config['domain'] ?? ''), '/');
if ($secretId === '' || $secretKey === '' || $bucket === '' || $region === '') {
UtilsService::getInstance()->errorThrow('腾讯云 COS 配置不完整(需要 SecretId/SecretKey/Bucket/Region');
}
$prefix = trim((string) ($this->config['path_prefix'] ?? ''), '/');
if ($prefix !== '' && !str_starts_with($key, $prefix . '/')) {
$key = $prefix . '/' . ltrim($key, '/');
}
$path = is_object($filePath) && method_exists($filePath, 'getRealPath')
? $filePath->getRealPath()
: (string) $filePath;
$content = file_get_contents($path);
$host = $bucket . '.cos.' . $region . '.myqcloud.com';
$urlPath = '/' . ltrim($key, '/');
$now = time();
$keyTime = $now . ';' . ($now + 600);
$signKey = hash_hmac('sha1', $keyTime, $secretKey);
$httpString = strtolower('put') . "\n" . $urlPath . "\n\nhost=" . strtolower($host) . "\n";
$stringToSign = "sha1\n{$keyTime}\n" . sha1($httpString) . "\n";
$signature = hash_hmac('sha1', $stringToSign, $signKey);
$authorization = 'q-sign-algorithm=sha1'
. '&q-ak=' . $secretId
. '&q-sign-time=' . $keyTime
. '&q-key-time=' . $keyTime
. '&q-header-list=host'
. '&q-url-param-list='
. '&q-signature=' . $signature;
$url = 'https://' . $host . $urlPath;
$response = Http::withHeaders([
'Host' => $host,
'Authorization' => $authorization,
'Content-Type' => 'application/octet-stream',
])->withBody($content, 'application/octet-stream')->put($url);
if (!$response->successful()) {
UtilsService::getInstance()->errorThrow('腾讯云上传失败:' . $response->body());
}
$publicUrl = $domain !== '' ? ($domain . $urlPath) : $url;
return ['key' => $key, 'url' => $publicUrl];
}
}