refactor: 七牛云上传
This commit is contained in:
@@ -47,6 +47,13 @@ REFRESH_TOKEN_LIFETIME = 1209600; # 刷新令牌有效期
|
|||||||
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
RESOURCE_IMAGES_DOMAIN = http://local.orico.com; # 图片资源服务器地址
|
||||||
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
RESOURCE_VIDEOS_DOMAIN = http://local.orico.com; # 视频资源服务器地址
|
||||||
|
|
||||||
|
# 七牛云存储配置
|
||||||
|
[QINUI]
|
||||||
|
BUCKET = orico
|
||||||
|
BASE_URL = http://local.orico.com
|
||||||
|
ACCESS_KEY = 1234567890
|
||||||
|
SECRET_KEY = 1234567890
|
||||||
|
|
||||||
# 前台视图模板规则配置
|
# 前台视图模板规则配置
|
||||||
[INDEX_VIEW_TPL]
|
[INDEX_VIEW_TPL]
|
||||||
# 视图目录
|
# 视图目录
|
||||||
|
|||||||
@@ -9,12 +9,32 @@ use app\admin\model\v1\SysAttachmentUploadRecordModel;
|
|||||||
use Intervention\Image\ImageManager;
|
use Intervention\Image\ImageManager;
|
||||||
use Intervention\Image\Typography\FontFactory;
|
use Intervention\Image\Typography\FontFactory;
|
||||||
use think\facade\Filesystem;
|
use think\facade\Filesystem;
|
||||||
|
use filesystem\Qiniu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传控制器
|
* 文件上传控制器
|
||||||
*/
|
*/
|
||||||
class Upload
|
class Upload
|
||||||
{
|
{
|
||||||
|
public function test()
|
||||||
|
{
|
||||||
|
set_time_limit(-1);
|
||||||
|
|
||||||
|
// $file = request()->file('image');
|
||||||
|
// if (is_null($file)) {
|
||||||
|
// return error('请确定上传对象或字段是否正确');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// $name_rule = fn() => true ? $this->filenameGenerator($file) : null;
|
||||||
|
|
||||||
|
// $filename = Filesystem::disk('video_qiniu')->putFile('unknown', $file, $name_rule());
|
||||||
|
|
||||||
|
$qiniu_uploader = new Qiniu();
|
||||||
|
$filename = $qiniu_uploader->uploadFile('image');
|
||||||
|
|
||||||
|
dump($filename);
|
||||||
|
}
|
||||||
|
|
||||||
// 上传图片
|
// 上传图片
|
||||||
public function image()
|
public function image()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ Route::group('v1', function () {
|
|||||||
Route::group('images', function () {
|
Route::group('images', function () {
|
||||||
// 图片上传
|
// 图片上传
|
||||||
Route::post('/:module/upload', 'Upload/image');
|
Route::post('/:module/upload', 'Upload/image');
|
||||||
|
Route::post('/upload/test', 'Upload/test');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 视频管理
|
// 视频管理
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"php": ">=8.0.0",
|
"php": ">=8.0.0",
|
||||||
"topthink/framework": "^8.0",
|
"topthink/framework": "^8.0",
|
||||||
"topthink/think-orm": "v3.0.34",
|
"topthink/think-orm": "v3.0.34",
|
||||||
"topthink/think-filesystem": "^2.0",
|
"topthink/think-filesystem": "^3.0",
|
||||||
"topthink/think-multi-app": "^1.1",
|
"topthink/think-multi-app": "^1.1",
|
||||||
"topthink/think-migration": "^3.1",
|
"topthink/think-migration": "^3.1",
|
||||||
"topthink/think-view": "^2.0",
|
"topthink/think-view": "^2.0",
|
||||||
@@ -35,7 +35,8 @@
|
|||||||
"phpoffice/phpspreadsheet": "^3.8",
|
"phpoffice/phpspreadsheet": "^3.8",
|
||||||
"friendsofsymfony/oauth2-php": "^1.3",
|
"friendsofsymfony/oauth2-php": "^1.3",
|
||||||
"mobiledetect/mobiledetectlib": "4.8.09",
|
"mobiledetect/mobiledetectlib": "4.8.09",
|
||||||
"qiniu/php-sdk": "^7.14"
|
"qiniu/php-sdk": "^7.14",
|
||||||
|
"overtrue/flysystem-qiniu": "^3.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/var-dumper": ">=4.2",
|
"symfony/var-dumper": ">=4.2",
|
||||||
|
|||||||
@@ -39,6 +39,20 @@ return [
|
|||||||
// 可见性
|
// 可见性
|
||||||
'visibility' => 'public',
|
'visibility' => 'public',
|
||||||
],
|
],
|
||||||
|
'video_qiniu' => [
|
||||||
|
// 磁盘类型
|
||||||
|
'type' => \filesystem\driver\Qiniu::class,
|
||||||
|
// bucker 名称
|
||||||
|
'bucket' => 'orico-official-website',
|
||||||
|
// 访问密钥
|
||||||
|
'access_key' => 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms',
|
||||||
|
// 密钥
|
||||||
|
'secret_key' => 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q',
|
||||||
|
// 外部URL
|
||||||
|
'base_url' => '//szw73dlk3.hn-bkt.clouddn.com',
|
||||||
|
// 路径
|
||||||
|
'path' => '/storage/videos',
|
||||||
|
]
|
||||||
// 更多的磁盘配置信息
|
// 更多的磁盘配置信息
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|||||||
165
extend/filesystem/Qiniu.php
Normal file
165
extend/filesystem/Qiniu.php
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem;
|
||||||
|
|
||||||
|
use Qiniu\Auth;
|
||||||
|
use Qiniu\Storage\UploadManager;
|
||||||
|
use Qiniu\Storage\BucketManager;
|
||||||
|
|
||||||
|
class Qiniu
|
||||||
|
{
|
||||||
|
private $bucket = 'orico-official-website';
|
||||||
|
private $access_key = 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms';
|
||||||
|
private $secret_key = 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q';
|
||||||
|
|
||||||
|
private $rule = [
|
||||||
|
'fileSize' => 1024 * 1024 * 50, // 默认最大上传5M
|
||||||
|
'fileExt' => 'jpeg,jpg,png,mp4', // 默认上传文件后缀
|
||||||
|
'fileMime' => 'image/jpeg,image/png,image/gif,video/mp4' // 默认上传文件mime
|
||||||
|
];
|
||||||
|
|
||||||
|
private $dir = true;
|
||||||
|
private $path_prefix = '';
|
||||||
|
private $file_name_prefix = 'orico';
|
||||||
|
private $keep_original_name = false;
|
||||||
|
|
||||||
|
private $base_url = '//szw73dlk3.hn-bkt.clouddn.com';
|
||||||
|
|
||||||
|
public function __construct($conf = [])
|
||||||
|
{
|
||||||
|
if (!empty($conf['base_url'])) {
|
||||||
|
$this->base_url = $conf['base_url'];
|
||||||
|
}
|
||||||
|
if (!empty($conf['bucket'])) {
|
||||||
|
$this->bucket = $conf['bucket'];
|
||||||
|
}
|
||||||
|
if (!empty($conf['access_key'])) {
|
||||||
|
$this->access_key = $conf['access_key'];
|
||||||
|
}
|
||||||
|
if (!empty($conf['secret_key'])) {
|
||||||
|
$this->secret_key = $conf['secret_key'];
|
||||||
|
}
|
||||||
|
if (!empty($conf['path_prefix'])) {
|
||||||
|
$this->path_prefix = trim($conf['path_prefix'], '/');
|
||||||
|
}
|
||||||
|
if (!empty($conf['file_name_prefix'])) {
|
||||||
|
$this->file_name_prefix = $conf['file_name_prefix'];
|
||||||
|
}
|
||||||
|
if (!empty($conf['keep_original_name'])) {
|
||||||
|
$this->keep_original_name = $conf['keep_original_name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成随机字符串
|
||||||
|
*/
|
||||||
|
private function random($length, $type = "string", $convert = "0")
|
||||||
|
{
|
||||||
|
$conf = [
|
||||||
|
'number' => '0123456789',
|
||||||
|
'string' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||||
|
'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789='
|
||||||
|
];
|
||||||
|
$string = $conf[$type];
|
||||||
|
if (!$string) {
|
||||||
|
$string = $conf['string'];
|
||||||
|
}
|
||||||
|
$strlen = strlen($string) - 1;
|
||||||
|
$char = '';
|
||||||
|
for ($i = 0; $i < $length; $i++) {
|
||||||
|
$char .= $string[mt_rand(0, $strlen)];
|
||||||
|
}
|
||||||
|
if ($convert > 0) {
|
||||||
|
$res = strtoupper($char);
|
||||||
|
} elseif ($convert == 0) {
|
||||||
|
$res = $char;
|
||||||
|
} elseif ($convert < 0) {
|
||||||
|
$res = strtolower($char);
|
||||||
|
}
|
||||||
|
return $res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装文件名
|
||||||
|
*/
|
||||||
|
private function buildFileName()
|
||||||
|
{
|
||||||
|
return $this->file_name_prefix . time() . substr(time(), -5) . substr(microtime(), 2, 3) . $this->random(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传验证规则
|
||||||
|
*/
|
||||||
|
public function validate($rule)
|
||||||
|
{
|
||||||
|
$this->rule = $rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件到七牛云
|
||||||
|
*/
|
||||||
|
public function uploadFile($name)
|
||||||
|
{
|
||||||
|
// 构建鉴权对象
|
||||||
|
$auth = new Auth($this->access_key, $this->secret_key);
|
||||||
|
|
||||||
|
// 生成上传 Token
|
||||||
|
$token = $auth->uploadToken($this->bucket);
|
||||||
|
|
||||||
|
// 初始化 UploadManager 对象并进行文件的上传。
|
||||||
|
$upload_mgr = new UploadManager();
|
||||||
|
|
||||||
|
$file = request()->file($name);
|
||||||
|
|
||||||
|
$aspect_ratio = [];
|
||||||
|
if (!empty($this->rule['aspectRatio'])) {
|
||||||
|
$aspect_ratio = $this->rule['aspectRatio'];
|
||||||
|
unset($this->rule['aspectRatio']);
|
||||||
|
}
|
||||||
|
$validate = validate([$name => $this->rule]);
|
||||||
|
if (!$validate->check([$name => $file])) {
|
||||||
|
throw new \Exception($validate->getError());
|
||||||
|
}
|
||||||
|
|
||||||
|
$file_name = $file->getOriginalName(); // 文件原名
|
||||||
|
if (!$this->keep_original_name) {
|
||||||
|
$file_name = $this->buildFileName() . '.' . $file->extension();
|
||||||
|
if (!$this->dir && !empty($this->path_prefix)) {
|
||||||
|
$file_name = $this->path_prefix . '/' . $file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($this->dir) {
|
||||||
|
$file_name = date('Ymd') . '/' . $file_name;
|
||||||
|
if (!empty($this->path_prefix)) {
|
||||||
|
$file_name = $this->path_prefix . '/' . $file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$file_path = $file->getPathname(); // 临时路径
|
||||||
|
if (!empty($aspect_ratio)) { // 验证图片宽高
|
||||||
|
list($width, $height, $type, $attr) = getimagesize($file);
|
||||||
|
if ($width != $aspect_ratio['width'] || $height != $aspect_ratio['height']) {
|
||||||
|
throw new \Exception('图片宽高不符合');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$file_type = $file->getOriginalMime();
|
||||||
|
list($ret, $err) = $upload_mgr->putFile($token, $file_name, $file_path, null, $file_type, false);
|
||||||
|
|
||||||
|
if ($err !== null) {
|
||||||
|
throw new \Exception($err);
|
||||||
|
} else {
|
||||||
|
return ['hash' => $ret['hash'], 'filename' => $ret['key'], 'remote_url' => $this->base_url . $ret['key']];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件到七牛云
|
||||||
|
*/
|
||||||
|
public function deleteFile($name)
|
||||||
|
{
|
||||||
|
// 构建鉴权对象
|
||||||
|
$auth = new Auth($this->access_key, $this->secret_key);
|
||||||
|
// 初始化 BucketManager 对象并进行文件的删除。
|
||||||
|
$bucket_mgr = new BucketManager($auth);
|
||||||
|
$ret = $bucket_mgr->delete($this->bucket, $name);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
286
extend/filesystem/adapter/QiniuAdapter.php
Normal file
286
extend/filesystem/adapter/QiniuAdapter.php
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem\adapter;
|
||||||
|
|
||||||
|
use League\Flysystem\Config;
|
||||||
|
use League\Flysystem\FilesystemAdapter;
|
||||||
|
use League\Flysystem\FileAttributes;
|
||||||
|
use League\Flysystem\UnableToCopyFile;
|
||||||
|
use League\Flysystem\UnableToDeleteFile;
|
||||||
|
use League\Flysystem\UnableToMoveFile;
|
||||||
|
use League\Flysystem\UnableToReadFile;
|
||||||
|
use League\Flysystem\UnableToRetrieveMetadata;
|
||||||
|
use League\Flysystem\UnableToSetVisibility;
|
||||||
|
use League\Flysystem\UnableToWriteFile;
|
||||||
|
use Qiniu\Auth;
|
||||||
|
use Qiniu\Storage\UploadManager;
|
||||||
|
use Qiniu\Storage\BucketManager;
|
||||||
|
|
||||||
|
class QiniuAdapter implements FilesystemAdapter
|
||||||
|
{
|
||||||
|
protected ?Auth $authMgr;
|
||||||
|
protected ?UploadManager $uploadMgr;
|
||||||
|
protected ?BucketManager $bucketMgr;
|
||||||
|
|
||||||
|
public function __construct(protected string $bucket, protected string $access_key, protected string $secret_key, protected string $base_url, protected string $path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getAuthMgr(): Auth
|
||||||
|
{
|
||||||
|
return $this->authMgr ?? new Auth($this->access_key, $this->secret_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUploadMgr(): UploadManager
|
||||||
|
{
|
||||||
|
return $this->uploadMgr ?? new UploadManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getBucketMgr(): BucketManager
|
||||||
|
{
|
||||||
|
return $this->bucketMgr ?? new BucketManager($this->authMgr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function applyPathPrefix(string $path): string
|
||||||
|
{
|
||||||
|
return $this->path . $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseUrl($url): array
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
// Build arrays of values we need to decode before parsing
|
||||||
|
$entities = [
|
||||||
|
'%21',
|
||||||
|
'%2A',
|
||||||
|
'%27',
|
||||||
|
'%28',
|
||||||
|
'%29',
|
||||||
|
'%3B',
|
||||||
|
'%3A',
|
||||||
|
'%40',
|
||||||
|
'%26',
|
||||||
|
'%3D',
|
||||||
|
'%24',
|
||||||
|
'%2C',
|
||||||
|
'%2F',
|
||||||
|
'%3F',
|
||||||
|
'%23',
|
||||||
|
'%5B',
|
||||||
|
'%5D',
|
||||||
|
'%5C'
|
||||||
|
];
|
||||||
|
$replacements = ['!', '*', "'", '(', ')', ';', ':', '@', '&', '=', '$', ',', '/', '?', '#', '[', ']', '/'];
|
||||||
|
|
||||||
|
// Create encoded URL with special URL characters decoded so it can be parsed
|
||||||
|
// All other characters will be encoded
|
||||||
|
$encodedURL = str_replace($entities, $replacements, urlencode($url));
|
||||||
|
|
||||||
|
// Parse the encoded URL
|
||||||
|
$encodedParts = parse_url($encodedURL);
|
||||||
|
|
||||||
|
// Now, decode each value of the resulting array
|
||||||
|
if ($encodedParts) {
|
||||||
|
foreach ($encodedParts as $key => $value) {
|
||||||
|
$result[$key] = urldecode(str_replace($replacements, $entities, $value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeHost($domain): string
|
||||||
|
{
|
||||||
|
if (0 !== stripos($domain, 'https://') && 0 !== stripos($domain, 'http://')) {
|
||||||
|
$domain = "http://{$domain}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtrim($domain, '/') . '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUrl(string $path): string
|
||||||
|
{
|
||||||
|
$segments = $this->parseUrl($path);
|
||||||
|
$query = empty($segments['query']) ? '' : '?' . $segments['query'];
|
||||||
|
|
||||||
|
return $this->normalizeHost($this->base_url) . ltrim(implode('/', array_map('rawurlencode', explode('/', $segments['path']))), '/') . $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function privateDownloadUrl(string $path): string
|
||||||
|
{
|
||||||
|
return $this->getAuthMgr()->privateDownloadUrl($this->bucket, $this->applyPathPrefix($path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getMetadata($path): FileAttributes|array
|
||||||
|
{
|
||||||
|
$result = $this->getBucketMgr()->stat($this->bucket, $path);
|
||||||
|
$result[0]['key'] = $path;
|
||||||
|
|
||||||
|
return $this->normalizeFileInfo($result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeFileInfo(array $stats): FileAttributes
|
||||||
|
{
|
||||||
|
return new FileAttributes(
|
||||||
|
$stats['key'],
|
||||||
|
$stats['fsize'] ?? null,
|
||||||
|
null,
|
||||||
|
isset($stats['putTime']) ? floor($stats['putTime'] / 10000000) : null,
|
||||||
|
$stats['mimeType'] ?? null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fileExists(string $path): bool
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->stat($this->bucket, $this->applyPathPrefix($path));
|
||||||
|
return is_null($error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function directoryExists(string $path): bool
|
||||||
|
{
|
||||||
|
// 待实现
|
||||||
|
return $this->fileExists($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function write(string $path, string $contents, Config $config): void
|
||||||
|
{
|
||||||
|
$mime = $config->get('mime', 'application/octet-stream');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Error|null $error
|
||||||
|
*/
|
||||||
|
[, $error] = $this->getUploadMgr()->put(
|
||||||
|
$this->getAuthMgr()->uploadToken($this->bucket),
|
||||||
|
$this->applyPathPrefix($path),
|
||||||
|
$contents,
|
||||||
|
null,
|
||||||
|
$mime,
|
||||||
|
$path
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
throw UnableToWriteFile::atLocation($path, $error->message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeStream(string $path, $contents, Config $config): void
|
||||||
|
{
|
||||||
|
$data = '';
|
||||||
|
|
||||||
|
while (!feof($contents)) {
|
||||||
|
$data .= fread($contents, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->write($path, $data, $config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read(string $path): string
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = file_get_contents($this->privateDownloadUrl($path));
|
||||||
|
} catch (\Exception $th) {
|
||||||
|
throw UnableToReadFile::fromLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $result) {
|
||||||
|
throw UnableToReadFile::fromLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readStream(string $path)
|
||||||
|
{
|
||||||
|
if (ini_get('allow_url_fopen')) {
|
||||||
|
if ($result = fopen($this->privateDownloadUrl($path), 'r')) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw UnableToReadFile::fromLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete(string $path): void
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->delete($this->bucket, $this->applyPathPrefix($path));
|
||||||
|
if (!is_null($error)) {
|
||||||
|
throw UnableToDeleteFile::atLocation($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteDirectory(string $path): void
|
||||||
|
{
|
||||||
|
$this->delete($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createDirectory(string $path, Config $config): void
|
||||||
|
{
|
||||||
|
// 待实现
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setVisibility(string $path, string $visibility): void
|
||||||
|
{
|
||||||
|
throw UnableToSetVisibility::atLocation($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function visibility(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
throw UnableToRetrieveMetadata::visibility($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mimeType(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
$meta = $this->getMetadata($path);
|
||||||
|
|
||||||
|
if ($meta->mimeType() === null) {
|
||||||
|
throw UnableToRetrieveMetadata::mimeType($path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function lastModified(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
$meta = $this->getMetadata($path);
|
||||||
|
|
||||||
|
if ($meta->lastModified() === null) {
|
||||||
|
throw UnableToRetrieveMetadata::lastModified($path);
|
||||||
|
}
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fileSize(string $path): FileAttributes
|
||||||
|
{
|
||||||
|
$meta = $this->getMetadata($path);
|
||||||
|
|
||||||
|
if ($meta->fileSize() === null) {
|
||||||
|
throw UnableToRetrieveMetadata::fileSize($path);
|
||||||
|
}
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function listContents(string $path, bool $deep): iterable
|
||||||
|
{
|
||||||
|
$result = $this->getBucketMgr()->listFiles($this->bucket, $path);
|
||||||
|
|
||||||
|
foreach ($result[0]['items'] ?? [] as $files) {
|
||||||
|
yield $this->normalizeFileInfo($files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function move(string $source, string $destination, Config $config): void
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->rename($this->bucket, $source, $destination);
|
||||||
|
if (!is_null($error)) {
|
||||||
|
throw UnableToMoveFile::fromLocationTo($source, $destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function copy(string $source, string $destination, Config $config): void
|
||||||
|
{
|
||||||
|
[, $error] = $this->getBucketMgr()->copy($this->bucket, $source, $this->bucket, $destination);
|
||||||
|
if (!is_null($error)) {
|
||||||
|
throw UnableToCopyFile::fromLocationTo($source, $destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
extend/filesystem/driver/Qiniu.php
Normal file
19
extend/filesystem/driver/Qiniu.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
namespace filesystem\driver;
|
||||||
|
|
||||||
|
use League\Flysystem\FilesystemAdapter;
|
||||||
|
use Overtrue\Flysystem\Qiniu\QiniuAdapter;
|
||||||
|
|
||||||
|
class Qiniu extends \think\filesystem\Driver
|
||||||
|
{
|
||||||
|
protected function createAdapter(): FilesystemAdapter
|
||||||
|
{
|
||||||
|
return new QiniuAdapter(
|
||||||
|
$this->config['access_key'],
|
||||||
|
$this->config['secret_key'],
|
||||||
|
$this->config['bucket'],
|
||||||
|
$this->config['base_url'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace uploader;
|
|
||||||
|
|
||||||
use Qiniu\Auth;
|
|
||||||
use Qiniu\Storage\UploadManager;
|
|
||||||
use Qiniu\Storage\BucketManager;
|
|
||||||
|
|
||||||
class QiniuUploader
|
|
||||||
{
|
|
||||||
private $bucket = 'orico-opd';
|
|
||||||
private $accessKey = 'dOsTum4a5qvhPTBbZRPX0pIOU7PZWRX7htKjztms';
|
|
||||||
private $secretKey = 'KFxsGbnErkALFfeGdMa8QWTdodJbamMX0iznLe-q';
|
|
||||||
|
|
||||||
private $rule = [
|
|
||||||
'fileSize' => 1024 * 1024 * 5, // 默认最大上传5M
|
|
||||||
'fileExt' => 'jpeg,jpg,png', // 默认上传文件后缀
|
|
||||||
'fileMime' => 'image/jpeg,image/png,image/gif' // 默认上传文件mime
|
|
||||||
];
|
|
||||||
|
|
||||||
private $dir = true;
|
|
||||||
private $originalName = false;
|
|
||||||
private $pathPrefix = '';
|
|
||||||
private $fileNamePrefix = 'orico';
|
|
||||||
|
|
||||||
static public $domain = 'http://opdfile.f2b211.com/';
|
|
||||||
|
|
||||||
public function __construct($conf = [])
|
|
||||||
{
|
|
||||||
if (!empty($conf['bucket'])) {
|
|
||||||
$this->bucket = $conf['bucket'];
|
|
||||||
}
|
|
||||||
if (!empty($conf['accessKey'])) {
|
|
||||||
$this->accessKey = $conf['accessKey'];
|
|
||||||
}
|
|
||||||
if (!empty($conf['secretKey'])) {
|
|
||||||
$this->secretKey = $conf['secretKey'];
|
|
||||||
}
|
|
||||||
if (!empty($conf['pathPrefix'])) {
|
|
||||||
$this->pathPrefix = trim($conf['pathPrefix'], '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成随机字符串
|
|
||||||
*/
|
|
||||||
private function random($length, $type = "string", $convert = "0")
|
|
||||||
{
|
|
||||||
$conf = [
|
|
||||||
'number' => '0123456789',
|
|
||||||
'string' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
||||||
'all' => 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789='
|
|
||||||
];
|
|
||||||
$string = $conf[$type];
|
|
||||||
if (!$string) {
|
|
||||||
$string = $conf['string'];
|
|
||||||
}
|
|
||||||
$strlen = strlen($string) - 1;
|
|
||||||
$char = '';
|
|
||||||
for ($i = 0; $i < $length; $i++) {
|
|
||||||
$char .= $string[mt_rand(0, $strlen)];
|
|
||||||
}
|
|
||||||
if ($convert > 0) {
|
|
||||||
$res = strtoupper($char);
|
|
||||||
} elseif ($convert == 0) {
|
|
||||||
$res = $char;
|
|
||||||
} elseif ($convert < 0) {
|
|
||||||
$res = strtolower($char);
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 组装文件名
|
|
||||||
*/
|
|
||||||
private function buildFileName()
|
|
||||||
{
|
|
||||||
return $this->fileNamePrefix . time() . substr(time(), -5) . substr(microtime(), 2, 3) . $this->random(8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传验证规则
|
|
||||||
*/
|
|
||||||
public function validate($rule)
|
|
||||||
{
|
|
||||||
$this->rule = $rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件到七牛云
|
|
||||||
*/
|
|
||||||
public function uploadFile($name)
|
|
||||||
{
|
|
||||||
// 构建鉴权对象
|
|
||||||
$auth = new Auth($this->accessKey, $this->secretKey);
|
|
||||||
|
|
||||||
// 生成上传 Token
|
|
||||||
$token = $auth->uploadToken($this->bucket);
|
|
||||||
|
|
||||||
// 初始化 UploadManager 对象并进行文件的上传。
|
|
||||||
$uploadMgr = new UploadManager();
|
|
||||||
|
|
||||||
$file = request()->file($name);
|
|
||||||
|
|
||||||
$aspectRatio = [];
|
|
||||||
if (!empty($this->rule['aspectRatio'])) {
|
|
||||||
$aspectRatio = $this->rule['aspectRatio'];
|
|
||||||
unset($this->rule['aspectRatio']);
|
|
||||||
}
|
|
||||||
$validate = validate([$name => $this->rule]);
|
|
||||||
if (!$validate->check([$name => $file])) {
|
|
||||||
throw new \Exception($validate->getError());
|
|
||||||
}
|
|
||||||
|
|
||||||
$fileName = $file->getOriginalName(); // 文件原名
|
|
||||||
if (!$this->originalName) {
|
|
||||||
$fileName = $this->buildFileName() . '.' . $file->extension();
|
|
||||||
if (!$this->dir && !empty($this->pathPrefix)) {
|
|
||||||
$fileName = $this->pathPrefix . '/' . $fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->dir) {
|
|
||||||
$fileName = date('Y') . '/' . date('m') . '/' . date('d') . '/' . $fileName;
|
|
||||||
if (!empty($this->pathPrefix)) {
|
|
||||||
$fileName = $this->pathPrefix . '/' . $fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$filePath = $file->getPathname(); // 临时路径
|
|
||||||
if (!empty($aspectRatio)) { // 验证图片宽高
|
|
||||||
list($width, $height, $type, $attr) = getimagesize($file);
|
|
||||||
if ($width != $aspectRatio['width'] || $height != $aspectRatio['height']) {
|
|
||||||
throw new \Exception('图片宽高不符合');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$fileType = $file->getOriginalMime();
|
|
||||||
list($ret, $err) = $uploadMgr->putFile($token, $fileName, $filePath, null, $fileType, false);
|
|
||||||
|
|
||||||
if ($err !== null) {
|
|
||||||
throw new \Exception($err);
|
|
||||||
} else {
|
|
||||||
return ['hash' => $ret['hash'], 'filename' => $ret['key'], 'remote_url' => self::$domain . $ret['key']];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传文件到七牛云
|
|
||||||
*/
|
|
||||||
public function deleteFile($name)
|
|
||||||
{
|
|
||||||
// 构建鉴权对象
|
|
||||||
$auth = new Auth($this->accessKey, $this->secretKey);
|
|
||||||
// 初始化 BucketManager 对象并进行文件的删除。
|
|
||||||
$bucketManager = new BucketManager($auth);
|
|
||||||
$ret = $bucketManager->delete($this->bucket, $name);
|
|
||||||
return $ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user