<?php
declare(strict_types=1);
* +----------------------------------------------------------------------
* | ThinkAdmin Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin;
use think\admin\contract\StorageInterface;
use think\admin\storage\LocalStorage;
use think\Container;
* 文件存储引擎管理.
* @class Storage
* @method static array info($name, $safe = false, $attname = null) 文件存储信息
* @method static array set($name, $file, $safe = false, $attname = null) 储存文件
* @method static string url($name, $safe = false, $attname = null) 获取文件链接
* @method static string get($name, $safe = false) 读取文件内容
* @method static string path($name, $safe = false) 文件存储路径
* @method static boolean del($name, $safe = false) 删除存储文件
* @method static boolean has($name, $safe = false) 检查是否存在
* @method static string upload() 获取上传地址
*/
abstract class Storage
{
* 静态访问启用.
* @param string $method 方法名称
* @param array $arguments 调用参数
* @return mixed
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
if (method_exists($storage = static::instance(), $method)) {
return call_user_func_array([$storage, $method], $arguments);
}
throw new Exception('method not exists: ' . get_class($storage) . "->{$method}()");
}
* 实例化存储操作对象
* @param ?string $name 驱动名称
* @param ?string $class 驱动类名
* @throws Exception
*/
public static function instance(?string $name = null, ?string $class = null): StorageInterface
{
try {
if (is_null($class)) {
$type = ucfirst(strtolower($name ?: sysconf('storage.type|raw')));
$class = "think\\admin\\storage\\{$type}Storage";
}
if (class_exists($class)) {
return Container::getInstance()->make($class);
}
throw new Exception("Storage driver [{$class}] does not exist.");
} catch (Exception $exception) {
throw $exception;
} catch (\Exception $exception) {
throw new Exception($exception->getMessage());
}
}
* 获取文件相对名称.
* @param string $url 文件访问链接
* @param string $ext 文件后缀名称
* @param string $pre 文件存储前缀
* @param string $fun 名称规则方法
*/
public static function name(string $url, string $ext = '', string $pre = '', string $fun = 'md5'): string
{
[$hah, $ext] = [$fun($url), trim($ext ?: pathinfo($url, 4), '.\/')];
$attr = [trim($pre, '.\/'), substr($hah, 0, 2), substr($hah, 2, 30)];
return trim(join('/', $attr), '/') . '.' . strtolower($ext ?: 'tmp');
}
* 下载文件到本地.
* @param string $url 文件URL地址
* @param bool $force 是否强制下载
* @param int $expire 文件保留时间
*/
public static function down(string $url, bool $force = false, int $expire = 0): array
{
try {
$local = LocalStorage::instance();
$filename = static::name($url, '', 'down/');
if (empty($force) && $local->has($filename)) {
if ($expire < 1 || filemtime($local->path($filename)) + $expire > time()) {
return $local->info($filename);
}
}
return $local->set($filename, static::curlGet($url));
} catch (\Exception $exception) {
return ['url' => $url, 'hash' => md5($url), 'key' => $url, 'file' => $url];
}
}
* 获取后缀类型.
* @param array|string $exts 文件后缀
* @param array $mime 文件信息
*/
public static function mime($exts, array $mime = []): string
{
$mimes = static::mimes();
foreach (is_string($exts) ? explode(',', $exts) : $exts as $ext) {
$mime[] = $mimes[strtolower($ext)] ?? 'application/octet-stream';
}
return join(',', array_unique($mime));
}
* 获取所有类型.
*/
public static function mimes(): array
{
static $mimes = [];
if (count($mimes) > 0) {
return $mimes;
}
return $mimes = include __DIR__ . '/storage/bin/mimes.php';
}
* 获取存储类型.
*/
public static function types(): array
{
return [
'local' => lang('本地服务器存储'),
'alist' => lang('自建Alist存储'),
'qiniu' => lang('七牛云对象存储'),
'upyun' => lang('又拍云USS存储'),
'txcos' => lang('腾讯云COS存储'),
'alioss' => lang('阿里云OSS存储'),
];
}
* 使用CURL读取网络资源.
* @param string $url 资源地址
*/
public static function curlGet(string $url): string
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$body = curl_exec($ch) ?: '';
curl_close($ch);
return $body;
}
* 图片数据存储.
* @param string $base64 图片内容
* @param string $prefix 保存前缀
* @param bool $safemode 安全模式
* @return array [ url => URL ]
* @throws Exception
*/
public static function saveImage(string $base64, string $prefix = 'image', bool $safemode = false): array
{
if (preg_match('|^data:image/(.*?);base64,|i', $base64)) {
[$ext, $img] = explode('|||', preg_replace('|^data:image/(.*?);base64,|i', '$1|||', $base64));
$name = static::name($img, $ext, $prefix);
if (empty($ext) || !in_array(strtolower($ext), ['gif', 'png', 'jpg', 'jpeg'])) {
throw new Exception('内容格式异常!');
}
if ($safemode) {
return LocalStorage::instance()->set($name, base64_decode($img), true);
}
return static::instance()->set($name, base64_decode($img));
}
return ['url' => $base64];
}
}