PageRenderTime 44ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/qeephp/library/helper/uploader.php

https://gitlab.com/BGCX262/zys-blog-svn-to-git
PHP | 427 lines | 350 code | 12 blank | 65 comment | 8 complexity | d7188a130f67d9407e334914e73b9486 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. // $Id: uploader.php 11 2012-02-08 06:05:02Z zys4416@gmail.com $
  3. /**
  4. * 定义 Helper_Uploader 类
  5. *
  6. * @link http://qeephp.com/
  7. * @copyright Copyright (c) 2006-2009 Qeeyuan Inc. {@link http://www.qeeyuan.com}
  8. * @license New BSD License {@link http://qeephp.com/license/}
  9. * @version $Id: uploader.php 11 2012-02-08 06:05:02Z zys4416@gmail.com $
  10. * @package helper
  11. */
  12. /**
  13. * Helper_Uploader 类封装了针对上传文件的操作
  14. *
  15. * @author YuLei Liao <liaoyulei@qeeyuan.com>
  16. * @version $Id: uploader.php 11 2012-02-08 06:05:02Z zys4416@gmail.com $
  17. * @package helper
  18. */
  19. class Helper_Uploader
  20. {
  21. /**
  22. * 所有的 Helper_Uploader_File 对象实例
  23. *
  24. * @var QColl
  25. */
  26. static protected $_files;
  27. /**
  28. * 指示是否已经完成了初始化
  29. *
  30. * @var boolean
  31. */
  32. static protected $_init = false;
  33. /**
  34. * 构造函数
  35. */
  36. function __construct()
  37. {
  38. if (self::$_init) return;
  39. self::$_init = true;
  40. self::$_files = new QColl('Helper_Uploader_File');
  41. foreach ($_FILES as $field_name => $postinfo)
  42. {
  43. if (!isset($postinfo['error'])) continue;
  44. if (is_array($postinfo['error']))
  45. {
  46. // 多文件上传
  47. foreach ($postinfo['error'] as $offset => $error)
  48. {
  49. if ($error == UPLOAD_ERR_OK)
  50. {
  51. $file = new Helper_Uploader_File($postinfo, $field_name, $offset);
  52. self::$_files["{$field_name}{$offset}"] = $file;
  53. }
  54. }
  55. }
  56. else
  57. {
  58. if ($postinfo['error'] == UPLOAD_ERR_OK)
  59. {
  60. self::$_files[$field_name] = new Helper_Uploader_File($postinfo, $field_name);
  61. }
  62. }
  63. }
  64. }
  65. /**
  66. * 确定服务器的最大上传限制(字节数)
  67. *
  68. * @return int 服务器允许的最大上传字节数
  69. */
  70. function allowedUploadSize()
  71. {
  72. $val = trim(ini_get('upload_max_filesize'));
  73. $last = strtolower($val{strlen($val) - 1});
  74. switch ($last)
  75. {
  76. case 'g':
  77. $val *= 1024;
  78. case 'm':
  79. $val *= 1024;
  80. case 'k':
  81. $val *= 1024;
  82. }
  83. return $val;
  84. }
  85. /**
  86. * 可用的上传文件对象数量
  87. *
  88. * @return int 上传文件对象数量
  89. */
  90. function filesCount()
  91. {
  92. return count(self::$_files);
  93. }
  94. /**
  95. * 获得所有上传文件对象
  96. *
  97. * @return array 包含所有上传文件对象的数组
  98. */
  99. function allFiles()
  100. {
  101. return self::$_files;
  102. }
  103. /**
  104. * 检查指定名字的上传对象是否存在
  105. *
  106. * @param string $name 要检查的名字
  107. *
  108. * @return boolean 指定名字的上传对象是否存在
  109. */
  110. function existsFile($name)
  111. {
  112. return isset(self::$_files[$name]);
  113. }
  114. /**
  115. * 取得指定名字的上传文件对象
  116. *
  117. * @param string $name 上传对象的名字
  118. *
  119. * @return Helper_Uploader_File 指定名字对应的文件对象
  120. */
  121. function file($name)
  122. {
  123. return self::$_files[$name];
  124. }
  125. /**
  126. * 移动所有上传文件到指定目录
  127. *
  128. * @param string $dest_dir 目的地目录
  129. */
  130. function moveAll($dest_dir)
  131. {
  132. $dest_dir = rtrim($dest_dir, '/\\') . DS;
  133. foreach (self::$_files as $file)
  134. {
  135. $dest = $dest_dir . $file->filename();
  136. $file->move($dest);
  137. }
  138. }
  139. }
  140. /**
  141. * Helper_Uploader 类封装一个上传的文件
  142. *
  143. * @author YuLei Liao <liaoyulei@qeeyuan.com>
  144. * @version $Id: uploader.php 11 2012-02-08 06:05:02Z zys4416@gmail.com $
  145. * @package helper
  146. */
  147. class Helper_Uploader_File
  148. {
  149. /**
  150. * 上传文件信息
  151. *
  152. * @var array
  153. */
  154. protected $_file = array();
  155. /**
  156. * 上传文件对象的名字
  157. *
  158. * @var string
  159. */
  160. protected $_name;
  161. /**
  162. * 构造函数
  163. *
  164. * @param array $struct 文件信息结构
  165. * @param string $name 上传对象名
  166. * @param int $ix 索引
  167. */
  168. function __construct(array $struct, $name, $ix = false)
  169. {
  170. if ($ix !== false)
  171. {
  172. $this->_file = array(
  173. 'name' => $struct['name'][$ix],
  174. 'type' => $struct['type'][$ix],
  175. 'tmp_name' => $struct['tmp_name'][$ix],
  176. 'error' => $struct['error'][$ix],
  177. 'size' => $struct['size'][$ix],
  178. );
  179. }
  180. else
  181. {
  182. $this->_file = $struct;
  183. }
  184. $this->_file['full_path'] = $this->_file['tmp_name'];
  185. $this->_file['is_moved'] = false;
  186. $this->_name = $name;
  187. }
  188. /**
  189. * 返回上传文件对象的名字
  190. *
  191. * @return string 上传对象名
  192. */
  193. function name()
  194. {
  195. return $this->_name;
  196. }
  197. /**
  198. * 指示上传是否成功
  199. *
  200. * @return boolean 指示上传是否成功
  201. */
  202. function isSuccessed()
  203. {
  204. return $this->_file['error'] == UPLOAD_ERR_OK;
  205. }
  206. /**
  207. * 返回上传错误代码
  208. *
  209. * @return int 上传错误代码
  210. */
  211. function errorCode()
  212. {
  213. return $this->_file['error'];
  214. }
  215. /**
  216. * 指示上传文件是否已经从临时目录移出
  217. *
  218. * @return boolean 指示文件是否已经移动
  219. */
  220. function isMoved()
  221. {
  222. return $this->_file['is_moved'];
  223. }
  224. /**
  225. * 返回上传文件的原名
  226. *
  227. * @return string 上传文件的原名
  228. */
  229. function filename()
  230. {
  231. return $this->_file['name'];
  232. }
  233. /**
  234. * 返回上传文件不带"."的扩展名
  235. *
  236. * @return string 上传文件的扩展名
  237. */
  238. function extname()
  239. {
  240. return pathinfo($this->filename(), PATHINFO_EXTENSION);
  241. }
  242. /**
  243. * 返回上传文件的大小(字节数)
  244. *
  245. * @return int 上传文件的大小
  246. */
  247. function filesize()
  248. {
  249. return $this->_file['size'];
  250. }
  251. /**
  252. * 返回上传文件的 MIME 类型(由浏览器提供,不可信)
  253. *
  254. * @return string 上传文件的 MIME 类型
  255. */
  256. function mimeType()
  257. {
  258. return $this->_file['type'];
  259. }
  260. /**
  261. * 返回上传文件的临时文件名
  262. *
  263. * @return string 上传文件的临时文件名
  264. */
  265. function tmpFilename()
  266. {
  267. return $this->_file['tmp_name'];
  268. }
  269. /**
  270. * 获得文件的完整路径
  271. *
  272. * @return string 文件的完整路径
  273. */
  274. function filepath()
  275. {
  276. return $this->_file['full_path'];
  277. }
  278. /**
  279. * 检查上传的文件是否成功上传,并符合检查条件(文件类型、最大尺寸)
  280. *
  281. * 文件类型以扩展名为准,多个扩展名以 , 分割,例如 “jpg, jpeg, png。”。
  282. *
  283. * 用法:
  284. * @code
  285. * // 检查文件类型和大小
  286. * if ($file->isValid('jpg, jpeg, png', 2048 * 1024))
  287. * {
  288. * ....
  289. * }
  290. * @endcode
  291. *
  292. * @param string $allowed_types 允许的扩展名
  293. * @param int $max_size 允许的最大上传字节数
  294. *
  295. * @return boolean 是否检查通过
  296. */
  297. function isValid($allowed_types = null, $max_size = null)
  298. {
  299. if (!$this->isSuccessed()) return false;
  300. if ($allowed_types)
  301. {
  302. $allowed_types = Q::normalize($allowed_types);
  303. foreach ($allowed_types as $offset => $extname)
  304. {
  305. if ($extname{0} == '.') $extname = substr($extname, 1);
  306. $allowed_types[$offset] = strtolower($extname);
  307. }
  308. $allowed_types = array_flip($allowed_types);
  309. // when upload filename is chinese, basename() only return extension name, it will be make mistake follow step
  310. //$filename = strtolower(basename($this->filename()));
  311. $filename = $this->filename(); // jerry2801
  312. $extnames = Q::normalize($filename, '.');
  313. array_shift($extnames);
  314. $passed = false;
  315. for ($i = count($extnames) - 1; $i >= 0; $i--)
  316. {
  317. $checking_ext = implode('.', array_slice($extnames, $i));
  318. if (isset($allowed_types[$checking_ext]))
  319. {
  320. $passed = true;
  321. break;
  322. }
  323. }
  324. if (!$passed) return false;
  325. }
  326. if ($max_size > 0 && ($this->filesize() > $max_size))
  327. {
  328. return false;
  329. }
  330. return true;
  331. }
  332. /**
  333. * 移动上传文件到指定位置和文件名
  334. *
  335. * @param string $dest_path 目的地路径
  336. *
  337. * @return Helper_Uploader_File 连贯接口
  338. */
  339. function move($dest_path)
  340. {
  341. if ($this->_file['is_moved'])
  342. {
  343. $ret = rename($this->filepath(), $dest_path);
  344. }
  345. else
  346. {
  347. $this->_file['is_moved'] = true;
  348. $ret = move_uploaded_file($this->filepath(), $dest_path);
  349. }
  350. if ($ret)
  351. {
  352. $this->_file['full_path'] = $dest_path;
  353. }
  354. return $this;
  355. }
  356. /**
  357. * 复制上传文件
  358. *
  359. * @param string $dest_path 目的地路径
  360. *
  361. * @return Helper_Uploader_File 连贯接口
  362. */
  363. function copy($dest_path)
  364. {
  365. copy($this->filepath(), $dest_path);
  366. return $this;
  367. }
  368. /**
  369. * 删除上传文件
  370. *
  371. * @return Helper_Uploader_File 连贯接口
  372. */
  373. function unlink()
  374. {
  375. unlink($this->filepath());
  376. return $this;
  377. }
  378. /**
  379. * 魔法方法
  380. *
  381. * @return string
  382. * @access private
  383. */
  384. function __toString()
  385. {
  386. return '';
  387. }
  388. }