BaseUpload.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace crmeb\services\upload;
  12. use crmeb\basic\BaseStorage;
  13. use think\facade\Config;
  14. /**
  15. * Class BaseUpload
  16. * @package crmeb\basic
  17. */
  18. abstract class BaseUpload extends BaseStorage
  19. {
  20. /**
  21. * 缩略图
  22. * @var string[]
  23. */
  24. protected $thumb = ['big', 'mid', 'small'];
  25. /**
  26. * 缩略图配置
  27. * @var array
  28. */
  29. protected $thumbConfig = [
  30. 'thumb_big_height' => 800,
  31. 'thumb_big_width' => 800,
  32. 'thumb_mid_height' => 300,
  33. 'thumb_mid_width' => 300,
  34. 'thumb_small_height' => 100,
  35. 'thumb_small_width' => 100,
  36. ];
  37. /**
  38. * 水印配置
  39. * @var array
  40. */
  41. protected $waterConfig = [
  42. 'image_watermark_status' => 0,
  43. 'watermark_type' => 1,
  44. 'watermark_image' => '',
  45. 'watermark_opacity' => 0,
  46. 'watermark_position' => 1,
  47. 'watermark_rotate' => 0,
  48. 'watermark_text' => '',
  49. 'watermark_text_angle' => "",
  50. 'watermark_text_color' => '#000000',
  51. 'watermark_text_size' => '5',
  52. 'watermark_text_font' => '',
  53. 'watermark_x' => 0,
  54. 'watermark_y' => 0
  55. ];
  56. /**
  57. * 图片信息
  58. * @var array
  59. */
  60. protected $fileInfo;
  61. /**
  62. * 下载图片信息
  63. */
  64. protected $downFileInfo;
  65. /**
  66. * 要生成缩略图、水印的图片地址
  67. * @var string
  68. */
  69. protected $filePath;
  70. /**
  71. * 验证配置
  72. * @var string
  73. */
  74. protected $validate;
  75. /**
  76. * 保存路径
  77. * @var string
  78. */
  79. protected $path = '';
  80. /**
  81. * 是否自动裁剪
  82. * @var bool
  83. */
  84. protected $authThumb = true;
  85. protected function initialize(array $config)
  86. {
  87. $this->fileInfo = $this->downFileInfo = new \StdClass();
  88. $thumbConfig = $this->thumbConfig;
  89. $config['thumb'] = $config['thumb'] ?? [];
  90. $this->thumbConfig = $config['thumb'] ?? [];
  91. foreach ($config['thumb'] as $item) {
  92. if ($item == '' || $item == 0) {
  93. $this->thumbConfig = $thumbConfig;
  94. }
  95. }
  96. $this->waterConfig = array_merge($this->waterConfig, $config['water'] ?? []);
  97. }
  98. /**
  99. * 设置处理缩略图、水印图片路径
  100. * @param string $filePath
  101. * @return $this
  102. */
  103. public function setFilepath(string $filePath)
  104. {
  105. $this->filePath = substr($filePath, 0, 1) === '.' ? substr($filePath, 1) : $filePath;
  106. return $this;
  107. }
  108. /**
  109. * 是否自动裁剪
  110. * @param bool $auth
  111. * @return $this
  112. */
  113. public function setAuthThumb(bool $auth)
  114. {
  115. $this->authThumb = $auth;
  116. return $this;
  117. }
  118. /**
  119. * 上传文件路径
  120. * @param string $path
  121. * @return $this
  122. */
  123. public function to(string $path)
  124. {
  125. $this->path = $path;
  126. return $this;
  127. }
  128. /**
  129. * 获取文件信息
  130. * @return array
  131. */
  132. public function getFileInfo()
  133. {
  134. return $this->fileInfo;
  135. }
  136. /**
  137. * 检测是否是图片
  138. * @param $filePath
  139. * @return bool
  140. */
  141. protected function checkImage($filePath)
  142. {
  143. //获取图像信息
  144. $info = @getimagesize($filePath);
  145. //检测图像合法性
  146. if (false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))) {
  147. return false;
  148. }
  149. return true;
  150. }
  151. /**
  152. * 验证合法上传域名
  153. * @param string $url
  154. * @return string
  155. */
  156. protected function checkUploadUrl(string $url)
  157. {
  158. if ($url && strstr($url, 'http') === false) {
  159. $url = 'http://' . $url;
  160. }
  161. return $url;
  162. }
  163. /**
  164. * 获取系统配置
  165. * @return mixed
  166. */
  167. protected function getConfig()
  168. {
  169. $config['filesize'] = Config::get($this->configFile . '.filesize', []);
  170. $config['fileExt'] = Config::get($this->configFile . '.fileExt', []);
  171. $config['fileMime'] = Config::get($this->configFile . '.fileMime', []);
  172. return $config;
  173. }
  174. /**
  175. * 设置验证规则
  176. * @param array|null $validate
  177. * @return $this
  178. */
  179. public function validate(?array $validate = null)
  180. {
  181. if (is_null($validate)) {
  182. $validate = $this->getConfig();
  183. }
  184. $this->validate = $validate;
  185. return $this;
  186. }
  187. /**
  188. * 验证目录是否正确
  189. * @param string $key
  190. * @return false|string
  191. */
  192. protected function getUploadPath(string $key)
  193. {
  194. $path = ($this->path ? $this->path . '/' : '') . $key;
  195. if ($path && $path[0] === '/') {
  196. $path = substr($path, 1);
  197. }
  198. return $path;
  199. }
  200. /**
  201. * 提取文件名
  202. * @param string $path
  203. * @param string $ext
  204. * @return string
  205. */
  206. protected function saveFileName(string $path = null, string $ext = 'jpg')
  207. {
  208. return ($path ? substr(md5($path), 0, 5) : '') . date('YmdHis') . rand(0, 9999) . '.' . $ext;
  209. }
  210. /**
  211. * 提取文件后缀以及之前部分
  212. * @param string $path
  213. * @return false|string[]
  214. */
  215. protected function getFileName(string $path)
  216. {
  217. $_empty = ['', ''];
  218. if (!$path) return $_empty;
  219. if (strpos($path, '?')) {
  220. $_tarr = explode('?', $path);
  221. $path = trim($_tarr[0]);
  222. }
  223. $arr = explode('.', $path);
  224. if (!is_array($arr) || count($arr) <= 1) return $_empty;
  225. $ext_name = trim($arr[count($arr) - 1]);
  226. $ext_name = !$ext_name ? 'jpg' : $ext_name;
  227. return [explode('.' . $ext_name, $path)[0], $ext_name];
  228. }
  229. /**
  230. * 获取图片地址
  231. * @param string $filePath
  232. * @param bool $is_parse_url
  233. * @return string
  234. */
  235. protected function getFilePath(string $filePath = '', bool $is_parse_url = false)
  236. {
  237. $path = $filePath ?: $this->filePath;
  238. if ($is_parse_url) {
  239. $data = parse_url($path);
  240. //远程地址处理
  241. if (isset($data['host']) && isset($data['path'])) {
  242. if (file_exists(app()->getRootPath() . 'public' . $data['path'])) {
  243. $path = $data['path'];
  244. }
  245. }
  246. }
  247. return $path;
  248. }
  249. /**
  250. * 获取文件类型和大小
  251. * @param string $url
  252. * @param bool $isData
  253. * @return array
  254. */
  255. protected function getFileHeaders(string $url, $isData = true)
  256. {
  257. stream_context_set_default(['ssl' => ['verify_peer' => false, 'verify_peer_name' => false]]);
  258. $header['size'] = 0;
  259. $header['type'] = 'image/jpeg';
  260. if (!$isData) {
  261. return $header;
  262. }
  263. try {
  264. $headerArray = get_headers(str_replace('\\', '/', $url), true);
  265. if (!isset($headerArray['Content-Length'])) {
  266. $header['size'] = 0;
  267. }
  268. if (!isset($headerArray['Content-Type'])) {
  269. $header['type'] = 'image/jpeg';
  270. }
  271. if (is_array($headerArray['Content-Length']) && count($headerArray['Content-Length']) == 2) {
  272. $header['size'] = $headerArray['Content-Length'][1];
  273. }
  274. if (is_array($headerArray['Content-Type']) && count($headerArray['Content-Type']) == 2) {
  275. $header['type'] = $headerArray['Content-Type'][1];
  276. }
  277. } catch (\Exception $e) {
  278. }
  279. return $header;
  280. }
  281. /**
  282. * 获取上传信息
  283. * @return array
  284. */
  285. public function getUploadInfo()
  286. {
  287. if (isset($this->fileInfo->filePath)) {
  288. if (strstr($this->fileInfo->filePath, 'http') === false) {
  289. $url = request()->domain() . $this->fileInfo->filePath;
  290. } else {
  291. $url = $this->fileInfo->filePath;
  292. }
  293. $headers = $this->getFileHeaders($url);
  294. return [
  295. 'name' => $this->fileInfo->fileName,
  296. 'real_name' => $this->fileInfo->realName ?? '',
  297. 'size' => $headers['size'] ?? 0,
  298. 'type' => $headers['type'] ?? 'image/jpeg',
  299. 'dir' => $this->fileInfo->filePath,
  300. 'thumb_path' => $this->fileInfo->filePath,
  301. 'thumb_path_big' => $this->fileInfo->filePathBig ?? '',
  302. 'thumb_path_mid' => $this->fileInfo->filePathMid ?? '',
  303. 'thumb_path_small' => $this->fileInfo->filePathSmall ?? '',
  304. 'thumb_path_water' => $this->fileInfo->filePathWater ?? '',
  305. 'time' => time(),
  306. ];
  307. } else {
  308. return [];
  309. }
  310. }
  311. /**
  312. * 获取下载信息
  313. * @return array
  314. */
  315. public function getDownloadInfo()
  316. {
  317. if (isset($this->downFileInfo->downloadFilePath)) {
  318. if (strstr($this->downFileInfo->downloadFilePath, 'http') === false) {
  319. $url = request()->domain() . $this->downFileInfo->downloadFilePath;
  320. } else {
  321. $url = $this->downFileInfo->downloadFilePath;
  322. }
  323. $headers = $this->getFileHeaders($url);
  324. return [
  325. 'name' => $this->downFileInfo->downloadFileName,
  326. 'real_name' => $this->downFileInfo->downloadRealName ?? '',
  327. 'size' => $headers['size'] ?? 0,
  328. 'type' => $headers['type'] ?? 'image/jpeg',
  329. 'dir' => $this->downFileInfo->downloadFilePath ?? '',
  330. 'thumb_path' => $this->downFileInfo->downloadFilePath ?? '',
  331. 'time' => time(),
  332. ];
  333. } else {
  334. return [];
  335. }
  336. }
  337. /**
  338. * 检测文件内容
  339. * @param $fileHandle
  340. * @return bool|void
  341. * @author wuhaotian
  342. * @email 442384644@qq.com
  343. * @date 2024/4/11
  344. */
  345. public function checkFileContent($fileHandle)
  346. {
  347. $stream = fopen($fileHandle->getPathname(), 'r');
  348. $content = (fread($stream, filesize($fileHandle->getPathname())));
  349. if (is_resource($stream)) {
  350. fclose($stream);
  351. }
  352. if (preg_match('/think|app|php|log|phar|Socket|Channel|Flysystem|Psr6Cache|Cached|Request|debug|Psr6Cachepool|eval/i', $content)) {
  353. return $this->setError('文件内容不合法');
  354. }
  355. }
  356. /**
  357. * 文件上传
  358. * @return mixed
  359. */
  360. abstract public function move(string $file = 'file');
  361. /**
  362. * 文件流上传
  363. * @return mixed
  364. */
  365. abstract public function stream($fileContent, string $key = null);
  366. /**
  367. * 删除文件
  368. * @return mixed
  369. */
  370. abstract public function delete(string $filePath);
  371. /**
  372. * 实例化上传
  373. * @return mixed
  374. */
  375. abstract protected function app();
  376. /**
  377. * 拉取空间
  378. * @param string $region
  379. * @param bool $line
  380. * @param bool $shared
  381. * @return mixed
  382. */
  383. abstract public function listbuckets(string $region, bool $line = false, bool $shared = false);
  384. /**
  385. * 创建空间
  386. * @param string $name
  387. * @param string $region
  388. * @return mixed
  389. */
  390. abstract public function createBucket(string $name, string $region);
  391. /**
  392. * 获得区域
  393. * @return mixed
  394. */
  395. abstract public function getRegion();
  396. /**
  397. * 删除空间
  398. * @param string $name
  399. * @return mixed
  400. */
  401. abstract public function deleteBucket(string $name);
  402. /**
  403. * 绑定自定义域名
  404. * @param string $name
  405. * @param string $domain
  406. * @param string|null $region
  407. * @return mixed
  408. */
  409. abstract public function bindDomian(string $name, string $domain, string $region = null);
  410. /**
  411. * 设置跨域
  412. * @param string $name
  413. * @param string $region
  414. * @return mixed
  415. */
  416. abstract public function setBucketCors(string $name, string $region);
  417. /**
  418. * 获取上传密钥
  419. * @return mixed
  420. */
  421. abstract public function getTempKeys();
  422. /**
  423. * 获取缩略图
  424. * @return mixed
  425. */
  426. abstract public function thumb(string $filePath = '');
  427. /**
  428. * 添加水印
  429. * @return mixed
  430. */
  431. abstract public function water(string $filePath = '');
  432. }