181 lines
5.8 KiB
PHP
181 lines
5.8 KiB
PHP
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Author: ywxapp<admin@ywxapp.cn>
|
|
// +----------------------------------------------------------------------
|
|
namespace ywxapp\service;
|
|
|
|
use think\Exception;
|
|
use think\facade\Config;
|
|
use think\file\UploadedFile;
|
|
use ywxapp\utils\storage\StorageInterface;
|
|
|
|
/**
|
|
* FileStorageService 类
|
|
*
|
|
* @author ywxapp <admin@ywxapp.cn>
|
|
*/
|
|
class FileStorageService
|
|
{
|
|
// 驱动常量
|
|
const DRIVER_LOCAL = 'local';
|
|
const DRIVER_ALIOSS = 'alioss';
|
|
const DRIVER_QCOS = 'qcos';
|
|
|
|
protected $config;
|
|
protected $storage;
|
|
|
|
/**
|
|
* 构造函数,读取配置并初始化驱动
|
|
*/
|
|
public function __construct()
|
|
{
|
|
// 读取配置文件
|
|
$this->config = Config::get('filesystem', []);
|
|
// 获取当前配置的驱动名称
|
|
$driverName = $this->config['default'] ?? self::DRIVER_LOCAL;
|
|
// 实例化对应的驱动
|
|
$this->initDriver($driverName);
|
|
}
|
|
|
|
/**
|
|
* 初始化存储驱动
|
|
*/
|
|
protected function initDriver(string $driverName): void
|
|
{
|
|
$drivers = $this->config['disks'] ?? [];
|
|
if (! isset($drivers[$driverName])) {
|
|
throw new Exception("存储驱动配置不存在: {$driverName}");
|
|
}
|
|
$config = $drivers[$driverName];
|
|
$class = $config['class'];
|
|
if (! class_exists($class)) {
|
|
throw new Exception("存储驱动类不存在: {$class}");
|
|
}
|
|
$this->storage = new $class($config);
|
|
if (! $this->storage instanceof StorageInterface) {
|
|
throw new Exception("存储驱动必须实现 StorageInterface 接口");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 上传文件(对外调用的方法)
|
|
*/
|
|
public function upload(UploadedFile $file, string $path = '', array $options = []): array
|
|
{
|
|
|
|
// 1. 基础验证(例如文件大小、类型)
|
|
$this->validateFile($file, $options);
|
|
// 2. 如果未指定路径,生成默认路径
|
|
if (empty($path)) {
|
|
$path = $this->generatePath($file);
|
|
}
|
|
// throw new \think\Exception(json_encode( [
|
|
// $file->getoriginalName(), //获取文件原始名称带后缀
|
|
// $file->getSize(), //获取文件大小
|
|
// $file->extension(), //获取文件后缀
|
|
// ])
|
|
// , 403);
|
|
// 3. 调用具体驱动的上传方法
|
|
|
|
$data = [
|
|
'module' => $options['module'] ?? 'index', // 模块标识
|
|
'original' => $file->getoriginalName(),
|
|
'size' => $file->getSize(),
|
|
'ext' => $file->extension(),
|
|
'mime' => $file->getOriginalMime(),
|
|
'mime' => $file->getMime(),
|
|
'storage' => $this->config['default'] ?? self::DRIVER_LOCAL,
|
|
'is_image' => (int) str_starts_with($file->getMime(), 'image/'),
|
|
'upload_ip' => request()->ip(),
|
|
];
|
|
|
|
// 如果是图片且能获取到尺寸
|
|
if ($data['is_image'] && function_exists('getimagesize')) {
|
|
// 注意:如果是云存储,这里可能需要从临时文件获取尺寸
|
|
$tempPath = $file->getRealPath();
|
|
if (file_exists($tempPath)) {
|
|
$imgInfo = getimagesize($tempPath);
|
|
$data['width'] = $imgInfo[0] ?? 0;
|
|
$data['height'] = $imgInfo[1] ?? 0;
|
|
}
|
|
}
|
|
|
|
list($name, $path, $url) = $this->storage->upload($file, $path, $options);
|
|
$data['name'] = $name;
|
|
$data['path'] = $path;
|
|
$data['url'] = $url;
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* 删除文件
|
|
*/
|
|
public function delete(string $path): bool
|
|
{
|
|
return $this->storage->delete($path);
|
|
}
|
|
|
|
/**
|
|
* 获取URL
|
|
*/
|
|
public function getUrl(string $path): string
|
|
{
|
|
return $this->storage->getUrl($path);
|
|
}
|
|
|
|
/**
|
|
* 基础文件验证
|
|
*/
|
|
protected function validateFile(UploadedFile $file, array $options): void
|
|
{
|
|
|
|
// 使用验证器验证上传的文件
|
|
validate(
|
|
[
|
|
'file' => [
|
|
// 限制文件大小(单位b),这里限制为4M
|
|
'fileSize' => 4 * 1024 * 1024,
|
|
// 限制文件后缀,多个后缀以英文逗号分割
|
|
'fileExt' => 'gif,jpg,png',
|
|
// fileSize 上传文件的最大字节;
|
|
// fileExt 文件后缀,多个用逗号分割或者数组;
|
|
// fileMime 文件MIME类型,多个用逗号分割或者数组;
|
|
// image 验证图像文件的尺寸和类型,
|
|
],
|
|
],
|
|
[
|
|
'file.fileSize' => '文件太大',
|
|
'file.fileExt' => '不支持的文件后缀',
|
|
]
|
|
)->check(['file' => $file]);
|
|
|
|
}
|
|
|
|
/**
|
|
* 生成唯一文件路径
|
|
*/
|
|
protected function generatePath(UploadedFile $file): string
|
|
{
|
|
$ext = $file->getClientOriginalExtension();
|
|
$date = date('Y/m/d');
|
|
$filename = date('His') . '_' . uniqid() . ".{$ext}";
|
|
return "{$date}/{$filename}";
|
|
}
|
|
|
|
/**
|
|
* 魔术方法,允许直接调用驱动的其他特有方法
|
|
*/
|
|
public function __call($method, $parameters)
|
|
{
|
|
if (method_exists($this->storage, $method)) {
|
|
return call_user_func_array([$this->storage, $method], $parameters);
|
|
}
|
|
throw new \BadMethodCallException("Method {$method} does not exist.");
|
|
}
|
|
}
|