Files
lgp-admin-plus-api/app/Service/common/upload/LocalhostStorageService.php
LQ bcf54c2727 初始化
缺陷:主题配色需要优化整体的同风格
2026-08-14 23:21:21 +08:00

128 lines
3.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Service\common\upload;
use App\BaseApp\BaseNotAuthService;
use App\Service\common\oss\OssStorageInterface;
use Illuminate\Support\Facades\Storage;
/**
* 本地磁盘上传;支持 domain / path_prefix 覆盖
*/
class LocalhostStorageService extends BaseNotAuthService implements OssStorageInterface
{
use ObjectKeyNormalizeTrait;
protected array $config = [
'domain' => '',
'path_prefix' => '',
];
/**
* 注入运行时配置(链式)
*/
public function withConfig(array $config): static
{
$this->config = array_merge($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);
}
public function deleteImage($key): bool
{
return $this->deleteFile($key);
}
public function deleteVideo($key): bool
{
return $this->deleteFile($key);
}
/**
* 扫本地磁盘目录
*
* 本地盘没有 marker 这种服务端游标,用「已列举条数」当偏移量模拟:
* 先把文件名排序固定顺序,再按偏移切页,这样反复调用能稳定推进。
* 代价是同步期间新增文件会让偏移错位,但素材同步是幂等的,下一轮就自愈。
*/
public function listObjects(string $prefix = '', string $marker = '', int $limit = 100): array
{
$listPrefix = rtrim($this->scopedListPrefix($prefix), '/');
$offset = max(0, (int) $marker);
$files = Storage::allFiles($listPrefix);
sort($files);
$page = array_slice($files, $offset, $this->boundedLimit($limit));
$items = [];
foreach ($page as $file) {
$key = $this->normalizeObjectKey($file);
if ($key === '') {
continue;
}
$realPath = Storage::path($file);
$items[] = [
'key' => $key,
'size' => (int) Storage::size($file),
// 本地盘没有服务端 ETag用 md5 顶上,素材库靠它判重与校验
'hash' => is_file($realPath) ? (string) md5_file($realPath) : '',
'last_modified' => (int) Storage::lastModified($file),
'url' => $this->publicUrlOf($key, asset('/storage/' . $key)),
];
}
$next = $offset + count($page);
$finished = $next >= count($files);
return [
'items' => $items,
'next_marker' => $finished ? '' : (string) $next,
'finished' => $finished,
];
}
public function deleteObject(string $key): bool
{
$key = $this->normalizeObjectKey($key);
if ($key === '') {
return false;
}
return $this->deleteFile($key);
}
/**
* 写入本地 storage兼容 UploadedFile 与路径字符串
*/
private function uploadFile(mixed $filePath, string $key): bool|array
{
$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;
if (!Storage::put($key, file_get_contents($path))) {
return false;
}
$domain = rtrim((string) ($this->config['domain'] ?? ''), '/');
$url = $domain !== '' ? ($domain . '/' . $key) : asset('/storage/' . $key);
return [
'key' => $key,
'url' => $url,
];
}
private function deleteFile(string $key): bool
{
return Storage::delete($key);
}
}