125 lines
4.2 KiB
PHP
125 lines
4.2 KiB
PHP
<?php
|
||
|
||
namespace App\Service\common\oss;
|
||
|
||
use App\BaseApp\BaseService;
|
||
use App\Models\oss\OssConfigModel;
|
||
use App\Service\common\FieldEncryptService;
|
||
use App\Service\SystemConfigService;
|
||
use Exception;
|
||
|
||
/**
|
||
* OSS 运行时配置:解析当前启用的存储配置并解密密钥,供上传工厂使用
|
||
*/
|
||
class OssRuntimeConfigService extends BaseService
|
||
{
|
||
public const CFG_ACTIVE_ID = 'oss_active_config_id';
|
||
|
||
public function __construct()
|
||
{
|
||
// 上传链路可能在无登录上下文触发,不强制鉴权
|
||
$this->isAuth = false;
|
||
parent::__construct();
|
||
}
|
||
|
||
/**
|
||
* 获取当前启用的明文配置
|
||
* 为什么要解密:上传客户端需要明文 access/secret;库内仅存 AES 密文
|
||
*
|
||
* @return array{
|
||
* id:int,driver:string,name:string,access_key:string,secret_key:string,
|
||
* endpoint:string,region:string,bucket:string,domain:string,
|
||
* path_prefix:string,extra_json:mixed
|
||
* }
|
||
*/
|
||
public function getActiveConfig(): array
|
||
{
|
||
$sys = SystemConfigService::getInstance();
|
||
$activeId = (int) $sys->getValue(self::CFG_ACTIVE_ID, '0');
|
||
$row = null;
|
||
if ($activeId > 0) {
|
||
$row = OssConfigModel::where('id', $activeId)
|
||
->where('deleted_at', 0)
|
||
->where('status', 1)
|
||
->first();
|
||
}
|
||
if (!$row) {
|
||
// 回落 is_active 标记,避免仅写了表未写 system_config 时上传失败
|
||
$row = OssConfigModel::where('is_active', 1)
|
||
->where('deleted_at', 0)
|
||
->where('status', 1)
|
||
->orderByDesc('id')
|
||
->first();
|
||
}
|
||
if (!$row) {
|
||
// 最终回落本地默认行或内存默认
|
||
$row = OssConfigModel::where('driver', 'local')
|
||
->where('deleted_at', 0)
|
||
->where('status', 1)
|
||
->orderByDesc('is_active')
|
||
->orderBy('id')
|
||
->first();
|
||
}
|
||
if (!$row) {
|
||
return [
|
||
'id' => 0,
|
||
'driver' => 'local',
|
||
'name' => '本地存储',
|
||
'access_key' => '',
|
||
'secret_key' => '',
|
||
'endpoint' => '',
|
||
'region' => '',
|
||
'bucket' => '',
|
||
'domain' => '',
|
||
'path_prefix' => 'uploads',
|
||
'extra_json' => null,
|
||
];
|
||
}
|
||
return $this->formatConfig($row);
|
||
}
|
||
|
||
/**
|
||
* 按 ID 获取明文配置
|
||
*
|
||
* 素材库要对指定 bucket 做列举与删除,不能只认「当前启用」那一份:
|
||
* 换过存储之后老素材仍然躺在旧配置的 bucket 里,回收时必须拿旧配置去删。
|
||
* 也因此这里不校验 status —— 配置被禁用不代表里面的对象不用管了。
|
||
*
|
||
* @throws Exception
|
||
*/
|
||
public function getConfigById(int $id): array
|
||
{
|
||
$row = OssConfigModel::where('id', $id)->where('deleted_at', 0)->first();
|
||
if (!$row) {
|
||
$this->utils->notFound('存储配置不存在');
|
||
}
|
||
return $this->formatConfig($row);
|
||
}
|
||
|
||
/**
|
||
* 库行转明文配置数组
|
||
*/
|
||
private function formatConfig(OssConfigModel $row): array
|
||
{
|
||
$enc = FieldEncryptService::getInstance();
|
||
$extra = $row->extra_json;
|
||
if (is_string($extra) && $extra !== '') {
|
||
$decoded = json_decode($extra, true);
|
||
$extra = is_array($decoded) ? $decoded : $extra;
|
||
}
|
||
return [
|
||
'id' => (int) $row->id,
|
||
'driver' => (string) $row->driver,
|
||
'name' => (string) $row->name,
|
||
'access_key' => $enc->decryptFromStorage((string) ($row->access_key ?? ''), true),
|
||
'secret_key' => $enc->decryptFromStorage((string) ($row->secret_key ?? ''), true),
|
||
'endpoint' => (string) ($row->endpoint ?? ''),
|
||
'region' => (string) ($row->region ?? ''),
|
||
'bucket' => (string) ($row->bucket ?? ''),
|
||
'domain' => (string) ($row->domain ?? ''),
|
||
'path_prefix' => (string) ($row->path_prefix ?? ''),
|
||
'extra_json' => $extra,
|
||
];
|
||
}
|
||
}
|