Upload.php 8.8 KB

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