選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

BaseUpload.php 11KB

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