FileService.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: pengyong <i@pengyong.info>
  10. // +----------------------------------------------------------------------
  11. namespace crmeb\services;
  12. class FileService
  13. {
  14. /*
  15. @function 创建目录
  16. @var:$filename 目录名
  17. @return: true
  18. */
  19. static public function mk_dir($dir)
  20. {
  21. $dir = rtrim($dir, '/') . '/';
  22. if (!is_dir($dir)) {
  23. if (mkdir($dir, 0700) == false) {
  24. return false;
  25. }
  26. return true;
  27. }
  28. return true;
  29. }
  30. /*
  31. @function 写文件
  32. @var:$filename 文件名
  33. @var:$writetext 文件内容
  34. @var:$openmod 打开方式
  35. @return: 成功=true
  36. */
  37. static function write_file($filename, $writetext, $openmod = 'w')
  38. {
  39. if (!self::checkPath($filename)) {
  40. return false;
  41. }
  42. if (!self::checkContent($writetext)) {
  43. return false;
  44. }
  45. if (@$fp = fopen($filename, $openmod)) {
  46. flock($fp, 2);
  47. fwrite($fp, $writetext);
  48. fclose($fp);
  49. return true;
  50. } else {
  51. return false;
  52. }
  53. }
  54. /*
  55. @function 删除目录
  56. @var:$dirName 原目录
  57. @return: 成功=true
  58. */
  59. static function del_dir($dirName)
  60. {
  61. if (!file_exists($dirName)) {
  62. return false;
  63. }
  64. $dir = opendir($dirName);
  65. while ($fileName = readdir($dir)) {
  66. $file = $dirName . '/' . $fileName;
  67. if ($fileName != '.' && $fileName != '..') {
  68. if (is_dir($file)) {
  69. self::del_dir($file);
  70. } else {
  71. unlink($file);
  72. }
  73. }
  74. }
  75. closedir($dir);
  76. return rmdir($dirName);
  77. }
  78. /*
  79. @function 复制目录
  80. @var:$surDir 原目录
  81. @var:$toDir 目标目录
  82. @return: true
  83. */
  84. public function copy_dir($surDir, $toDir)
  85. {
  86. $surDir = rtrim($surDir, '/') . '/';
  87. $toDir = rtrim($toDir, '/') . '/';
  88. if (!file_exists($surDir)) {
  89. return false;
  90. }
  91. if (!file_exists($toDir)) {
  92. $this->create_dir($toDir);
  93. }
  94. $file = opendir($surDir);
  95. while ($fileName = readdir($file)) {
  96. $file1 = $surDir . '/' . $fileName;
  97. $file2 = $toDir . '/' . $fileName;
  98. if ($fileName != '.' && $fileName != '..') {
  99. if (is_dir($file1)) {
  100. self::copy_dir($file1, $file2);
  101. } else {
  102. copy($file1, $file2);
  103. }
  104. }
  105. }
  106. closedir($file);
  107. return true;
  108. }
  109. /*
  110. @function 列出目录
  111. @var:$dir 目录名
  112. @return: 目录数组
  113. 列出文件夹下内容,返回数组 $dirArray['dir']:存文件夹;$dirArray['file']:存文件
  114. */
  115. static function get_dirs($dir)
  116. {
  117. $dir = rtrim($dir, '/') . '/';
  118. $dirArray [][] = NULL;
  119. if (false != ($handle = opendir($dir))) {
  120. $i = 0;
  121. $j = 0;
  122. while (false !== ($file = readdir($handle))) {
  123. if (is_dir($dir . $file)) { //判断是否文件夹
  124. $dirArray ['dir'] [$i] = $file;
  125. $i++;
  126. } else {
  127. $dirArray ['file'] [$j] = $file;
  128. $j++;
  129. }
  130. }
  131. closedir($handle);
  132. }
  133. return $dirArray;
  134. }
  135. /*
  136. @function 统计文件夹大小
  137. @var:$dir 目录名
  138. @return: 文件夹大小(单位 B)
  139. */
  140. static function get_size($dir)
  141. {
  142. $dirlist = opendir($dir);
  143. $dirsize = 0;
  144. while (false !== ($folderorfile = readdir($dirlist))) {
  145. if ($folderorfile != "." && $folderorfile != "..") {
  146. if (is_dir("$dir/$folderorfile")) {
  147. $dirsize += self::get_size("$dir/$folderorfile");
  148. } else {
  149. $dirsize += filesize("$dir/$folderorfile");
  150. }
  151. }
  152. }
  153. closedir($dirlist);
  154. return $dirsize;
  155. }
  156. /*
  157. @function 检测是否为空文件夹
  158. @var:$dir 目录名
  159. @return: 存在则返回true
  160. */
  161. static function empty_dir($dir)
  162. {
  163. return (($files = @scandir($dir)) && count($files) <= 2);
  164. }
  165. /**
  166. * 创建多级目录
  167. * @param string $dir
  168. * @param int $mode
  169. * @return boolean
  170. */
  171. public function create_dir($dir, $mode = 0777)
  172. {
  173. return is_dir($dir) or ($this->create_dir(dirname($dir)) and mkdir($dir, $mode));
  174. }
  175. /**
  176. * 创建指定路径下的指定文件
  177. * @param string $path (需要包含文件名和后缀)
  178. * @param boolean $over_write 是否覆盖文件
  179. * @param int $time 设置时间。默认是当前系统时间
  180. * @param int $atime 设置访问时间。默认是当前系统时间
  181. * @return boolean
  182. */
  183. public function create_file($path, $over_write = FALSE, $time = NULL, $atime = NULL)
  184. {
  185. $path = $this->dir_replace($path);
  186. $time = empty($time) ? time() : $time;
  187. $atime = empty($atime) ? time() : $atime;
  188. if (file_exists($path) && $over_write) {
  189. $this->unlink_file($path);
  190. }
  191. $aimDir = dirname($path);
  192. $this->create_dir($aimDir);
  193. return touch($path, $time, $atime);
  194. }
  195. /**
  196. * 关闭文件操作
  197. * @param string $path
  198. * @return boolean
  199. */
  200. public function close($path)
  201. {
  202. return fclose($path);
  203. }
  204. /**
  205. * 读取文件操作
  206. * @param string $file
  207. * @return boolean
  208. */
  209. public static function read_file($file)
  210. {
  211. return @file_get_contents($file);
  212. }
  213. /**
  214. * 确定服务器的最大上传限制(字节数)
  215. * @return int 服务器允许的最大上传字节数
  216. */
  217. public function allow_upload_size()
  218. {
  219. $val = trim(ini_get('upload_max_filesize'));
  220. return $val;
  221. }
  222. /**
  223. * 字节格式化 把字节数格式为 B K M G T P E Z Y 描述的大小
  224. * @param int $size 大小
  225. * @param int $dec 显示类型
  226. * @return int
  227. */
  228. public static function byte_format($size, $dec = 2)
  229. {
  230. $a = array("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB");
  231. $pos = 0;
  232. while ($size >= 1024) {
  233. $size /= 1024;
  234. $pos++;
  235. }
  236. return round($size, $dec) . " " . $a[$pos];
  237. }
  238. /**
  239. * 删除非空目录
  240. * 说明:只能删除非系统和特定权限的文件,否则会出现错误
  241. * @param string $dirName 目录路径
  242. * @param boolean $is_all 是否删除所有
  243. * @param boolean $del_dir 是否删除目录
  244. * @return boolean
  245. */
  246. public function remove_dir($dir_path, $is_all = FALSE)
  247. {
  248. $dirName = $this->dir_replace($dir_path);
  249. $handle = @opendir($dirName);
  250. while (($file = @readdir($handle)) !== FALSE) {
  251. if ($file != '.' && $file != '..') {
  252. $dir = $dirName . '/' . $file;
  253. if ($is_all) {
  254. is_dir($dir) ? $this->remove_dir($dir) : $this->unlink_file($dir);
  255. } else {
  256. if (is_file($dir)) {
  257. $this->unlink_file($dir);
  258. }
  259. }
  260. }
  261. }
  262. closedir($handle);
  263. return @rmdir($dirName);
  264. }
  265. /**
  266. * 获取完整文件名
  267. * @param string $fn 路径
  268. * @return string
  269. */
  270. public function get_basename($file_path)
  271. {
  272. $file_path = $this->dir_replace($file_path);
  273. return basename(str_replace('\\', '/', $file_path));
  274. //return pathinfo($file_path,PATHINFO_BASENAME);
  275. }
  276. /**
  277. * 获取文件后缀名
  278. * @param string $file_name 文件路径
  279. * @return string
  280. */
  281. public static function get_ext($file)
  282. {
  283. $file = self::dir_replace($file);
  284. //return strtolower(substr(strrchr(basename($file), '.'),1));
  285. //return end(explode(".",$filename ));
  286. //return strtolower(trim(array_pop(explode('.', $file))));//取得后缀
  287. //return preg_replace('/.*\.(.*[^\.].*)*/iU','\\1',$file);
  288. return pathinfo($file, PATHINFO_EXTENSION);
  289. }
  290. /**
  291. * 取得指定目录名称
  292. * @param string $path 文件路径
  293. * @param int $num 需要返回以上级目录的数
  294. * @return string
  295. */
  296. public function father_dir($path, $num = 1)
  297. {
  298. $path = $this->dir_replace($path);
  299. $arr = explode('/', $path);
  300. if ($num == 0 || count($arr) < $num) return pathinfo($path, PATHINFO_BASENAME);
  301. return substr(strrev($path), 0, 1) == '/' ? $arr[(count($arr) - (1 + $num))] : $arr[(count($arr) - $num)];
  302. }
  303. /**
  304. * 删除文件
  305. * @param string $path
  306. * @return boolean
  307. */
  308. public function unlink_file($path)
  309. {
  310. $path = $this->dir_replace($path);
  311. if (file_exists($path)) {
  312. return unlink($path);
  313. }
  314. }
  315. /**
  316. * 文件操作(复制/移动)
  317. * @param string $old_path 指定要操作文件路径(需要含有文件名和后缀名)
  318. * @param string $new_path 指定新文件路径(需要新的文件名和后缀名)
  319. * @param string $type 文件操作类型
  320. * @param boolean $overWrite 是否覆盖已存在文件
  321. * @return boolean
  322. */
  323. public function handle_file($old_path, $new_path, $type = 'copy', $overWrite = FALSE)
  324. {
  325. $old_path = $this->dir_replace($old_path);
  326. $new_path = $this->dir_replace($new_path);
  327. if (file_exists($new_path) && $overWrite = FALSE) {
  328. return FALSE;
  329. } else if (file_exists($new_path) && $overWrite = TRUE) {
  330. $this->unlink_file($new_path);
  331. }
  332. $aimDir = dirname($new_path);
  333. $this->create_dir($aimDir);
  334. switch ($type) {
  335. case 'copy':
  336. return copy($old_path, $new_path);
  337. break;
  338. case 'move':
  339. return @rename($old_path, $new_path);
  340. break;
  341. }
  342. }
  343. /**
  344. * 文件夹操作(复制/移动)
  345. * @param string $old_path 指定要操作文件夹路径
  346. * @param string $aimDir 指定新文件夹路径
  347. * @param string $type 操作类型
  348. * @param boolean $overWrite 是否覆盖文件和文件夹
  349. * @return boolean
  350. */
  351. public function handle_dir($old_path, $new_path, $type = 'copy', $overWrite = FALSE)
  352. {
  353. $new_path = $this->check_path($new_path);
  354. $old_path = $this->check_path($old_path);
  355. if (!is_dir($old_path)) return FALSE;
  356. if (!file_exists($new_path)) $this->create_dir($new_path);
  357. $dirHandle = opendir($old_path);
  358. if (!$dirHandle) return FALSE;
  359. $boolean = TRUE;
  360. while (FALSE !== ($file = readdir($dirHandle))) {
  361. if ($file == '.' || $file == '..') continue;
  362. if (!is_dir($old_path . $file)) {
  363. $boolean = $this->handle_file($old_path . $file, $new_path . $file, $type, $overWrite);
  364. } else {
  365. $this->handle_dir($old_path . $file, $new_path . $file, $type, $overWrite);
  366. }
  367. }
  368. switch ($type) {
  369. case 'copy':
  370. closedir($dirHandle);
  371. return $boolean;
  372. break;
  373. case 'move':
  374. closedir($dirHandle);
  375. return @rmdir($old_path);
  376. break;
  377. }
  378. }
  379. /**
  380. * 替换相应的字符
  381. * @param string $path 路径
  382. * @return string
  383. */
  384. public static function dir_replace($path)
  385. {
  386. return str_replace('//', '/', str_replace('\\', '/', $path));
  387. }
  388. /**
  389. * 读取指定路径下模板文件
  390. * @param string $path 指定路径下的文件
  391. * @return string $rstr
  392. */
  393. public static function get_templtes($path)
  394. {
  395. $path = self::dir_replace($path);
  396. if (file_exists($path)) {
  397. $fp = fopen($path, 'r');
  398. $rstr = fread($fp, filesize($path));
  399. fclose($fp);
  400. return $rstr;
  401. } else {
  402. return '';
  403. }
  404. }
  405. /**
  406. * 文件重命名
  407. * @param string $oldname
  408. * @param string $newname
  409. */
  410. public function rename($oldname, $newname)
  411. {
  412. if (($newname != $oldname) && is_writable($oldname)) {
  413. return rename($oldname, $newname);
  414. }
  415. }
  416. /**
  417. * 获取指定路径下的信息
  418. * @param string $dir 路径
  419. * @return ArrayObject
  420. */
  421. public function get_dir_info($dir)
  422. {
  423. $handle = @opendir($dir);//打开指定目录
  424. $directory_count = 0;
  425. $total_size = 0;
  426. $file_cout = 0;
  427. while (FALSE !== ($file_path = readdir($handle))) {
  428. if ($file_path != "." && $file_path != "..") {
  429. //is_dir("$dir/$file_path") ? $sizeResult += $this->get_dir_size("$dir/$file_path") : $sizeResult += filesize("$dir/$file_path");
  430. $next_path = $dir . '/' . $file_path;
  431. if (is_dir($next_path)) {
  432. $directory_count++;
  433. $result_value = self::get_dir_info($next_path);
  434. $total_size += $result_value['size'];
  435. $file_cout += $result_value['filecount'];
  436. $directory_count += $result_value['dircount'];
  437. } elseif (is_file($next_path)) {
  438. $total_size += filesize($next_path);
  439. $file_cout++;
  440. }
  441. }
  442. }
  443. closedir($handle);//关闭指定目录
  444. $result_value['size'] = $total_size;
  445. $result_value['filecount'] = $file_cout;
  446. $result_value['dircount'] = $directory_count;
  447. return $result_value;
  448. }
  449. /**
  450. * 指定文件编码转换
  451. * @param string $path 文件路径
  452. * @param string $input_code 原始编码
  453. * @param string $out_code 输出编码
  454. * @return boolean
  455. */
  456. public function change_file_code($path, $input_code, $out_code)
  457. {
  458. if (is_file($path))//检查文件是否存在,如果存在就执行转码,返回真
  459. {
  460. $content = file_get_contents($path);
  461. $content = string::chang_code($content, $input_code, $out_code);
  462. $fp = fopen($path, 'w');
  463. return fputs($fp, $content) ? TRUE : FALSE;
  464. fclose($fp);
  465. }
  466. }
  467. /**
  468. * 指定目录下指定条件文件编码转换
  469. * @param string $dirname 目录路径
  470. * @param string $input_code 原始编码
  471. * @param string $out_code 输出编码
  472. * @param boolean $is_all 是否转换所有子目录下文件编码
  473. * @param string $exts 文件类型
  474. * @return boolean
  475. */
  476. public function change_dir_files_code($dirname, $input_code, $out_code, $is_all = TRUE, $exts = '')
  477. {
  478. if (is_dir($dirname)) {
  479. $fh = opendir($dirname);
  480. while (($file = readdir($fh)) !== FALSE) {
  481. if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) {
  482. continue;
  483. }
  484. $filepath = $dirname . '/' . $file;
  485. if (is_dir($filepath) && $is_all == TRUE) {
  486. $files = $this->change_dir_files_code($filepath, $input_code, $out_code, $is_all, $exts);
  487. } else {
  488. if ($this->get_ext($filepath) == $exts && is_file($filepath)) {
  489. $boole = $this->change_file_code($filepath, $input_code, $out_code, $is_all, $exts);
  490. if (!$boole) continue;
  491. }
  492. }
  493. }
  494. closedir($fh);
  495. return TRUE;
  496. } else {
  497. return FALSE;
  498. }
  499. }
  500. /**
  501. * 列出指定目录下符合条件的文件和文件夹
  502. * @param string $dirname 路径
  503. * @param boolean $is_all 是否列出子目录中的文件
  504. * @param string $exts 需要列出的后缀名文件
  505. * @param string $sort 数组排序
  506. * @return ArrayObject
  507. */
  508. public function list_dir_info($dirname, $is_all = FALSE, $exts = '', $sort = 'ASC')
  509. {
  510. //处理多于的/号
  511. $new = strrev($dirname);
  512. if (strpos($new, '/') == 0) {
  513. $new = substr($new, 1);
  514. }
  515. $dirname = strrev($new);
  516. $sort = strtolower($sort);//将字符转换成小写
  517. $files = array();
  518. $subfiles = array();
  519. if (is_dir($dirname)) {
  520. $fh = opendir($dirname);
  521. while (($file = readdir($fh)) !== FALSE) {
  522. if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) continue;
  523. $filepath = $dirname . '/' . $file;
  524. switch ($exts) {
  525. case '*':
  526. if (is_dir($filepath) && $is_all == TRUE) {
  527. $files = array_merge($files, self::list_dir_info($filepath, $is_all, $exts, $sort));
  528. }
  529. array_push($files, $filepath);
  530. break;
  531. case 'folder':
  532. if (is_dir($filepath) && $is_all == TRUE) {
  533. $files = array_merge($files, self::list_dir_info($filepath, $is_all, $exts, $sort));
  534. array_push($files, $filepath);
  535. } elseif (is_dir($filepath)) {
  536. array_push($files, $filepath);
  537. }
  538. break;
  539. case 'file':
  540. if (is_dir($filepath) && $is_all == TRUE) {
  541. $files = array_merge($files, self::list_dir_info($filepath, $is_all, $exts, $sort));
  542. } elseif (is_file($filepath)) {
  543. array_push($files, $filepath);
  544. }
  545. break;
  546. default:
  547. if (is_dir($filepath) && $is_all == TRUE) {
  548. $files = array_merge($files, self::list_dir_info($filepath, $is_all, $exts, $sort));
  549. } elseif (preg_match("/\.($exts)/i", $filepath) && is_file($filepath)) {
  550. array_push($files, $filepath);
  551. }
  552. break;
  553. }
  554. switch ($sort) {
  555. case 'asc':
  556. sort($files);
  557. break;
  558. case 'desc':
  559. rsort($files);
  560. break;
  561. case 'nat':
  562. natcasesort($files);
  563. break;
  564. }
  565. }
  566. closedir($fh);
  567. return $files;
  568. } else {
  569. return FALSE;
  570. }
  571. }
  572. /**
  573. * 返回指定路径的文件夹信息,其中包含指定路径中的文件和目录
  574. * @param string $dir
  575. * @return ArrayObject
  576. */
  577. public function dir_info($dir)
  578. {
  579. return scandir($dir);
  580. }
  581. /**
  582. * 判断目录是否为空
  583. * @param string $dir
  584. * @return boolean
  585. */
  586. public function is_empty($dir)
  587. {
  588. $handle = opendir($dir);
  589. while (($file = readdir($handle)) !== false) {
  590. if ($file != '.' && $file != '..') {
  591. closedir($handle);
  592. return true;
  593. }
  594. }
  595. closedir($handle);
  596. return false;
  597. }
  598. /**
  599. * 返回指定文件和目录的信息
  600. * @param string $file
  601. * @return ArrayObject
  602. */
  603. public static function list_info($file)
  604. {
  605. $dir = array();
  606. $dir['filename'] = basename($file);//返回路径中的文件名部分。
  607. $dir['pathname'] = strstr(php_uname('s'), 'Windows') ? str_replace('\\', '\\\\', realpath($file)) : realpath($file);//返回绝对路径名。
  608. $dir['owner'] = fileowner($file);//文件的 user ID (所有者)。
  609. $dir['perms'] = fileperms($file);//返回文件的 inode 编号。
  610. $dir['inode'] = fileinode($file);//返回文件的 inode 编号。
  611. $dir['group'] = filegroup($file);//返回文件的组 ID。
  612. $dir['path'] = dirname($file);//返回路径中的目录名称部分。
  613. $dir['atime'] = fileatime($file);//返回文件的上次访问时间。
  614. $dir['ctime'] = filectime($file);//返回文件的上次改变时间。
  615. $dir['perms'] = fileperms($file);//返回文件的权限。
  616. $dir['size'] = self::byte_format(filesize($file), 2);//返回文件大小。
  617. $dir['type'] = filetype($file);//返回文件类型。
  618. $dir['ext'] = is_file($file) ? pathinfo($file, PATHINFO_EXTENSION) : '';//返回文件后缀名
  619. $dir['mtime'] = filemtime($file);//返回文件的上次修改时间。
  620. $dir['isDir'] = is_dir($file);//判断指定的文件名是否是一个目录。
  621. $dir['isFile'] = is_file($file);//判断指定文件是否为常规的文件。
  622. $dir['isLink'] = is_link($file);//判断指定的文件是否是连接。
  623. $dir['isReadable'] = is_readable($file);//判断文件是否可读。
  624. $dir['isWritable'] = is_writable($file);//判断文件是否可写。
  625. $dir['isUpload'] = is_uploaded_file($file);//判断文件是否是通过 HTTP POST 上传的。
  626. return $dir;
  627. }
  628. /**
  629. * 返回关于打开文件的信息
  630. * @param $file
  631. * @return ArrayObject
  632. * 数字下标 关联键名(自 PHP 4.0.6) 说明
  633. * 0 dev 设备名
  634. * 1 ino 号码
  635. * 2 mode inode 保护模式
  636. * 3 nlink 被连接数目
  637. * 4 uid 所有者的用户 id
  638. * 5 gid 所有者的组 id
  639. * 6 rdev 设备类型,如果是 inode 设备的话
  640. * 7 size 文件大小的字节数
  641. * 8 atime 上次访问时间(Unix 时间戳)
  642. * 9 mtime 上次修改时间(Unix 时间戳)
  643. * 10 ctime 上次改变时间(Unix 时间戳)
  644. * 11 blksize 文件系统 IO 的块大小
  645. * 12 blocks 所占据块的数目
  646. */
  647. public function open_info($file)
  648. {
  649. $file = fopen($file, "r");
  650. $result = fstat($file);
  651. fclose($file);
  652. return $result;
  653. }
  654. /**
  655. * 改变文件和目录的相关属性
  656. * @param string $file 文件路径
  657. * @param string $type 操作类型
  658. * @param string $ch_info 操作信息
  659. * @return boolean
  660. */
  661. public function change_file($file, $type, $ch_info)
  662. {
  663. switch ($type) {
  664. case 'group' :
  665. $is_ok = chgrp($file, $ch_info);//改变文件组。
  666. break;
  667. case 'mode' :
  668. $is_ok = chmod($file, $ch_info);//改变文件模式。
  669. break;
  670. case 'ower' :
  671. $is_ok = chown($file, $ch_info);//改变文件所有者。
  672. break;
  673. }
  674. }
  675. /**
  676. * 取得文件路径信息
  677. * @param $full_path 完整路径
  678. * @return ArrayObject
  679. */
  680. public function get_file_type($path)
  681. {
  682. //pathinfo() 函数以数组的形式返回文件路径的信息。
  683. //---------$file_info = pathinfo($path); echo file_info['extension'];----------//
  684. //extension取得文件后缀名【pathinfo($path,PATHINFO_EXTENSION)】-----dirname取得文件路径【pathinfo($path,PATHINFO_DIRNAME)】-----basename取得文件完整文件名【pathinfo($path,PATHINFO_BASENAME)】-----filename取得文件名【pathinfo($path,PATHINFO_FILENAME)】
  685. return pathinfo($path);
  686. }
  687. /**
  688. * 取得上传文件信息
  689. * @param $file file属性信息
  690. * @return array
  691. */
  692. public function get_upload_file_info($file)
  693. {
  694. $file_info = $_FILES[$file];//取得上传文件基本信息
  695. $info = array();
  696. $info['type'] = strtolower(trim(stripslashes(preg_replace("/^(.+?);.*$/", "\\1", $file_info['type'])), '"'));//取得文件类型
  697. $info['temp'] = $file_info['tmp_name'];//取得上传文件在服务器中临时保存目录
  698. $info['size'] = $file_info['size'];//取得上传文件大小
  699. $info['error'] = $file_info['error'];//取得文件上传错误
  700. $info['name'] = $file_info['name'];//取得上传文件名
  701. $info['ext'] = $this->get_ext($file_info['name']);//取得上传文件后缀
  702. return $info;
  703. }
  704. /**
  705. * 设置文件命名规则
  706. * @param string $type 命名规则
  707. * @param string $filename 文件名
  708. * @return string
  709. */
  710. public function set_file_name($type)
  711. {
  712. switch ($type) {
  713. case 'hash' :
  714. $new_file = md5(uniqid(mt_rand()));//mt_srand()以随机数md5加密来命名
  715. break;
  716. case 'time' :
  717. $new_file = time();
  718. break;
  719. default :
  720. $new_file = date($type, time());//以时间格式来命名
  721. break;
  722. }
  723. return $new_file;
  724. }
  725. /**
  726. * 文件保存路径处理
  727. * @return string
  728. */
  729. public function check_path($path)
  730. {
  731. return (preg_match('/\/$/', $path)) ? $path : $path . '/';
  732. }
  733. /**
  734. * 文件下载
  735. * $save_dir 保存路径
  736. * $filename 文件名
  737. * @return array
  738. */
  739. public static function down_remote_file($url, $save_dir = '', $filename = '', $type = 0)
  740. {
  741. if (trim($url) == '') {
  742. return array('file_name' => '', 'save_path' => '', 'error' => 1);
  743. }
  744. if (trim($save_dir) == '') {
  745. $save_dir = './';
  746. }
  747. if (trim($filename) == '') {//保存文件名
  748. $ext = strrchr($url, '.');
  749. // if($ext!='.gif'&&$ext!='.jpg'){
  750. // return array('file_name'=>'','save_path'=>'','error'=>3);
  751. // }
  752. $filename = time() . $ext;
  753. }
  754. if (0 !== strrpos($save_dir, '/')) {
  755. $save_dir .= '/';
  756. }
  757. //创建保存目录
  758. if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
  759. return array('file_name' => '', 'save_path' => '', 'error' => 5);
  760. }
  761. //获取远程文件所采用的方法
  762. if ($type) {
  763. $ch = curl_init();
  764. $timeout = 5;
  765. curl_setopt($ch, CURLOPT_URL, $url);
  766. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  767. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  768. $img = curl_exec($ch);
  769. curl_close($ch);
  770. } else {
  771. ob_start();
  772. readfile($url);
  773. $img = ob_get_contents();
  774. ob_end_clean();
  775. }
  776. //$size=strlen($img);
  777. //文件大小
  778. $fp2 = fopen($save_dir . $filename, 'a');
  779. fwrite($fp2, $img);
  780. fclose($fp2);
  781. unset($img, $url);
  782. return array('file_name' => $filename, 'save_path' => $save_dir . $filename, 'error' => 0);
  783. }
  784. public static function zipopen($filename, $savename)
  785. {
  786. $zip = new \ZipArchive;
  787. $zipfile = $filename;
  788. $res = $zip->open($zipfile);
  789. $toDir = $savename;
  790. if (!file_exists($toDir)) mkdir($toDir, 0777);
  791. $docnum = $zip->numFiles;
  792. for ($i = 0; $i < $docnum; $i++) {
  793. $statInfo = $zip->statIndex($i);
  794. if ($statInfo['crc'] == 0 && $statInfo['comp_size'] != 2) {
  795. //新建目录
  796. mkdir($toDir . '/' . substr($statInfo['name'], 0, -1), 0777);
  797. } else {
  798. //拷贝文件
  799. copy('zip://' . $zipfile . '#' . $statInfo['name'], $toDir . '/' . $statInfo['name']);
  800. }
  801. }
  802. $zip->close();
  803. return true;
  804. }
  805. /**
  806. *设置字体格式
  807. * @param $title string 必选
  808. * return string
  809. */
  810. public static function setUtf8($title)
  811. {
  812. return iconv('utf-8', 'gb2312', $title);
  813. }
  814. /**
  815. *检查指定文件是否能写入
  816. * @param $file string 必选
  817. * return boole
  818. */
  819. public static function isWritable($file)
  820. {
  821. $file = str_replace('\\', '/', $file);
  822. if (!file_exists($file)) return false;
  823. return is_writable($file);
  824. }
  825. /**
  826. * 验证目录结构中是否包含特殊字符
  827. * @param $path
  828. * @return bool
  829. */
  830. public static function checkPath($path)
  831. {
  832. $str = ['/%00/', '"/\/|\~|\,|\。|\!|\?|\“|\”|\【|\】|\『|\』|\:|\;|\《|\》|\’|\‘|\ |\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\+|\{|\}|\:|\<|\>|\?|\[|\]|\,|\/|\;|\'|\`|\=|\\\|\|/"'];
  833. foreach ($str as $value) {
  834. if (preg_match($value, $path)) {
  835. return false;
  836. }
  837. }
  838. return true;
  839. }
  840. /**
  841. * 验证文件内容中可能存在的shell
  842. * @param $content
  843. * @return bool
  844. */
  845. public static function checkContent($content)
  846. {
  847. //加密类型shell
  848. if ((preg_match('#(\$\w{2,4}\s?=\s?str_replace\("\w+","","[\w_]+"\);\s?)+#s', $content) && preg_match('#(\$\w{2,4}\s?=\s?"[\w\d\+\/\=]+";\s?)+#', $content) && preg_match('#\$[\w]{2,4}\s?=\s\$[\w]{2,4}\(\'\',\s?\$\w{2,4}\(\$\w{2,4}\("\w{1,4}",\s?"",\s?\$\w{2,4}\.\$\w{2,4}\.\$\w{2,4}\.\$\w{2,4}\)\)\);\s+?\$\w{2,4}\(\)\;#', $content))
  849. ||
  850. (preg_match('#\$\w+\d\s?=\s?str_replace\(\"[\w\d]+\",\"\",\"[\w\d]+\"\);#s', $content) && preg_match('#\$\w+\s?=\s?\$[\w\d]+\(\'\',\s?\$[\w\d]+\(\$\w+\(\$\w+\(\"[[:punct:]]+\",\s?\"\",\s?\$\w+\.\$\w+\.\$\w+\.\$\w+\)\)\)\);\s?\$\w+\(\);#s', $content))
  851. ) {
  852. return false;
  853. }
  854. //回调类型
  855. if (preg_match('#\$\w+\s?=\s?\$_(?:GET|POST|REQUEST|COOKIE|SERVER)\[.*?\]#is', $content) &&
  856. preg_match('#\$\w+\s?=\s?(?:new)?\s?array\w*\s?\(.*?_(?:GET|POST|REQUEST|COOKIE|SERVER)\[.*?\].*?\)+#is', $content) &&
  857. preg_match('#(?:array_(?:reduce|map|udiff|walk|walk_recursive|filter)|u[ak]sort)\s?\(.*?\)+?#is', $content)
  858. ) {
  859. return false;
  860. }
  861. //内容过滤
  862. $matches = [
  863. '/mb_ereg_replace\([\'\*\s\,\.\"]+\$_(?:GET|POST|REQUEST|COOKIE|SERVER)\[[\'\"].*?[\'\"][\]][\,\s\'\"]+e[\'\"]/is',
  864. '/preg_filter\([\'\"\|\.\*e]+.*\$_(?:GET|POST|REQUEST|COOKIE|SERVER)/is',
  865. '/create_function\s?\(.*assert\(/is',
  866. '/ini_get\(\'safe_mode\'\)/i',
  867. '/get_current_user\(.*?\)/i',
  868. '/@?assert\s?\(\$.*?\)/i',
  869. '/proc_open\s?\(.*?pipe\',\s?\'w\'\)/is',
  870. '/sTr_RepLaCe\s?\([\'\"].*?[\'\"],[\'\"].*?[\'\"]\s?,\s?\'a[[:alnum:][:punct:]]+?s[[:alnum:][:punct:]]+?s[[:alnum:][:punct:]]+?e[[:alnum:][:punct:]]+?r[[:alnum:][:punct:]]+?t[[:alnum:][:punct:]]+?\)/i',
  871. '/preg_replace_callback\(.*?create_function\(/is',
  872. '/filter_var(?:_array)?\s?.*?\$_(?:GET|POST|REQUEST|COOKIE|SERVER)\[[\'\"][[:punct:][:alnum:]]+[\'\"]\][[:punct:][:alnum:][:space:]]+?assert[\'\"]\)/is',
  873. '/ob_start\([\'\"]+assert[\'\"]+\)/is',
  874. '/new\s?ReflectionFunction\(.*?->invoke\(/is',
  875. '/PDO::FETCH_FUNC/',
  876. '/\$\w+.*\s?(?:=|->)\s?.*?[\'\"]assert[\'\"]\)?/i',
  877. '/\$\w+->(?:sqlite)?createFunction\(.*?\)/i',
  878. '/eval\([\"\']?\\\?\$\w+\s?=\s?.*?\)/i',
  879. '/eval\(.*?gzinflate\(base64_decode\(/i',
  880. '/copy\(\$HTTP_POST_FILES\[\'\w+\'\]\s?\[\'tmp_name\'\]/i',
  881. '/register_(?:shutdown|tick)_function\s?\(\$\w+,\s\$_(?:GET|POST|REQUEST|COOKIE|SERVER)\[.*?\]\)/is',
  882. '/register_(?:shutdown|tick)_function\s?\(?[\'\"]assert[\"\'].*?\)/i',
  883. '/call_user_func.*?\([\"|\']assert[\"|\'],.*\$_(?:GET|POST|REQUEST|COOKIE|SERVER)\[[\'|\"].*\]\)+/is',
  884. '/preg_replace\(.*?e.*?\'\s?,\s?.*?\w+\(.*?\)/i',
  885. '/function_exists\s*\(\s*[\'|\"](popen|exec|proc_open|system|passthru)+[\'|\"]\s*\)/i',
  886. '/(exec|shell_exec|system|passthru)+\s*\(\s*\$_(\w+)\[(.*)\]\s*\)/i',
  887. '/(exec|shell_exec|system|passthru)+\s*\(\$\w+\)/i',
  888. '/(exec|shell_exec|system|passthru)\s?\(\w+\(\"http_.*\"\)\)/i',
  889. '/(?:john\.barker446@gmail\.com|xb5@hotmail\.com|shopen@aventgrup\.net|milw0rm\.com|www\.aventgrup\.net|mgeisler@mgeisler\.net)/i',
  890. '/Php\s*?Shell/i',
  891. '/((udp|tcp)\:\/\/(.*)\;)+/i',
  892. '/preg_replace\s*\((.*)\/e(.*)\,\s*\$_(.*)\,(.*)\)/i',
  893. '/preg_replace\s*\((.*)\(base64_decode\(\$/i',
  894. '/(eval|assert|include|require|include_once|require_once)+\s*\(\s*(base64_decode|str_rot13|gz(\w+)|file_(\w+)_contents|(.*)php\:\/\/input)+/i',
  895. '/(eval|assert|include|require|include_once|require_once|array_map|array_walk)+\s*\(.*?\$_(?:GET|POST|REQUEST|COOKIE|SERVER|SESSION)+\[(.*)\]\s*\)/i',
  896. '/eval\s*\(\s*\(\s*\$\$(\w+)/i',
  897. '/((?:include|require|include_once|require_once)+\s*\(?\s*[\'|\"]\w+\.(?!php).*[\'|\"])/i',
  898. '/\$_(\w+)(.*)(eval|assert|include|require|include_once|require_once)+\s*\(\s*\$(\w+)\s*\)/i',
  899. '/\(\s*\$_FILES\[(.*)\]\[(.*)\]\s*\,\s*\$_(GET|POST|REQUEST|FILES)+\[(.*)\]\[(.*)\]\s*\)/i',
  900. '/(fopen|fwrite|fputs|file_put_contents)+\s*\((.*)\$_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\](.*)\)/i',
  901. '/echo\s*curl_exec\s*\(\s*\$(\w+)\s*\)/i',
  902. '/new com\s*\(\s*[\'|\"]shell(.*)[\'|\"]\s*\)/i',
  903. '/\$(.*)\s*\((.*)\/e(.*)\,\s*\$_(.*)\,(.*)\)/i',
  904. '/\$_\=(.*)\$_/i',
  905. '/\$_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\(\s*\$(.*)\)/i',
  906. '/\$(\w+)\s*\(\s*\$_(GET|POST|REQUEST|COOKIE|SERVER)+\[(.*)\]\s*\)/i',
  907. '/\$(\w+)\s*\(\s*\$\{(.*)\}/i',
  908. '/\$(\w+)\s*\(\s*chr\(\d+\)/i'
  909. ];
  910. foreach ($matches as $value) {
  911. if (preg_match($value, $content)) {
  912. return false;
  913. }
  914. }
  915. return true;
  916. }
  917. }