BaseUpload.php 12 KB

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