项目初始化
This commit is contained in:
260
app/common/library/Upload.php
Normal file
260
app/common/library/Upload.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\library;
|
||||
|
||||
use ba\Random;
|
||||
use ba\Filesystem;
|
||||
use app\common\model\Attachment;
|
||||
use app\common\library\upload\Driver;
|
||||
use app\common\library\upload\WebmanUploadedFile;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* 上传(Webman 迁移版,使用 WebmanUploadedFile)
|
||||
*/
|
||||
class Upload
|
||||
{
|
||||
protected array $config = [];
|
||||
protected ?WebmanUploadedFile $file = null;
|
||||
protected bool $isImage = false;
|
||||
protected array $fileInfo = [];
|
||||
protected array $driver = [
|
||||
'name' => 'local',
|
||||
'handler' => [],
|
||||
'namespace' => '\\app\\common\\library\\upload\\driver\\',
|
||||
];
|
||||
protected string $topic = 'default';
|
||||
|
||||
public function __construct(?WebmanUploadedFile $file = null, array $config = [])
|
||||
{
|
||||
$upload = config('upload', []);
|
||||
$this->config = array_merge($upload, $config);
|
||||
|
||||
if ($file) {
|
||||
$this->setFile($file);
|
||||
}
|
||||
}
|
||||
|
||||
public function setFile(?WebmanUploadedFile $file): self
|
||||
{
|
||||
if (empty($file)) {
|
||||
throw new RuntimeException(__('No files were uploaded'));
|
||||
}
|
||||
|
||||
$suffix = strtolower($file->extension());
|
||||
$suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
|
||||
$this->fileInfo = [
|
||||
'suffix' => $suffix,
|
||||
'type' => $file->getMime(),
|
||||
'size' => $file->getSize(),
|
||||
'name' => $file->getOriginalName(),
|
||||
'sha1' => $file->sha1(),
|
||||
];
|
||||
$this->file = $file;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDriver(string $driver): self
|
||||
{
|
||||
$this->driver['name'] = $driver;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDriver(?string $driver = null, bool $noDriveException = true): Driver|false
|
||||
{
|
||||
$driver = $driver ?? $this->driver['name'];
|
||||
if (!isset($this->driver['handler'][$driver])) {
|
||||
$class = $this->resolveDriverClass($driver);
|
||||
if ($class) {
|
||||
$this->driver['handler'][$driver] = new $class();
|
||||
} elseif ($noDriveException) {
|
||||
throw new InvalidArgumentException(__('Driver %s not supported', [$driver]));
|
||||
}
|
||||
}
|
||||
return $this->driver['handler'][$driver] ?? false;
|
||||
}
|
||||
|
||||
protected function resolveDriverClass(string $driver): string|false
|
||||
{
|
||||
if ($this->driver['namespace'] || str_contains($driver, '\\')) {
|
||||
$class = str_contains($driver, '\\') ? $driver : $this->driver['namespace'] . $this->studly($driver);
|
||||
if (class_exists($class)) {
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function studly(string $value): string
|
||||
{
|
||||
$value = ucwords(str_replace(['-', '_'], ' ', $value));
|
||||
return str_replace(' ', '', $value);
|
||||
}
|
||||
|
||||
public function setTopic(string $topic): self
|
||||
{
|
||||
$this->topic = $topic;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function checkIsImage(): bool
|
||||
{
|
||||
if (in_array($this->fileInfo['type'], ['image/gif', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/png', 'image/webp'])
|
||||
|| in_array($this->fileInfo['suffix'], ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'webp'])) {
|
||||
$path = $this->file->getPathname();
|
||||
$imgInfo = is_file($path) ? getimagesize($path) : false;
|
||||
if (!$imgInfo || !isset($imgInfo[0]) || !isset($imgInfo[1])) {
|
||||
throw new RuntimeException(__('The uploaded image file is not a valid image'));
|
||||
}
|
||||
$this->fileInfo['width'] = $imgInfo[0];
|
||||
$this->fileInfo['height'] = $imgInfo[1];
|
||||
$this->isImage = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isImage(): bool
|
||||
{
|
||||
return $this->isImage;
|
||||
}
|
||||
|
||||
public function getSuffix(): string
|
||||
{
|
||||
return $this->fileInfo['suffix'] ?? 'file';
|
||||
}
|
||||
|
||||
public function getSaveName(?string $saveName = null, ?string $filename = null, ?string $sha1 = null): string
|
||||
{
|
||||
if ($filename) {
|
||||
$suffix = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
$suffix = $suffix && preg_match("/^[a-zA-Z0-9]+$/", $suffix) ? $suffix : 'file';
|
||||
} else {
|
||||
$suffix = $this->fileInfo['suffix'];
|
||||
}
|
||||
$filename = $filename ?? $this->fileInfo['name'];
|
||||
$sha1 = $sha1 ?? $this->fileInfo['sha1'];
|
||||
$replaceArr = [
|
||||
'{topic}' => $this->topic,
|
||||
'{year}' => date('Y'),
|
||||
'{mon}' => date('m'),
|
||||
'{day}' => date('d'),
|
||||
'{hour}' => date('H'),
|
||||
'{min}' => date('i'),
|
||||
'{sec}' => date('s'),
|
||||
'{random}' => Random::build(),
|
||||
'{random32}' => Random::build('alnum', 32),
|
||||
'{fileName}' => $this->getFileNameSubstr($filename, $suffix),
|
||||
'{suffix}' => $suffix,
|
||||
'{.suffix}' => $suffix ? '.' . $suffix : '',
|
||||
'{fileSha1}' => $sha1,
|
||||
];
|
||||
$saveName = $saveName ?? $this->config['save_name'];
|
||||
return Filesystem::fsFit(str_replace(array_keys($replaceArr), array_values($replaceArr), $saveName));
|
||||
}
|
||||
|
||||
public function validates(): void
|
||||
{
|
||||
if (empty($this->file)) {
|
||||
throw new RuntimeException(__('No files have been uploaded or the file size exceeds the upload limit of the server'));
|
||||
}
|
||||
|
||||
$size = Filesystem::fileUnitToByte($this->config['max_size'] ?? '10M');
|
||||
$mime = $this->checkConfig($this->config['allowed_mime_types'] ?? []);
|
||||
$suffix = $this->checkConfig($this->config['allowed_suffixes'] ?? '');
|
||||
|
||||
if ($this->fileInfo['size'] > $size) {
|
||||
throw new RuntimeException(__('The uploaded file is too large (%sMiB), Maximum file size:%sMiB', [
|
||||
round($this->fileInfo['size'] / pow(1024, 2), 2),
|
||||
round($size / pow(1024, 2), 2)
|
||||
]));
|
||||
}
|
||||
|
||||
if ($suffix && !in_array(strtolower($this->fileInfo['suffix']), $suffix)) {
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
|
||||
if ($mime && !in_array(strtolower($this->fileInfo['type']), $mime)) {
|
||||
throw new RuntimeException(__('The uploaded file format is not allowed'));
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $this->topic)) {
|
||||
throw new RuntimeException(__('Topic format error'));
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $this->driver['name'])) {
|
||||
throw new RuntimeException(__('Driver %s not supported', [$this->driver['name']]));
|
||||
}
|
||||
|
||||
if ($this->checkIsImage()) {
|
||||
$maxW = $this->config['image_max_width'] ?? 0;
|
||||
$maxH = $this->config['image_max_height'] ?? 0;
|
||||
if ($maxW && $this->fileInfo['width'] > $maxW) {
|
||||
throw new RuntimeException(__('The uploaded image file is not a valid image'));
|
||||
}
|
||||
if ($maxH && $this->fileInfo['height'] > $maxH) {
|
||||
throw new RuntimeException(__('The uploaded image file is not a valid image'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function upload(?string $saveName = null, int $adminId = 0, int $userId = 0): array
|
||||
{
|
||||
$this->validates();
|
||||
|
||||
$driver = $this->getDriver();
|
||||
if (!$driver) {
|
||||
throw new RuntimeException(__('Driver %s not supported', [$this->driver['name']]));
|
||||
}
|
||||
|
||||
$saveName = $saveName ?: $this->getSaveName();
|
||||
$params = [
|
||||
'topic' => $this->topic,
|
||||
'admin_id' => $adminId,
|
||||
'user_id' => $userId,
|
||||
'url' => $driver->url($saveName, false),
|
||||
'width' => $this->fileInfo['width'] ?? 0,
|
||||
'height' => $this->fileInfo['height'] ?? 0,
|
||||
'name' => $this->getFileNameSubstr($this->fileInfo['name'], $this->fileInfo['suffix'], 100) . '.' . $this->fileInfo['suffix'],
|
||||
'size' => $this->fileInfo['size'],
|
||||
'mimetype' => $this->fileInfo['type'],
|
||||
'storage' => $this->driver['name'],
|
||||
'sha1' => $this->fileInfo['sha1'],
|
||||
];
|
||||
|
||||
$attachment = Attachment::where('sha1', $params['sha1'])
|
||||
->where('topic', $params['topic'])
|
||||
->where('storage', $params['storage'])
|
||||
->find();
|
||||
|
||||
if ($attachment && $driver->exists($attachment->url)) {
|
||||
$attachment->quote++;
|
||||
$attachment->last_upload_time = time();
|
||||
} else {
|
||||
$driver->save($this->file, $saveName);
|
||||
$attachment = new Attachment();
|
||||
$attachment->data(array_filter($params));
|
||||
}
|
||||
$attachment->save();
|
||||
return $attachment->toArray();
|
||||
}
|
||||
|
||||
public function getFileNameSubstr(string $fileName, string $suffix, int $length = 15): string
|
||||
{
|
||||
$pattern = "/[\s:@#?&\/=',+]+/u";
|
||||
$fileName = str_replace(".$suffix", '', $fileName);
|
||||
$fileName = preg_replace($pattern, '', $fileName);
|
||||
return mb_substr(htmlspecialchars(strip_tags($fileName)), 0, $length);
|
||||
}
|
||||
|
||||
protected function checkConfig(mixed $configItem): array
|
||||
{
|
||||
if (is_array($configItem)) {
|
||||
return array_map('strtolower', $configItem);
|
||||
}
|
||||
return $configItem ? explode(',', strtolower((string)$configItem)) : [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user