Storage.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Library for ThinkAdmin
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2014~2021 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: https://gitee.com/zoujingli/ThinkLibrary
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( https://mit-license.org )
  10. // +----------------------------------------------------------------------
  11. // | gitee 仓库地址 :https://gitee.com/zoujingli/ThinkLibrary
  12. // | github 仓库地址 :https://github.com/zoujingli/ThinkLibrary
  13. // +----------------------------------------------------------------------
  14. declare (strict_types=1);
  15. namespace think\admin;
  16. use think\admin\storage\LocalStorage;
  17. use think\App;
  18. use think\Container;
  19. use think\db\exception\DataNotFoundException;
  20. use think\db\exception\DbException;
  21. use think\db\exception\ModelNotFoundException;
  22. /**
  23. * 文件存储引擎管理
  24. * Class Storage
  25. * @package think\admin
  26. * @method array info($name, $safe = false, $attname = null) static 文件存储信息
  27. * @method array set($name, $file, $safe = false, $attname = null) static 储存文件
  28. * @method string url($name, $safe = false, $attname = null) static 获取文件链接
  29. * @method string get($name, $safe = false) static 读取文件内容
  30. * @method string path($name, $safe = false) static 文件存储路径
  31. * @method boolean del($name, $safe = false) static 删除存储文件
  32. * @method boolean has($name, $safe = false) static 检查是否存在
  33. * @method string upload() static 获取上传地址
  34. */
  35. abstract class Storage
  36. {
  37. /**
  38. * 应用实例
  39. * @var App
  40. */
  41. protected $app;
  42. /**
  43. * 存储类型
  44. * @var string
  45. */
  46. protected $type;
  47. /**
  48. * 链接类型
  49. * @var string
  50. */
  51. protected $link;
  52. /**
  53. * 链接前缀
  54. * @var string
  55. */
  56. protected $prefix;
  57. /**
  58. * Storage constructor.
  59. * @param App $app
  60. * @throws DataNotFoundException
  61. * @throws DbException
  62. * @throws ModelNotFoundException
  63. */
  64. public function __construct(App $app)
  65. {
  66. $this->app = $app;
  67. $this->link = sysconf('storage.link_type');
  68. $this->initialize();
  69. }
  70. /**
  71. * 存储驱动初始化
  72. */
  73. abstract protected function initialize();
  74. /**
  75. * 静态访问启用
  76. * @param string $method 方法名称
  77. * @param array $arguments 调用参数
  78. * @return mixed
  79. * @throws Exception
  80. * @throws DataNotFoundException
  81. * @throws DbException
  82. * @throws ModelNotFoundException
  83. */
  84. public static function __callStatic(string $method, array $arguments)
  85. {
  86. if (method_exists($class = static::instance(), $method)) {
  87. return call_user_func_array([$class, $method], $arguments);
  88. } else {
  89. throw new Exception("method not exists: " . get_class($class) . "->{$method}()");
  90. }
  91. }
  92. /**
  93. * 设置文件驱动名称
  94. * @param null|string $name 驱动名称
  95. * @return static
  96. * @throws Exception
  97. * @throws DataNotFoundException
  98. * @throws DbException
  99. * @throws ModelNotFoundException
  100. */
  101. public static function instance(?string $name = null)
  102. {
  103. $class = ucfirst(strtolower($name ?: sysconf('storage.type')));
  104. if (class_exists($object = "think\\admin\\storage\\{$class}Storage")) {
  105. return Container::getInstance()->make($object);
  106. } else {
  107. throw new Exception("File driver [{$class}] does not exist.");
  108. }
  109. }
  110. /**
  111. * 获取文件相对名称
  112. * @param string $url 文件访问链接
  113. * @param string $ext 文件后缀名称
  114. * @param string $pre 文件存储前缀
  115. * @param string $fun 名称规则方法
  116. * @return string
  117. */
  118. public static function name(string $url, string $ext = '', string $pre = '', string $fun = 'md5'): string
  119. {
  120. [$hah, $ext] = [$fun($url), trim($ext ?: pathinfo($url, 4), '.\\/')];
  121. $attr = [trim($pre, '.\\/'), substr($hah, 0, 2), substr($hah, 2, 30)];
  122. return trim(join('/', $attr), '/') . '.' . strtolower($ext ?: 'tmp');
  123. }
  124. /**
  125. * 下载文件到本地
  126. * @param string $url 文件URL地址
  127. * @param boolean $force 是否强制下载
  128. * @param integer $expire 文件保留时间
  129. * @return array
  130. */
  131. public static function down(string $url, bool $force = false, int $expire = 0): array
  132. {
  133. try {
  134. $file = LocalStorage::instance();
  135. $name = static::name($url, '', 'down/');
  136. if (empty($force) && $file->has($name)) {
  137. if ($expire < 1 || filemtime($file->path($name)) + $expire > time()) {
  138. return $file->info($name);
  139. }
  140. }
  141. return $file->set($name, static::curlGet($url));
  142. } catch (\Exception $exception) {
  143. return ['url' => $url, 'hash' => md5($url), 'key' => $url, 'file' => $url];
  144. }
  145. }
  146. /**
  147. * 根据文件后缀获取文件MINE
  148. * @param array|string $exts 文件后缀
  149. * @param array $mime 文件信息
  150. * @return string
  151. */
  152. public static function mime($exts, array $mime = []): string
  153. {
  154. $mimes = static::mimes();
  155. foreach (is_string($exts) ? explode(',', $exts) : $exts as $ext) {
  156. $mime[] = $mimes[strtolower($ext)] ?? 'application/octet-stream';
  157. }
  158. return join(',', array_unique($mime));
  159. }
  160. /**
  161. * 获取所有文件的信息
  162. * @return array
  163. */
  164. public static function mimes(): array
  165. {
  166. static $mimes = [];
  167. if (count($mimes) > 0) return $mimes;
  168. return $mimes = include __DIR__ . '/storage/bin/mimes.php';
  169. }
  170. /**
  171. * 使用CURL读取网络资源
  172. * @param string $url 资源地址
  173. * @return string
  174. */
  175. public static function curlGet(string $url): string
  176. {
  177. $ch = curl_init();
  178. curl_setopt($ch, CURLOPT_URL, $url);
  179. curl_setopt($ch, CURLOPT_HEADER, 0);
  180. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  181. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  182. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  183. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  184. $content = curl_exec($ch);
  185. curl_close($ch);
  186. return $content ?: '';
  187. }
  188. /**
  189. * 获取下载链接后缀
  190. * @param null|string $attname 下载名称
  191. * @param null|string $filename 文件名称
  192. * @return string
  193. */
  194. protected function getSuffix(?string $attname = null, ?string $filename = null): string
  195. {
  196. $suffix = '';
  197. if (is_string($filename) && stripos($this->link, 'compress') !== false) {
  198. $compress = [
  199. 'LocalStorage' => '',
  200. 'QiniuStorage' => '?imageslim',
  201. 'TxcosStorage' => '?imageMogr2/format/webp',
  202. 'AliossStorage' => '?x-oss-process=image/format,webp',
  203. ];
  204. $class = basename(get_class($this));
  205. $extens = strtolower(pathinfo($this->delSuffix($filename), PATHINFO_EXTENSION));
  206. $suffix = in_array($extens, ['png', 'jpg', 'jpeg']) ? ($compress[$class] ?? '') : '';
  207. }
  208. if (is_string($attname) && strlen($attname) > 0 && stripos($this->link, 'full') !== false) {
  209. $suffix .= ($suffix ? '&' : '?') . 'attname=' . urlencode($attname);
  210. }
  211. return $suffix;
  212. }
  213. /**
  214. * 获取文件基础名称
  215. * @param string $name 文件名称
  216. * @return string
  217. */
  218. protected function delSuffix(string $name): string
  219. {
  220. if (strpos($name, '?') !== false) {
  221. return strstr($name, '?', true);
  222. }
  223. return $name;
  224. }
  225. }