Upload.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. <?php
  2. namespace Qii\Library;
  3. /**
  4. * Library upload_library
  5. * @author Jinhui Zhu <jinhui.zhu@live.cn>
  6. * @version 1.2
  7. *
  8. * 使用方法:
  9. * $libUpload = new \Qii\Library\Upload();
  10. * $libUpload->setAllowed(array('mp3', 'mp4'));
  11. * $uploaded_files = $libUpload->upload('file', array('path' => 'data/tmp',
  12. * 'maxSize' => 1024*1024,
  13. * 'maxFolder' => 100,
  14. * 'prefix' => '',
  15. * ));
  16. *
  17. */
  18. class Upload
  19. {
  20. const VERSION = '1.2';
  21. public $dir;
  22. public $name;
  23. public $allowed = array('jpg', 'gif', 'png');
  24. public $error;
  25. protected $errorMessage = array(
  26. 1 => '文件超出大小限制',
  27. 2 => '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值',
  28. 3 => '文件只有部分被上传',
  29. 4 => '没有文件被上传',
  30. 6 => '找不到临时文件夹',
  31. 7 => '文件写入失败',
  32. 8 => '上传被其它扩展中断'
  33. );
  34. public $mine = array (
  35. 'image/gif' => 'gif',
  36. 'image/jpeg' => 'jpg',
  37. 'image/bmp' => 'bmp',
  38. 'image/png' => 'png',
  39. 'image/tiff' => 'tiff',
  40. 'image/x-pict' => 'pict',
  41. 'image/x-photoshop' => 'psd',
  42. 'application/x-shockwave-flash' => 'swf',
  43. 'application/x-javascript' => 'js',
  44. 'application/pdf' => 'pdf',
  45. 'application/postscript' => 'ps',
  46. 'application/x-msmetafile' => 'wmf',
  47. 'application/x-httpd-php' => 'php',
  48. 'application/x-httpd-asp' => 'asp',
  49. 'application/x-httpd-aspx' => 'aspx',
  50. 'text/css' => 'css',
  51. 'text/ini' => 'ini',
  52. 'text/html' => 'html',
  53. 'text/plain' => 'txt',
  54. 'text/xml' => 'xml',
  55. 'text/wml' => 'wml',
  56. 'image/vnd.wap.wbmp' => 'wbmp',
  57. 'audio/midi' => 'mid',
  58. 'audio/wav' => 'wav',
  59. 'audio/mpeg' => 'mp3',
  60. 'audio/wma' => 'wma',
  61. 'video/x-msvideo' => 'avi',
  62. 'video/mpeg' => 'mpeg',
  63. 'video/quicktime' => 'mov',
  64. 'video/rm' => 'rm',
  65. 'video/rmvb' => 'rmvb',
  66. 'application/x-lha' => 'lzh',
  67. 'application/x-compress' => 'z',
  68. 'application/x-gtar' => 'gtar',
  69. 'application/x-gzip' => 'gzip',
  70. 'application/x-tar' => 'tar',
  71. 'application/bzip2' => 'bz2',
  72. 'application/zip' => 'zip',
  73. 'application/7z' => '7z',
  74. 'application/x-arj' => 'arj',
  75. 'application/x-rar-compressed' => 'rar',
  76. 'application/mac-binhex40' => 'hqx',
  77. 'application/x-stuffit' => 'sit',
  78. 'application/x-macbinary' => 'bin',
  79. 'text/x-uuencode' => 'uue',
  80. 'application/x-latex' => 'latex',
  81. 'application/x-tcl' => 'tcl',
  82. 'application/pgp' => 'pgp',
  83. 'application/x-msdownload' => 'exe',
  84. 'application/msword' => 'docx',
  85. 'application/rtf' => 'rtf',
  86. 'application/vnd.ms-excel' => 'xlsx',
  87. 'application/vnd.ms-powerpoint' => 'ppt',
  88. 'application/x-msaccess' => 'mdb',
  89. 'application/x-mswrite' => 'wri',
  90. 'application/octet-stream' => 'dll',
  91. 'application/x-bittorrent' => 'torrent',
  92. );
  93. public function __construct()
  94. {
  95. }
  96. /**
  97. * 设置允许上传的文件类型
  98. * @param array $array 允许上传的文件类型
  99. */
  100. public function setAllowed(array $array)
  101. {
  102. $this->allowed = $array;
  103. }
  104. /**
  105. * setError
  106. *
  107. * @param String $key
  108. * @param Mix $value
  109. */
  110. public function setError($key, $value)
  111. {
  112. $this->error[$key] = $value;
  113. }
  114. /**
  115. * 获取错误信息
  116. *
  117. * @param String $key
  118. * @return Mix
  119. */
  120. public function getError($key)
  121. {
  122. if (!empty($key)) {
  123. return $this->error[$key];
  124. }
  125. return $this->error;
  126. }
  127. /**
  128. * 上传过程中是否有错误
  129. */
  130. public function isError()
  131. {
  132. return count($this->error) > 0 ? true : false;
  133. }
  134. /**
  135. * 是否为二进制上传
  136. */
  137. public function isBinaryUpload()
  138. {
  139. return isset($_SERVER['HTTP_CONTENT_DISPOSITION'])
  140. && preg_match('/attachment;\s+name="(.+?)";\s+filename="(.+?)"/i',
  141. $_SERVER['HTTP_CONTENT_DISPOSITION']);
  142. }
  143. /**
  144. * html5上传
  145. */
  146. public function uploadBinary($configure)
  147. {
  148. $data = array();
  149. if(!is_array($configure) || empty($configure))
  150. {
  151. $data['code'] = 1406;
  152. $data['src'] = '';
  153. $data['msg'] = 'Configure file is empty';
  154. return $data;
  155. }
  156. //如果文件路径不存在就自动创建
  157. if (!is_dir($configure['path'])) {
  158. mkdir($configure['path'], 0777, true);
  159. }
  160. if (!isset($configure['prefix'])) $configure['prefix'] = '';
  161. $tmpFile = sys_get_temp_dir() . DS . time() . rand(10000, 1000000);
  162. if(isset($_SERVER['HTTP_CONTENT_DISPOSITION'])
  163. && preg_match('/attachment;\s+name="(.+?)";\s+filename="(.+?)"/i',
  164. $_SERVER['HTTP_CONTENT_DISPOSITION'],$info)
  165. )
  166. {
  167. file_put_contents($tmpFile, file_get_contents("php://input"));
  168. $name = urldecode($info[2]);
  169. }
  170. $file = array(
  171. 'binary' => true,
  172. 'name' => $name,
  173. 'type' => '',
  174. 'tmp_name' => $tmpFile,
  175. 'error' => 0,
  176. 'size' => filesize($tmpFile)
  177. );
  178. return $this->deal($file, $configure);
  179. }
  180. /**
  181. * 上传文件
  182. * @param $files
  183. * @param array $configure
  184. * @return array
  185. */
  186. protected function deal($files, $configure = array(), $index = 0)
  187. {
  188. $data = array();
  189. if(!is_array($configure) || empty($configure))
  190. {
  191. $data['code'] = 1406;
  192. $data['src'] = '';
  193. $data['msg'] = 'Configure file is empty';
  194. return $data;
  195. }
  196. if (is_array($files['name'])) {
  197. foreach ($files['name'] as $key => $value) {
  198. $file = array(
  199. 'name' => $files['name'][$key],
  200. 'type' => $files['type'][$key],
  201. 'tmp_name' => $files['tmp_name'][$key],
  202. 'error' => $files['error'][$key],
  203. 'size' => $files['size'][$key]
  204. );
  205. $data['files'][] = $this->deal($file, $configure, $key);
  206. }
  207. return $data;
  208. }
  209. if(!isset($files['binary'])) $files['binary'] = false;
  210. if ($files['error'] != UPLOAD_ERR_OK) {
  211. $data['code'] = $files['error'];
  212. $data['src'] = '';
  213. $data['msg'] = $this->errorMessage[$files['error']];
  214. $this->setError($index, 100008);
  215. return $data;
  216. }
  217. $extension = pathinfo($files['name'], PATHINFO_EXTENSION);
  218. if(!$extension){
  219. if(isset($this->mine[$files['type']]))
  220. {
  221. $extension = $this->mine[$files['type']];
  222. }
  223. }
  224. if(!in_array($extension, $this->allowed))
  225. {
  226. $data['code'] = 1407;
  227. $data['src'] = '';
  228. $data['msg'] = 'Not Allowed';
  229. return $data;
  230. return $data;
  231. }
  232. $extension = '.'. $extension;
  233. $fileName = rand(10000, 90000) . uniqid();
  234. $configure['fileName'] = $configure['prefix'] . $fileName . $extension;
  235. $subDir = $this->distribution($fileName, $configure['maxFolder']);
  236. $fillPath = $configure['path'];
  237. if (!empty($subDir)) {
  238. $fillPath = $fillPath . '/' . $subDir;
  239. }
  240. if (!is_dir($fillPath)) {
  241. if (!mkdir($fillPath, 0777, true)) {
  242. $data['code'] = 100007;
  243. $data['src'] = '';
  244. $data['msg'] = 'Access Denied';
  245. $this->setError($index, 100007);
  246. return $data;
  247. }
  248. }
  249. if($files['binary'])
  250. {
  251. $result = rename($files['tmp_name'], $fillPath . '/' . $configure['fileName']);
  252. }
  253. else
  254. {
  255. $result= move_uploaded_file($files['tmp_name'], $fillPath . '/' . $configure['fileName']);
  256. }
  257. if ($result) {
  258. $data['code'] = 0;
  259. $data['src'] = $fillPath . '/' . $configure['fileName'];
  260. } else {
  261. $data['src'] = '';
  262. $data['code'] = 100005;
  263. $data['msg'] = 100005;
  264. $this->setError($index, 100005);
  265. }
  266. return $data;
  267. }
  268. /**
  269. * 上传文件
  270. *
  271. * @param String $filed 上传文件域名称
  272. * @param Array $configure array('path' => 'data/tmp',
  273. * 'maxSize' => 1024*1024,
  274. * 'maxFolder' => 100);
  275. */
  276. public function upload($filed = 'upload', $configure)
  277. {
  278. $data = array();
  279. if ($_FILES[$filed]) {
  280. if (!is_dir($configure['path'])) {
  281. mkdir($configure['path'], 0777, true);
  282. }
  283. if (!isset($configure['prefix'])) $configure['prefix'] = '';
  284. return $this->deal($_FILES[$filed], $configure);
  285. }
  286. return $data;
  287. }
  288. /**
  289. * 自动重命名文件,如果没有指定目录就重命名,否则移动文件
  290. *
  291. * @param Mix $oldName 原始文件名
  292. * @param Mix $newName 新文件名
  293. * @param Bool $keepExtension 是否保持当前文件名
  294. * @return Array|String
  295. */
  296. public function rename($oldName, $newName, $keepExtension = false)
  297. {
  298. $path = array();
  299. if (is_array($oldName)) {
  300. foreach ($oldName AS $key => $val) {
  301. $path[] = autoRename($val, $newName[$key]);
  302. }
  303. } else {
  304. $oldNameArray = pathinfo($oldName);
  305. $newNameArray = pathinfo($newName);
  306. $dirName = $oldNameArray['dirname'];
  307. //如果第二个文件夹没有包含路径就直接重新命名,否则移动到新的路径下
  308. if ($newNameArray['dirname'] == substr($newName, 0, strlen($newNameArray['dirname']))) {
  309. $dirName = $newNameArray['dirname'];
  310. }
  311. $fileName = $oldNameArray['filename'];
  312. if ($newNameArray['filename']) {
  313. $fileName = $newNameArray['filename'];
  314. }
  315. $extension = '.' . $oldNameArray['extension'];
  316. if (!isset($newNameArray['extension']) && !$keepExtension) {
  317. $extension = '';
  318. }
  319. $newPath = $dirName . '/' . $fileName . $extension;
  320. rename($oldName, $newPath);
  321. return $newPath;
  322. }
  323. return $path;
  324. }
  325. /**
  326. * 过滤images
  327. *
  328. * @param Array $images
  329. * @return Array
  330. */
  331. public function filterImages($images)
  332. {
  333. $data = array();
  334. if (!is_array($images)) {
  335. return $data;
  336. }
  337. foreach ($images AS $image) {
  338. if (!empty($image)) $data[] = $image;
  339. }
  340. return $data;
  341. }
  342. /**
  343. * 根据配置文件批量缩放图片
  344. * @param $images 图片路径
  345. * @param $configure [{width: 100, height: 100}, ...]
  346. * @return array
  347. */
  348. public function autoResize($images, $configure)
  349. {
  350. $data = array();
  351. if (is_array($images)) {
  352. foreach ($images AS $image) {
  353. $data[] = $this->autoResize($image, $configure);
  354. }
  355. } else {
  356. $thumbs = array();
  357. foreach ($configure['size'] AS $key => $value) {
  358. $pathInfo = pathinfo($images);
  359. $thumbs[$key] = $small = $pathInfo['dirname'] . '/' . $pathInfo['filename'] . '.' . $key . '.' . $pathInfo['extension'];
  360. $this->imgCutScale($images, $small, $configure['size'][$key]['width'], $configure['size'][$key]['height']);
  361. $this->imgResizeSamll($small, $small, $configure['size'][$key]['width']);
  362. }
  363. return $thumbs;
  364. }
  365. return $data;
  366. }
  367. /**
  368. * 计算存放的文件夹
  369. *
  370. * @param String $fileName 文件名
  371. * @param Int $maxFolder 文件夹数量
  372. * @return String
  373. */
  374. public function distribution($fileName, $maxFolder = 100)
  375. {
  376. if (empty($maxFolder) || $maxFolder == 1) {
  377. return '';
  378. }
  379. $folder = ord($fileName) % $maxFolder;
  380. if ($folder == 0) {
  381. return $maxFolder;
  382. }
  383. return $folder;
  384. }
  385. /**
  386. * 图片缩放,等比缩放
  387. *
  388. * @param String $bigImg 原图
  389. * @param String $smallImg 缩放以后的图片
  390. * @param Int $width 宽度
  391. * @return Bool
  392. */
  393. public function imgResizeSmall($bigImg, $smallImg, $width = 392)
  394. {
  395. // 图片路径
  396. if (!file_exists($bigImg)) {
  397. $this->setError('img_resize_samll', $bigImg . "文件不存在");
  398. return false;
  399. } else {
  400. ini_set("memory_limit", "128M");
  401. $filename = $bigImg;
  402. // 获取原图片的尺寸
  403. list($widthOrig, $heightOrig) = getimagesize($filename);
  404. //根据比例,计算新图片的尺寸
  405. $height = ($width / $widthOrig) * $heightOrig;
  406. //新建一个真彩色图像
  407. $destImage = imagecreatetruecolor($width, $height);
  408. //从 JPEG 文件或 URL 新建一图像
  409. $imageInfo = getimagesize($bigImg);//获取大图信息
  410. switch ($imageInfo[2]) {//判断图像类型
  411. case 1:
  412. $image = imagecreatefromgif($bigImg);
  413. break;
  414. case 2:
  415. $image = imagecreatefromjpeg($bigImg);
  416. break;
  417. case 3:
  418. $image = imagecreatefrompng($bigImg);
  419. $color = imagecolorallocate($image, 255, 255, 255);
  420. imagecolortransparent($image, $color);
  421. imagefill($image, 0, 0, $color);
  422. break;
  423. default:
  424. $image = imagecreatefromjpeg($filename);
  425. break;
  426. }
  427. //重采样拷贝部分图像并调整大小
  428. imagecopyresampled($destImage, $image, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig);
  429. // 将图片保存到服务器
  430. imagejpeg($destImage, $smallImg, 100);
  431. //销毁图片,释放内存
  432. imagedestroy($destImage);
  433. return true;
  434. }
  435. }
  436. /**
  437. * 缩放并按给定长宽比裁切图片
  438. * @param string $bigImg 原图路径
  439. * @param string $smallImg 缩放以后的文件路径
  440. * @param int $width 缩放宽度
  441. * @param int $height 缩放高度
  442. */
  443. public function imgCutScale($bigImg, $smallImg = 'test.jpg', $width = 90, $height = 130)
  444. {
  445. if (!file_exists($bigImg)) {
  446. $this->setError('img_cut_scale', $bigImg . "文件不存在");
  447. return;
  448. }
  449. ini_set("memory_limit", "128M");
  450. //大图文件地址,缩略宽,缩略高,小图地址
  451. $image = getimagesize($bigImg);//获取大图信息
  452. switch ($image[2]) {//判断图像类型
  453. case 1:
  454. $im = imagecreatefromgif($bigImg);
  455. break;
  456. case 2:
  457. $im = imagecreatefromjpeg($bigImg);
  458. break;
  459. case 3:
  460. $im = imagecreatefrompng($bigImg);
  461. break;
  462. }
  463. $src_W = imagesx($im);//获取大图宽
  464. $src_H = imagesy($im);//获取大图高
  465. //计算比例
  466. //检查图片高度和宽度
  467. $srcScale = sprintf("%.2f", ($src_W / $src_H));//原图比例
  468. $destScale = sprintf("%.2f", ($width / $height));//缩略图比例
  469. //echo "<p>原始比例:".$srcScale.";目标比例".$destScale."</p>";
  470. if ($srcScale > $destScale) {
  471. //说明高度不够,就以高度为准
  472. $myH = $src_H;
  473. $myW = intval($src_H * ($width / $height));
  474. //获取开始位置
  475. $myY = 0;
  476. $myX = intval(($src_W - $myW) / 2);
  477. } elseif ($srcScale < $destScale) {
  478. //宽度不够就以宽度为准
  479. $myW = $src_W;
  480. $myH = intval($src_W * ($height / $width));
  481. $myX = 0;
  482. $myY = intval(($src_H - $myH) / 2);
  483. } else {
  484. if ($src_W > $src_H) {
  485. //echo "<p>case 1:</p>";
  486. $myH = $src_H;
  487. $myW = intval($src_H * ($width / $height));
  488. //获取开始位置
  489. $myY = 0;
  490. $myX = intval(($src_W - $myW) / 2);
  491. }
  492. if ($src_W < $src_H) {
  493. //echo "case 2";
  494. $myW = $src_W;
  495. $myH = intval($src_W * ($height / $width));
  496. $myX = 0;
  497. $myY = intval(($src_H - $myH) / 2);
  498. }
  499. }
  500. if ($src_W == $src_H) {
  501. $myW = intval($src_H * ($width / $height));
  502. $myH = $src_H;
  503. $myX = intval(($src_W - $myW) / 2);
  504. $myY = 0;
  505. }
  506. //echo "<p>SW:" . $src_W ."W:" .$myW . "</p><p>X".$myX."</p><p>SH".$src_H.";H:" . $myH ."<p>Y".$myY."</p>";
  507. //从中间截取图片
  508. $tn = imagecreatetruecolor($myW, $myH);//创建小图
  509. imagecopy($tn, $im, 0, 0, $myX, $myY, $myW, $myH);
  510. imagejpeg($tn, $smallImg, 100);//输出图像
  511. }
  512. /**
  513. *
  514. * 剪切圖片到指定大小
  515. * @param String $bigImg 原始圖片
  516. * @param Int $width 寬
  517. * @param Int $height高
  518. * @param String $smallImg 縮放後保存的圖片
  519. */
  520. public function imgCutSmall($bigImg, $smallImg, $width, $height)
  521. {
  522. if (!file_exists($bigImg)) {
  523. return;
  524. }
  525. ini_set("memory_limit", "128M");
  526. //大图文件地址,缩略宽,缩略高,小图地址
  527. $imgage = getimagesize($bigImg);//获取大图信息
  528. switch ($imgage[2]) {//判断图像类型
  529. case 1:
  530. $im = imagecreatefromgif($bigImg);
  531. break;
  532. case 2:
  533. $im = imagecreatefromjpeg($bigImg);
  534. break;
  535. case 3:
  536. $im = imagecreatefrompng($bigImg);
  537. break;
  538. }
  539. $src_W = imagesx($im);//获取大图宽
  540. $src_H = imagesy($im);//获取大图高
  541. $tn = imagecreatetruecolor($width, $height);//创建小图
  542. imagecopy($tn, $im, 0, 0, 0, 0, $width, $height);
  543. imagejpeg($tn, $smallImg, 100);//输出图像
  544. }
  545. /**
  546. * 按比例缩放图片并限制图片的最大宽度或高度
  547. * @param string $bigImg 原图地址
  548. * @param string $smallImg 缩略图地址
  549. * @param int $maxValue 最大宽高
  550. */
  551. public function imgResizeMaxSize($bigImg, $smallImg, $maxValue = 392)
  552. {
  553. // 图片路径
  554. if (!file_exists($bigImg)) {
  555. $this->setError('img_resize_samll', $bigImg . "文件不存在");
  556. return false;
  557. } else {
  558. ini_set("memory_limit", "128M");
  559. $filename = $bigImg;
  560. // 获取原图片的尺寸
  561. list($widthOrig, $heightOrig) = getimagesize($filename);
  562. $width = $widthOrig;
  563. $height = $heightOrig;
  564. //根据比例,计算新图片的尺寸
  565. if ($widthOrig > $heightOrig) {
  566. if ($widthOrig > $maxValue) {
  567. $width = $maxValue;
  568. $height = ($maxValue / $widthOrig) * $heightOrig;
  569. }
  570. } else {
  571. if ($heightOrig > $maxValue) {
  572. $height = $maxValue;
  573. $width = ($maxValue / $heightOrig) * $widthOrig;
  574. }
  575. }
  576. //$height = ($width / $widthOrig) * $heightOrig;
  577. //新建一个真彩色图像
  578. $destImage = imagecreatetruecolor($width, $height);
  579. //从 JPEG 文件或 URL 新建一图像
  580. $imageInfo = getimagesize($bigImg);//获取大图信息
  581. switch ($imageInfo[2]) {//判断图像类型
  582. case 1:
  583. $image = imagecreatefromgif($bigImg);
  584. break;
  585. case 2:
  586. $image = imagecreatefromjpeg($bigImg);
  587. break;
  588. case 3:
  589. $image = imagecreatefrompng($bigImg);
  590. $color = imagecolorallocate($image, 255, 255, 255);
  591. imagecolortransparent($image, $color);
  592. imagefill($image, 0, 0, $color);
  593. break;
  594. default:
  595. $image = imagecreatefromjpeg($filename);
  596. break;
  597. }
  598. //重采样拷贝部分图像并调整大小
  599. imagecopyresampled($destImage, $image, 0, 0, 0, 0, $width, $height, $widthOrig, $heightOrig);
  600. // 将图片保存到服务器
  601. imagejpeg($destImage, $smallImg, 100);
  602. //销毁图片,释放内存
  603. imagedestroy($destImage);
  604. return true;
  605. }
  606. }
  607. }
  608. ?>