BaseUpload.php 12 KB

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