Upload.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <?php
  2. /**
  3. * Niushop商城系统 - 团队十年电商经验汇集巨献!
  4. * =========================================================
  5. * Copy right 2019-2029 杭州牛之云科技有限公司, 保留所有权利。
  6. * ----------------------------------------------
  7. * 官方网址: https://www.niushop.com
  8. * =========================================================
  9. */
  10. namespace extend;
  11. /**
  12. * 上传控制器
  13. * @author Administrator
  14. *
  15. */
  16. class Upload
  17. {
  18. /**
  19. * @var string 错误信息
  20. */
  21. public $error;
  22. /**
  23. * @var array 上传规则
  24. */
  25. public $validate = [];
  26. /**
  27. * @var array 上传文件信息
  28. */
  29. public $info;
  30. /**
  31. * @var string 当前完整文件名
  32. */
  33. protected $filename;
  34. /**
  35. * @var array 上传文件信息
  36. */
  37. public function __construct($filename = '')
  38. {
  39. $this->filename = $filename;
  40. }
  41. /**
  42. * 设置上传信息
  43. * @param unknown $filename
  44. */
  45. public function setFilename($filename)
  46. {
  47. $this->file = $filename;
  48. return $this;
  49. }
  50. /**
  51. * 设置上传信息
  52. * @param array $info
  53. * @return \util\Upload
  54. */
  55. public function setUploadInfo($info)
  56. {
  57. $this->info = $info;
  58. return $this;
  59. }
  60. /**
  61. * 获取上传文件的信息
  62. * @access public
  63. * @param string $name 信息名称
  64. * @return array|string
  65. */
  66. public function getInfo($name = '')
  67. {
  68. return isset($this->info[ $name ]) ? $this->info[ $name ] : $this->info;
  69. }
  70. /**
  71. * 设置文件上传文件的验证规则
  72. * @param array $rule
  73. * @return \util\Upload
  74. */
  75. public function setValidate(array $rule = [])
  76. {
  77. $this->validate = $rule;
  78. return $this;
  79. }
  80. /**
  81. * 验证目录是否可写
  82. * @param unknown $path
  83. * @return boolean
  84. */
  85. public function checkPath($path)
  86. {
  87. if (is_dir($path) || mkdir($path, 0755, true)) {
  88. return true;
  89. }
  90. $this->error = [ 'directory {:path} creation failed', [ 'path' => $path ] ];
  91. if(!defined("initroute_tag")) exit();
  92. return false;
  93. }
  94. /**
  95. * 检测是否合法的上传文件
  96. * @access public
  97. * @return bool
  98. */
  99. public function isValid()
  100. {
  101. return $this->isTest ? is_file($this->filename) : is_uploaded_file($this->filename);
  102. }
  103. /**
  104. * 检测上传文件
  105. * @access public
  106. * @param array $rule 验证规则
  107. * @return bool
  108. */
  109. public function check($rule = [])
  110. {
  111. $rule = $this->validate;
  112. /* 检查文件大小 */
  113. if (isset($rule['size']) && !$this->checkSize($rule['size'])) {
  114. $this->error = 'filesize not match';
  115. return false;
  116. }
  117. /* 检查文件 Mime 类型 */
  118. if (isset($rule['type']) && !$this->checkMime($rule['type'])) {
  119. $this->error = 'mimetype to upload is not allowed';
  120. return false;
  121. }
  122. /* 检查文件后缀 */
  123. if (isset($rule['ext']) && !$this->checkExt($rule['ext'])) {
  124. $this->error = 'extensions to upload is not allowed';
  125. return false;
  126. }
  127. return true;
  128. }
  129. /**
  130. * 检测上传文件大小
  131. * @access public
  132. * @param integer $size 最大大小
  133. * @return bool
  134. */
  135. public function checkSize($size)
  136. {
  137. return $this->getFileSize($this->info["tmp_name"]) <= $size;
  138. }
  139. /**
  140. * 检测上传文件类型
  141. * @access public
  142. * @param array|string $mime 允许类型
  143. * @return bool
  144. */
  145. public function getFileSize($filename)
  146. {
  147. $filesize = filesize($filename);
  148. clearstatcache();
  149. return $filesize;
  150. }
  151. /**
  152. * 获取文件类型
  153. * @param unknown $filename
  154. * @return unknown
  155. */
  156. public function getFileType($filename)
  157. {
  158. // filetype($filePath);
  159. $finfo = finfo_open(FILEINFO_MIME_TYPE); // 返回 mime 类型
  160. $filetype = finfo_file($finfo, $filename);
  161. finfo_close($finfo);
  162. return $filetype;
  163. }
  164. /**
  165. * 检测上传文件类型
  166. * @access public
  167. * @param array|string $mime 允许类型
  168. * @return bool
  169. */
  170. public function checkMime($mime)
  171. {
  172. $mime = is_string($mime) ? explode(',', $mime) : $mime;
  173. return in_array(strtolower($this->getFileType($this->info["tmp_name"])), $mime);
  174. }
  175. /**
  176. * 获取文件类型信息
  177. * @access public
  178. * @return string
  179. */
  180. public function getMime()
  181. {
  182. $finfo = finfo_open(FILEINFO_MIME_TYPE);
  183. return finfo_file($finfo, $this->filename);
  184. }
  185. /**
  186. * 检测上传文件后缀
  187. * @access public
  188. * @param array|string $ext 允许后缀
  189. * @return bool
  190. */
  191. public function checkExt($ext)
  192. {
  193. if (is_string($ext)) {
  194. $ext = explode(',', $ext);
  195. }
  196. $extension = strtolower($this->getFileExt($this->getInfo('name')));
  197. return in_array($extension, $ext);
  198. }
  199. /**
  200. * 获取文件后缀
  201. * @param unknown $filename
  202. * @return mixed
  203. */
  204. public function getFileExt($filename)
  205. {
  206. return pathinfo($filename, PATHINFO_EXTENSION);
  207. }
  208. /**
  209. * 移动文件
  210. * @param unknown $path
  211. * @param string $savename
  212. * @param string $replace
  213. * @return boolean|\util\Upload
  214. */
  215. public function move($path, $savename, $replace = true)
  216. {
  217. // 文件上传失败,捕获错误代码
  218. if (!empty($this->info['error'])) {
  219. $this->error($this->info['error']);
  220. return false;
  221. }
  222. // 验证上传
  223. if (!$this->check()) {
  224. return false;
  225. }
  226. $path = rtrim($path, "/") . "/";
  227. // 文件保存命名规则(有外部传入)
  228. $filename = $path . $savename;
  229. // 检测目录
  230. if (false === $this->checkPath(dirname($filename))) {
  231. return false;
  232. }
  233. // 不覆盖同名文件
  234. if (!$replace && is_file($filename)) {
  235. $this->error = [ 'has the same filename: {:filename}', [ 'filename' => $filename ] ];
  236. return false;
  237. }
  238. /* 移动文件 */
  239. if (!move_uploaded_file($this->filename, $filename)) {
  240. $this->error = 'upload write error';
  241. return false;
  242. }
  243. return $filename;
  244. }
  245. /**
  246. * 检测图像文件
  247. * @access public
  248. * @return bool
  249. */
  250. public function checkImg()
  251. {
  252. $extension = strtolower($this->getFileExt($this->getInfo('name')));
  253. // 如果上传的不是图片,或者是图片而且后缀确实符合图片类型则返回 true
  254. return !in_array($extension, [ 'gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf' ]) || in_array($this->getImageType($this->filename), [ 1, 2, 3, 4, 6, 13 ]);
  255. }
  256. /**
  257. * 判断图像类型
  258. * @access protected
  259. * @param string $image 图片名称
  260. * @return bool|int
  261. */
  262. protected function getImageType($image)
  263. {
  264. if (function_exists('exif_imagetype')) {
  265. return exif_imagetype($image);
  266. }
  267. try {
  268. $info = getimagesize($image);
  269. return $info ? $info[2] : false;
  270. } catch (\Exception $e) {
  271. return false;
  272. }
  273. }
  274. /**
  275. * 得到图片mime信息
  276. * @param unknown $image
  277. * @return boolean
  278. */
  279. public function getImageInfo($image)
  280. {
  281. try {
  282. $info = getimagesize($image);
  283. return $info;
  284. } catch (\Exception $e) {
  285. return false;
  286. }
  287. }
  288. /**
  289. *获取一个新文件名
  290. */
  291. public function createNewFileName()
  292. {
  293. $name = date('Ymdhis', time())
  294. . sprintf('%03d', microtime(true) * 1000)
  295. . sprintf('%02d', mt_rand(10, 99));
  296. return $name;
  297. }
  298. /**
  299. * 这里$data为一个数组类型
  300. * $data[0] 为图像的宽度
  301. * $data[1] 为图像的高度
  302. * $data[2] 为图像的格式,包括jpg、gif和png等
  303. * $data[3] 为图像的宽度和高度,内容为 width="xxx" height="yyy"
  304. */
  305. private function getFileSizeData($file_name)
  306. {
  307. $data = getimagesize($file_name); // 图片名称
  308. return $data;
  309. }
  310. /**
  311. * 获取错误信息(支持多语言)
  312. * @access public
  313. * @return string
  314. */
  315. public function getError()
  316. {
  317. return $this->error;
  318. }
  319. /**
  320. * 获取文件名称
  321. * @param unknown $file_name
  322. */
  323. public function getFileName($file_name)
  324. {
  325. return basename($file_name, "." . $this->getFileExt($file_name));
  326. }
  327. /**
  328. * 获取错误代码信息
  329. * @access private
  330. * @param int $errorNo 错误号
  331. * @return $this
  332. */
  333. private function error($errorNo)
  334. {
  335. switch ($errorNo) {
  336. case 1:
  337. case 2:
  338. $this->error = 'upload File size exceeds the maximum value';
  339. break;
  340. case 3:
  341. $this->error = 'only the portion of file is uploaded';
  342. break;
  343. case 4:
  344. $this->error = 'no file to uploaded';
  345. break;
  346. case 6:
  347. $this->error = 'upload temp dir not found';
  348. break;
  349. case 7:
  350. $this->error = 'file write error';
  351. break;
  352. default:
  353. $this->error = 'unknown upload error';
  354. }
  355. return $this;
  356. }
  357. /**
  358. * @param $path
  359. * @return bool
  360. */
  361. public function checkAll($path, $savename){
  362. // 文件上传失败,捕获错误代码
  363. if (!empty($this->info['error'])) {
  364. $this->error($this->info['error']);
  365. return false;
  366. }
  367. // 验证上传
  368. if (!$this->check()) {
  369. return false;
  370. }
  371. $path = rtrim($path, "/") . "/";
  372. // 文件保存命名规则(有外部传入)
  373. $filename = $path . $savename;
  374. // 检测目录
  375. if (false === $this->checkPath(dirname($filename))) {
  376. return false;
  377. }
  378. return true;
  379. }
  380. }