FileService.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace qiniu\services;
  12. use think\exception\ValidateException;
  13. /**
  14. * 文件操作类
  15. * Class FileService
  16. * @package crmeb\services
  17. */
  18. class FileService
  19. {
  20. /**
  21. * 创建目录
  22. * @param string $dir
  23. * @return bool
  24. */
  25. public static function mkDir(string $dir)
  26. {
  27. $dir = rtrim($dir, '/') . '/';
  28. if (!is_dir($dir)) {
  29. if (mkdir($dir, 0700) == false) {
  30. return false;
  31. }
  32. return true;
  33. }
  34. return true;
  35. }
  36. /**
  37. * @param string $filename 写入文件名
  38. * @param string $writetext 保存内容
  39. * @param string $openmod 打开方式
  40. * @return bool
  41. */
  42. public static function writeFile(string $filename, string $writetext, string $openmod = 'w')
  43. {
  44. if (@$fp = fopen($filename, $openmod)) {
  45. flock($fp, 2);
  46. fwrite($fp, $writetext);
  47. fclose($fp);
  48. return true;
  49. } else {
  50. return false;
  51. }
  52. }
  53. /**
  54. * 删除目录下所有满足条件文件
  55. * @param mixed $path 文件目录
  56. * @param mixed $start 开始时间
  57. * @param mixed $end 结束时间
  58. * return bool
  59. */
  60. public static function del_where_dir($path, $start = '', $end = '')
  61. {
  62. if (!file_exists($path)) {
  63. return false;
  64. }
  65. $dh = @opendir($path);
  66. if ($dh) {
  67. while (($d = readdir($dh)) !== false) {
  68. if ($d == '.' || $d == '..') {//如果为.或..
  69. continue;
  70. }
  71. $tmp = $path . '/' . $d;
  72. if (!is_dir($tmp)) {//如果为文件
  73. $file_time = filemtime($tmp);
  74. if ($file_time) {
  75. if ($start != '' && $end != '') {
  76. if ($file_time >= $start && $file_time <= $end) {
  77. @unlink($tmp);
  78. }
  79. } elseif ($start != '' && $end == '') {
  80. if ($file_time >= $start) {
  81. @unlink($tmp);
  82. }
  83. } elseif ($start == '' && $end != '') {
  84. if ($file_time <= $end) {
  85. @unlink($tmp);
  86. }
  87. } else {
  88. @unlink($tmp);
  89. }
  90. }
  91. } else {//如果为目录
  92. self::delDir($tmp);
  93. }
  94. }
  95. //判断文件夹下是否 还有文件
  96. $count = count(scandir($path));
  97. closedir($dh);
  98. if ($count <= 2) @rmdir($path);
  99. }
  100. return true;
  101. }
  102. /**
  103. * 删除目录
  104. * @param mixed $dirName
  105. * @return bool
  106. */
  107. public static function delDir($dirName)
  108. {
  109. if (!file_exists($dirName)) {
  110. return false;
  111. }
  112. $dir = opendir($dirName);
  113. while ($fileName = readdir($dir)) {
  114. $file = $dirName . '/' . $fileName;
  115. if ($fileName != '.' && $fileName != '..') {
  116. if (is_dir($file)) {
  117. self::delDir($file);
  118. } else {
  119. unlink($file);
  120. }
  121. }
  122. }
  123. closedir($dir);
  124. return rmdir($dirName);
  125. }
  126. /**
  127. * 拷贝目录
  128. * @param string $surDir
  129. * @param string $toDir
  130. * @return bool
  131. */
  132. public function copyDir(string $surDir, string $toDir)
  133. {
  134. $surDir = rtrim($surDir, '/') . '/';
  135. $toDir = rtrim($toDir, '/') . '/';
  136. if (!file_exists($surDir)) {
  137. return false;
  138. }
  139. if (!file_exists($toDir)) {
  140. $this->createDir($toDir);
  141. }
  142. $file = opendir($surDir);
  143. while ($fileName = readdir($file)) {
  144. $file1 = $surDir . '/' . $fileName;
  145. $file2 = $toDir . '/' . $fileName;
  146. if ($fileName != '.' && $fileName != '..') {
  147. if (is_dir($file1)) {
  148. $this->copyDir($file1, $file2);
  149. } else {
  150. copy($file1, $file2);
  151. }
  152. }
  153. }
  154. closedir($file);
  155. return true;
  156. }
  157. /**
  158. * 列出目录
  159. * @param mixed $dir 目录名
  160. * @return array 列出文件夹下内容,返回数组 $dirArray['dir']:存文件夹;$dirArray['file']:存文件
  161. */
  162. static function getDirs($dir)
  163. {
  164. $dir = rtrim($dir, '/') . '/';
  165. $dirArray [][] = NULL;
  166. if (false != ($handle = opendir($dir))) {
  167. $i = 0;
  168. $j = 0;
  169. while (false !== ($file = readdir($handle))) {
  170. if (is_dir($dir . $file)) { //判断是否文件夹
  171. $dirArray ['dir'] [$i] = $file;
  172. $i++;
  173. } else {
  174. $dirArray ['file'] [$j] = $file;
  175. $j++;
  176. }
  177. }
  178. closedir($handle);
  179. }
  180. return $dirArray;
  181. }
  182. /**
  183. * 统计文件夹大小
  184. * @param $dir
  185. * @return int 文件夹大小(单位 B)
  186. */
  187. public static function getSize($dir)
  188. {
  189. $dirlist = opendir($dir);
  190. $dirsize = 0;
  191. while (false !== ($folderorfile = readdir($dirlist))) {
  192. if ($folderorfile != "." && $folderorfile != "..") {
  193. if (is_dir("$dir/$folderorfile")) {
  194. $dirsize += self::getSize("$dir/$folderorfile");
  195. } else {
  196. $dirsize += filesize("$dir/$folderorfile");
  197. }
  198. }
  199. }
  200. closedir($dirlist);
  201. return $dirsize;
  202. }
  203. /**
  204. * 检测是否为空文件夹
  205. * @param $dir
  206. * @return bool
  207. */
  208. static function emptyDir($dir)
  209. {
  210. return (($files = @scandir($dir)) && count($files) <= 2);
  211. }
  212. /**
  213. * 创建多级目录
  214. * @param string $dir
  215. * @param int $mode
  216. * @return boolean
  217. */
  218. public function createDir(string $dir, int $mode = 0777)
  219. {
  220. return is_dir($dir) or ($this->createDir(dirname($dir)) and mkdir($dir, $mode));
  221. }
  222. /**
  223. * 创建指定路径下的指定文件
  224. * @param string $path (需要包含文件名和后缀)
  225. * @param boolean $over_write 是否覆盖文件
  226. * @param int $time 设置时间。默认是当前系统时间
  227. * @param int $atime 设置访问时间。默认是当前系统时间
  228. * @return boolean
  229. */
  230. public function createFile(string $path, bool $over_write = FALSE, int $time = NULL, int $atime = NULL)
  231. {
  232. $path = $this->dirReplace($path);
  233. $time = empty($time) ? time() : $time;
  234. $atime = empty($atime) ? time() : $atime;
  235. if (file_exists($path) && $over_write) {
  236. $this->unlinkFile($path);
  237. }
  238. $aimDir = dirname($path);
  239. $this->createDir($aimDir);
  240. return touch($path, $time, $atime);
  241. }
  242. /**
  243. * 关闭文件操作
  244. * @param string $path
  245. * @return boolean
  246. */
  247. public function close(string $path)
  248. {
  249. return fclose($path);
  250. }
  251. /**
  252. * 读取文件操作
  253. * @param string $file
  254. * @return boolean
  255. */
  256. public static function readFile(string $file)
  257. {
  258. return @file_get_contents($file);
  259. }
  260. /**
  261. * 确定服务器的最大上传限制(字节数)
  262. * @return int 服务器允许的最大上传字节数
  263. */
  264. public function allowUploadSize()
  265. {
  266. $val = trim(ini_get('upload_max_filesize'));
  267. return $val;
  268. }
  269. /**
  270. * 字节格式化 把字节数格式为 B K M G T P E Z Y 描述的大小
  271. * @param int $size 大小
  272. * @param int $dec 显示类型
  273. * @return int
  274. */
  275. public static function byteFormat($size, $dec = 2)
  276. {
  277. $a = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
  278. $pos = 0;
  279. while ($size >= 1024) {
  280. $size /= 1024;
  281. $pos++;
  282. }
  283. return round($size, $dec) . " " . $a[$pos];
  284. }
  285. /**
  286. * 删除非空目录
  287. * 说明:只能删除非系统和特定权限的文件,否则会出现错误
  288. * @param string $dirName 目录路径
  289. * @param boolean $is_all 是否删除所有
  290. * @param boolean $delDir 是否删除目录
  291. * @return boolean
  292. */
  293. public function removeDir(string $dir_path, bool $is_all = FALSE)
  294. {
  295. $dirName = $this->dirReplace($dir_path);
  296. $handle = @opendir($dirName);
  297. while (($file = @readdir($handle)) !== FALSE) {
  298. if ($file != '.' && $file != '..') {
  299. $dir = $dirName . '/' . $file;
  300. if ($is_all) {
  301. is_dir($dir) ? $this->removeDir($dir) : $this->unlinkFile($dir);
  302. } else {
  303. if (is_file($dir)) {
  304. $this->unlinkFile($dir);
  305. }
  306. }
  307. }
  308. }
  309. closedir($handle);
  310. return @rmdir($dirName);
  311. }
  312. /**
  313. * 获取完整文件名
  314. * @param string $fn 路径
  315. * @return string
  316. */
  317. public function getBasename(string $file_path)
  318. {
  319. $file_path = $this->dirReplace($file_path);
  320. return basename(str_replace('\\', '/', $file_path));
  321. //return pathinfo($file_path,PATHINFO_BASENAME);
  322. }
  323. /**
  324. * 获取文件后缀名
  325. * @param string $file_name 文件路径
  326. * @return string
  327. */
  328. public static function getExt(string $file)
  329. {
  330. $file = self::dirReplace($file);
  331. return pathinfo($file, PATHINFO_EXTENSION);
  332. }
  333. /**
  334. * 取得指定目录名称
  335. * @param string $path 文件路径
  336. * @param int $num 需要返回以上级目录的数
  337. * @return string
  338. */
  339. public function fatherDir(string $path, $num = 1)
  340. {
  341. $path = $this->dirReplace($path);
  342. $arr = explode('/', $path);
  343. if ($num == 0 || count($arr) < $num) return pathinfo($path, PATHINFO_BASENAME);
  344. return substr(strrev($path), 0, 1) == '/' ? $arr[(count($arr) - (1 + $num))] : $arr[(count($arr) - $num)];
  345. }
  346. /**
  347. * 删除文件
  348. * @param string $path
  349. * @return boolean
  350. */
  351. public function unlinkFile(string $path)
  352. {
  353. $path = $this->dirReplace($path);
  354. if (file_exists($path)) {
  355. return unlink($path);
  356. }
  357. }
  358. /**
  359. * 文件操作(复制/移动)
  360. * @param string $old_path 指定要操作文件路径(需要含有文件名和后缀名)
  361. * @param string $new_path 指定新文件路径(需要新的文件名和后缀名)
  362. * @param string $type 文件操作类型
  363. * @param boolean $overWrite 是否覆盖已存在文件
  364. * @return boolean
  365. */
  366. public function handleFile(string $old_path, string $new_path, string $type = 'copy', bool $overWrite = FALSE)
  367. {
  368. $old_path = $this->dirReplace($old_path);
  369. $new_path = $this->dirReplace($new_path);
  370. if (file_exists($new_path) && $overWrite = FALSE) {
  371. return FALSE;
  372. } else if (file_exists($new_path) && $overWrite = TRUE) {
  373. $this->unlinkFile($new_path);
  374. }
  375. $aimDir = dirname($new_path);
  376. $this->createDir($aimDir);
  377. switch ($type) {
  378. case 'copy':
  379. return copy($old_path, $new_path);
  380. break;
  381. case 'move':
  382. return @rename($old_path, $new_path);
  383. break;
  384. }
  385. }
  386. /**
  387. * 文件夹操作(复制/移动)
  388. * @param string $old_path 指定要操作文件夹路径
  389. * @param string $aimDir 指定新文件夹路径
  390. * @param string $type 操作类型
  391. * @param boolean $overWrite 是否覆盖文件和文件夹
  392. * @return boolean
  393. */
  394. public function handleDir(string $old_path, string $new_path, string $type = 'copy', bool $overWrite = FALSE)
  395. {
  396. $new_path = $this->checkPath($new_path);
  397. $old_path = $this->checkPath($old_path);
  398. if (!is_dir($old_path)) return FALSE;
  399. if (!file_exists($new_path)) $this->createDir($new_path);
  400. $dirHandle = opendir($old_path);
  401. if (!$dirHandle) return FALSE;
  402. $boolean = TRUE;
  403. while (FALSE !== ($file = readdir($dirHandle))) {
  404. if ($file == '.' || $file == '..') continue;
  405. if (!is_dir($old_path . $file)) {
  406. $boolean = $this->handleFile($old_path . $file, $new_path . $file, $type, $overWrite);
  407. } else {
  408. $this->handleDir($old_path . $file, $new_path . $file, $type, $overWrite);
  409. }
  410. }
  411. switch ($type) {
  412. case 'copy':
  413. closedir($dirHandle);
  414. return $boolean;
  415. break;
  416. case 'move':
  417. closedir($dirHandle);
  418. return @rmdir($old_path);
  419. break;
  420. }
  421. }
  422. /**
  423. * 替换相应的字符
  424. * @param string $path 路径
  425. * @return string
  426. */
  427. public static function dirReplace(string $path)
  428. {
  429. return str_replace('//', '/', str_replace('\\', '/', $path));
  430. }
  431. /**
  432. * 读取指定路径下模板文件
  433. * @param string $path 指定路径下的文件
  434. * @return string $rstr
  435. */
  436. public static function getTempltes(string $path)
  437. {
  438. $path = self::dirReplace($path);
  439. if (file_exists($path)) {
  440. $fp = fopen($path, 'r');
  441. $rstr = fread($fp, filesize($path));
  442. fclose($fp);
  443. return $rstr;
  444. } else {
  445. return '';
  446. }
  447. }
  448. /**
  449. * @param string $oldname 原始名称
  450. * @param string $newname 新名称
  451. * @return bool
  452. */
  453. public function rename(string $oldname, string $newname)
  454. {
  455. if (($newname != $oldname) && is_writable($oldname)) {
  456. return rename($oldname, $newname);
  457. }
  458. }
  459. /**
  460. * 获取指定路径下的信息
  461. * @param string $dir 路径
  462. * @return ArrayObject
  463. */
  464. public function getDirInfo(string $dir)
  465. {
  466. $handle = @opendir($dir);//打开指定目录
  467. $directory_count = 0;
  468. while (FALSE !== ($file_path = readdir($handle))) {
  469. if ($file_path != "." && $file_path != "..") {
  470. //is_dir("$dir/$file_path") ? $sizeResult += $this->get_dir_size("$dir/$file_path") : $sizeResult += filesize("$dir/$file_path");
  471. $next_path = $dir . '/' . $file_path;
  472. if (is_dir($next_path)) {
  473. $directory_count++;
  474. $result_value = self::getDirInfo($next_path);
  475. $total_size += $result_value['size'];
  476. $file_cout += $result_value['filecount'];
  477. $directory_count += $result_value['dircount'];
  478. } elseif (is_file($next_path)) {
  479. $total_size += filesize($next_path);
  480. $file_cout++;
  481. }
  482. }
  483. }
  484. closedir($handle);//关闭指定目录
  485. $result_value['size'] = $total_size;
  486. $result_value['filecount'] = $file_cout;
  487. $result_value['dircount'] = $directory_count;
  488. return $result_value;
  489. }
  490. /**
  491. * 指定文件编码转换
  492. * @param string $path 文件路径
  493. * @param string $input_code 原始编码
  494. * @param string $out_code 输出编码
  495. * @return boolean
  496. */
  497. public function changeFileCode(string $path, string $input_code, string $out_code)
  498. {
  499. if (is_file($path))//检查文件是否存在,如果存在就执行转码,返回真
  500. {
  501. $content = file_get_contents($path);
  502. $content = string::chang_code($content, $input_code, $out_code);
  503. $fp = fopen($path, 'w');
  504. $res = (bool)fputs($fp, $content);
  505. fclose($fp);
  506. return $res;
  507. }
  508. }
  509. /**
  510. * 指定目录下指定条件文件编码转换
  511. * @param string $dirname 目录路径
  512. * @param string $input_code 原始编码
  513. * @param string $out_code 输出编码
  514. * @param boolean $is_all 是否转换所有子目录下文件编码
  515. * @param string $exts 文件类型
  516. * @return boolean
  517. */
  518. public function changeDirFilesCode(string $dirname, string $input_code, string $out_code, bool $is_all = TRUE, string $exts = '')
  519. {
  520. if (is_dir($dirname)) {
  521. $fh = opendir($dirname);
  522. while (($file = readdir($fh)) !== FALSE) {
  523. if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) {
  524. continue;
  525. }
  526. $filepath = $dirname . '/' . $file;
  527. if (is_dir($filepath) && $is_all == TRUE) {
  528. $files = $this->changeDirFilesCode($filepath, $input_code, $out_code, $is_all, $exts);
  529. } else {
  530. if ($this->getExt($filepath) == $exts && is_file($filepath)) {
  531. $boole = $this->changeFileCode($filepath, $input_code, $out_code, $is_all, $exts);
  532. if (!$boole) continue;
  533. }
  534. }
  535. }
  536. closedir($fh);
  537. return TRUE;
  538. } else {
  539. return FALSE;
  540. }
  541. }
  542. /**
  543. * 列出指定目录下符合条件的文件和文件夹
  544. * @param string $dirname 路径
  545. * @param boolean $is_all 是否列出子目录中的文件
  546. * @param string $exts 需要列出的后缀名文件
  547. * @param string $sort 数组排序
  548. * @return ArrayObject
  549. */
  550. public function listDirInfo(string $dirname, bool $is_all = FALSE, string $exts = '', string $sort = 'ASC')
  551. {
  552. //处理多于的/号
  553. $new = strrev($dirname);
  554. if (strpos($new, '/') == 0) {
  555. $new = substr($new, 1);
  556. }
  557. $dirname = strrev($new);
  558. $sort = strtolower($sort);//将字符转换成小写
  559. $files = [];
  560. $subfiles = [];
  561. if (is_dir($dirname)) {
  562. $fh = opendir($dirname);
  563. while (($file = readdir($fh)) !== FALSE) {
  564. if (strcmp($file, '.') == 0 || strcmp($file, '..') == 0) continue;
  565. $filepath = $dirname . '/' . $file;
  566. switch ($exts) {
  567. case '*':
  568. if (is_dir($filepath) && $is_all == TRUE) {
  569. $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort));
  570. }
  571. array_push($files, $filepath);
  572. break;
  573. case 'folder':
  574. if (is_dir($filepath) && $is_all == TRUE) {
  575. $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort));
  576. array_push($files, $filepath);
  577. } elseif (is_dir($filepath)) {
  578. array_push($files, $filepath);
  579. }
  580. break;
  581. case 'file':
  582. if (is_dir($filepath) && $is_all == TRUE) {
  583. $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort));
  584. } elseif (is_file($filepath)) {
  585. array_push($files, $filepath);
  586. }
  587. break;
  588. default:
  589. if (is_dir($filepath) && $is_all == TRUE) {
  590. $files = array_merge($files, self::listDirInfo($filepath, $is_all, $exts, $sort));
  591. } elseif (preg_match("/\.($exts)/i", $filepath) && is_file($filepath)) {
  592. array_push($files, $filepath);
  593. }
  594. break;
  595. }
  596. switch ($sort) {
  597. case 'asc':
  598. sort($files);
  599. break;
  600. case 'desc':
  601. rsort($files);
  602. break;
  603. case 'nat':
  604. natcasesort($files);
  605. break;
  606. }
  607. }
  608. closedir($fh);
  609. return $files;
  610. } else {
  611. return FALSE;
  612. }
  613. }
  614. /**
  615. * 返回指定路径的文件夹信息,其中包含指定路径中的文件和目录
  616. * @param string $dir
  617. * @return ArrayObject
  618. */
  619. public function dirInfo(string $dir)
  620. {
  621. return scandir($dir);
  622. }
  623. /**
  624. * 判断目录是否为空
  625. * @param string $dir
  626. * @return boolean
  627. */
  628. public function isEmpty(string $dir)
  629. {
  630. $handle = opendir($dir);
  631. while (($file = readdir($handle)) !== false) {
  632. if ($file != '.' && $file != '..') {
  633. closedir($handle);
  634. return true;
  635. }
  636. }
  637. closedir($handle);
  638. return false;
  639. }
  640. /**
  641. * 返回指定文件和目录的信息
  642. * @param string $file
  643. * @return ArrayObject
  644. */
  645. public static function listInfo(string $file)
  646. {
  647. $dir = [];
  648. $dir['filename'] = basename($file);//返回路径中的文件名部分。
  649. $dir['pathname'] = strstr(php_uname('s'), 'Windows') ? str_replace('\\', '\\\\', realpath($file)) : realpath($file);//返回绝对路径名。
  650. $dir['owner'] = fileowner($file);//文件的 user ID (所有者)。
  651. $dir['perms'] = fileperms($file);//返回文件的 inode 编号。
  652. $dir['inode'] = fileinode($file);//返回文件的 inode 编号。
  653. $dir['group'] = filegroup($file);//返回文件的组 ID。
  654. $dir['path'] = dirname($file);//返回路径中的目录名称部分。
  655. $dir['atime'] = fileatime($file);//返回文件的上次访问时间。
  656. $dir['ctime'] = filectime($file);//返回文件的上次改变时间。
  657. $dir['perms'] = fileperms($file);//返回文件的权限。
  658. $dir['size'] = self::byteFormat(filesize($file), 2);//返回文件大小。
  659. $dir['type'] = filetype($file);//返回文件类型。
  660. $dir['ext'] = is_file($file) ? pathinfo($file, PATHINFO_EXTENSION) : '';//返回文件后缀名
  661. $dir['mtime'] = filemtime($file);//返回文件的上次修改时间。
  662. $dir['isDir'] = is_dir($file);//判断指定的文件名是否是一个目录。
  663. $dir['isFile'] = is_file($file);//判断指定文件是否为常规的文件。
  664. $dir['isLink'] = is_link($file);//判断指定的文件是否是连接。
  665. $dir['isReadable'] = is_readable($file);//判断文件是否可读。
  666. $dir['isWritable'] = is_writable($file);//判断文件是否可写。
  667. $dir['isUpload'] = is_uploaded_file($file);//判断文件是否是通过 HTTP POST 上传的。
  668. return $dir;
  669. }
  670. /**
  671. * 返回关于打开文件的信息
  672. * @param $file
  673. * @return ArrayObject
  674. * 数字下标 关联键名(自 PHP 4.0.6) 说明
  675. * 0 dev 设备名
  676. * 1 ino 号码
  677. * 2 mode inode 保护模式
  678. * 3 nlink 被连接数目
  679. * 4 uid 所有者的用户 id
  680. * 5 gid 所有者的组 id
  681. * 6 rdev 设备类型,如果是 inode 设备的话
  682. * 7 size 文件大小的字节数
  683. * 8 atime 上次访问时间(Unix 时间戳)
  684. * 9 mtime 上次修改时间(Unix 时间戳)
  685. * 10 ctime 上次改变时间(Unix 时间戳)
  686. * 11 blksize 文件系统 IO 的块大小
  687. * 12 blocks 所占据块的数目
  688. */
  689. public function openInfo(string $file)
  690. {
  691. $file = fopen($file, "r");
  692. $result = fstat($file);
  693. fclose($file);
  694. return $result;
  695. }
  696. /**
  697. * 改变文件和目录的相关属性
  698. * @param string $file 文件路径
  699. * @param string $type 操作类型
  700. * @param string $ch_info 操作信息
  701. * @return boolean
  702. */
  703. public function change_file($file, $type, $ch_info)
  704. {
  705. switch ($type) {
  706. case 'group' :
  707. $is_ok = chgrp($file, $ch_info);//改变文件组。
  708. break;
  709. case 'mode' :
  710. $is_ok = chmod($file, $ch_info);//改变文件模式。
  711. break;
  712. case 'ower' :
  713. $is_ok = chown($file, $ch_info);//改变文件所有者。
  714. break;
  715. }
  716. }
  717. /**
  718. * 取得文件路径信息
  719. * @param $full_path 完整路径
  720. * @return ArrayObject
  721. */
  722. public function getFileType(string $path)
  723. {
  724. //pathinfo() 函数以数组的形式返回文件路径的信息。
  725. //---------$file_info = pathinfo($path); echo file_info['extension'];----------//
  726. //extension取得文件后缀名【pathinfo($path,PATHINFO_EXTENSION)】-----dirname取得文件路径【pathinfo($path,PATHINFO_DIRNAME)】-----basename取得文件完整文件名【pathinfo($path,PATHINFO_BASENAME)】-----filename取得文件名【pathinfo($path,PATHINFO_FILENAME)】
  727. return pathinfo($path);
  728. }
  729. /**
  730. * 取得上传文件信息
  731. * @param $file file属性信息
  732. * @return array
  733. */
  734. public function getUploadFileInfo($file)
  735. {
  736. $file_info = request()->file($file);//取得上传文件基本信息
  737. $info = [];
  738. $info['type'] = strtolower(trim(stripslashes(preg_replace("/^(.+?);.*$/", "\\1", $file_info['type'])), '"'));//取得文件类型
  739. $info['temp'] = $file_info['tmp_name'];//取得上传文件在服务器中临时保存目录
  740. $info['size'] = $file_info['size'];//取得上传文件大小
  741. $info['error'] = $file_info['error'];//取得文件上传错误
  742. $info['name'] = $file_info['name'];//取得上传文件名
  743. $info['ext'] = $this->getExt($file_info['name']);//取得上传文件后缀
  744. return $info;
  745. }
  746. /**
  747. * 设置文件命名规则
  748. * @param string $type 命名规则
  749. * @param string $filename 文件名
  750. * @return string
  751. */
  752. public function setFileName(string $type)
  753. {
  754. switch ($type) {
  755. case 'hash' :
  756. mt_srand();
  757. $new_file = md5(uniqid(mt_rand()));//mt_srand()以随机数md5加密来命名
  758. break;
  759. case 'time' :
  760. $new_file = time();
  761. break;
  762. default :
  763. $new_file = date($type, time());//以时间格式来命名
  764. break;
  765. }
  766. return $new_file;
  767. }
  768. /**
  769. * 文件保存路径处理
  770. * @return string
  771. */
  772. public function checkPath($path)
  773. {
  774. return (preg_match('/\/$/', $path)) ? $path : $path . '/';
  775. }
  776. /**
  777. * 文件下载
  778. * $save_dir 保存路径
  779. * $filename 文件名
  780. * @return array
  781. */
  782. public static function downRemoteFile(string $url, string $save_dir = '', string $filename = '', int $type = 0)
  783. {
  784. if (trim($url) == '') {
  785. return ['file_name' => '', 'save_path' => '', 'error' => 1];
  786. }
  787. if (trim($save_dir) == '') {
  788. $save_dir = './';
  789. }
  790. if (trim($filename) == '') {//保存文件名
  791. $ext = strrchr($url, '.');
  792. // if($ext!='.gif'&&$ext!='.jpg'){
  793. // return ['file_name'=>'','save_path'=>'','error'=>3];
  794. // }
  795. $filename = time() . $ext;
  796. }
  797. if (0 !== strrpos($save_dir, '/')) {
  798. $save_dir .= '/';
  799. }
  800. //创建保存目录
  801. if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
  802. return ['file_name' => '', 'save_path' => '', 'error' => 5];
  803. }
  804. //获取远程文件所采用的方法
  805. if ($type) {
  806. $ch = curl_init();
  807. $timeout = 5;
  808. curl_setopt($ch, CURLOPT_URL, $url);
  809. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  810. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  811. $img = curl_exec($ch);
  812. curl_close($ch);
  813. } else {
  814. ob_start();
  815. readfile($url);
  816. $img = ob_get_contents();
  817. ob_end_clean();
  818. }
  819. //$size=strlen($img);
  820. //文件大小
  821. $fp2 = fopen($save_dir . $filename, 'a');
  822. fwrite($fp2, $img);
  823. fclose($fp2);
  824. unset($img, $url);
  825. return ['file_name' => $filename, 'save_path' => $save_dir . $filename, 'error' => 0];
  826. }
  827. /**
  828. * 解压zip文件
  829. * @param string $filename
  830. * @param string $savename
  831. * @return bool
  832. */
  833. public static function zipOpen(string $filename, string $savename)
  834. {
  835. $zip = new \ZipArchive;
  836. $zipfile = $filename;
  837. $res = $zip->open($zipfile);
  838. $toDir = $savename;
  839. if (!file_exists($toDir)) mkdir($toDir, 0777);
  840. $docnum = $zip->numFiles;
  841. for ($i = 0; $i < $docnum; $i++) {
  842. $statInfo = $zip->statIndex($i);
  843. if ($statInfo['crc'] == 0 && $statInfo['comp_size'] != 2) {
  844. //新建目录
  845. mkdir($toDir . '/' . substr($statInfo['name'], 0, -1), 0777);
  846. } else {
  847. //拷贝文件
  848. copy('zip://' . $zipfile . '#' . $statInfo['name'], $toDir . '/' . $statInfo['name']);
  849. }
  850. }
  851. $zip->close();
  852. return true;
  853. }
  854. /**
  855. *设置字体格式
  856. * @param $title string 必选
  857. * return string
  858. */
  859. public static function setUtf8($title)
  860. {
  861. return iconv('utf-8', 'gb2312', $title);
  862. }
  863. /**
  864. *检查指定文件是否能写入
  865. * @param $file string 必选
  866. * return boole
  867. */
  868. public static function isWritable($file)
  869. {
  870. $file = str_replace('\\', '/', $file);
  871. if (!file_exists($file)) return false;
  872. return is_writable($file);
  873. }
  874. /**读取excel文件内容
  875. * @param $filePath
  876. * @param $row_num
  877. * @param $suffix
  878. * @return array|false
  879. * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
  880. */
  881. public function readExcel($filePath, $row_num = 2, $suffix = 'Xlsx')
  882. {
  883. if (!$filePath) return false;
  884. $pathInfo = pathinfo($filePath, PATHINFO_EXTENSION);
  885. if (!$pathInfo || $pathInfo != "xlsx") throw new ValidateException('必须上传xlsx格式文件');
  886. //加载读取模型
  887. $readModel = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($suffix);
  888. // 创建读操作
  889. // 打开文件 载入excel表格
  890. try {
  891. $spreadsheet = $readModel->load($filePath);
  892. $sheet = $spreadsheet->getActiveSheet();
  893. $sheet->getHighestColumn();
  894. $highestRow = $sheet->getHighestRow();
  895. $lines = $highestRow - 1;
  896. if ($lines <= 0) {
  897. throw new ValidateException('物流数据不能为空');
  898. }
  899. // 用于存储表格数据
  900. /** @var ExpressServices $expressService */
  901. // $expressService = app()->make(ExpressServices::class);
  902. $data = $expressCode = [];
  903. for ($i = $row_num; $i <= $highestRow; $i++) {
  904. $t1 = $this->objToStr($sheet->getCellByColumnAndRow(1, $i)->getValue());
  905. $t2 = $this->objToStr($sheet->getCellByColumnAndRow(2, $i)->getValue());
  906. $t3 = $this->objToStr($sheet->getCellByColumnAndRow(5, $i)->getValue());
  907. $t4 = $this->objToStr($sheet->getCellByColumnAndRow(6, $i)->getValue());
  908. $t5 = $this->objToStr($sheet->getCellByColumnAndRow(7, $i)->getValue());
  909. if ($t1 && $t2 && $t3 && $t4 && $t5) {
  910. $data[] = [$t1, $t2, $t3, $t4, $t5];
  911. $expressCode[] = $t4;
  912. }
  913. }
  914. if ($expressCode) {
  915. $expressCode = array_unique(array_map('trim', $expressCode));
  916. // $expressId = $expressService->getColumn([['code', 'in', $expressCode]], 'id', 'code');
  917. foreach ($expressCode as $code) {
  918. if (!isset($expressId[$code])) {
  919. throw new ValidateException($code . '订单物流公司不在平台收录内');
  920. }
  921. }
  922. }
  923. return $data;
  924. } catch (\Exception $e) {
  925. throw new ValidateException($e->getMessage());
  926. }
  927. }
  928. /**
  929. * 读取商品卡密excel文件内容
  930. * @param $filePath
  931. * @param int $row_num
  932. * @param string $suffix
  933. * @return array|false
  934. * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
  935. */
  936. public function readProductCardExcel($filePath, $row_num = 1, $suffix = 'Xlsx')
  937. {
  938. if (!$filePath) return false;
  939. $pathInfo = pathinfo($filePath, PATHINFO_EXTENSION);
  940. if (!$pathInfo || $pathInfo != "xlsx") throw new ValidateException('必须上传xlsx格式文件');
  941. //加载读取模型
  942. $readModel = \PhpOffice\PhpSpreadsheet\IOFactory::createReader($suffix);
  943. // 创建读操作
  944. // 打开文件 载入excel表格
  945. try {
  946. $spreadsheet = $readModel->load($filePath);
  947. $sheet = $spreadsheet->getActiveSheet();
  948. $sheet->getHighestColumn();
  949. $highestRow = $sheet->getHighestRow();
  950. $lines = $highestRow - 1;
  951. if ($lines <= 0) {
  952. throw new ValidateException('数据不能为空');
  953. }
  954. // 用于存储表格数据
  955. $data = [];
  956. for ($i = $row_num; $i <= $highestRow; $i++) {
  957. $t1 = $this->objToStr($sheet->getCellByColumnAndRow(1, $i)->getValue()) ?? '';
  958. $t2 = $this->objToStr($sheet->getCellByColumnAndRow(2, $i)->getValue());
  959. if ($t2) {
  960. $data[] = [
  961. 'key' => $t1,
  962. 'value' => $t2
  963. ];
  964. }
  965. }
  966. return $data;
  967. } catch (\Exception $e) {
  968. throw new ValidateException($e->getMessage());
  969. }
  970. }
  971. /**对象转字符
  972. * @param $value
  973. * @return mixed
  974. */
  975. public function objToStr($value)
  976. {
  977. return is_object($value) ? $value->__toString() : $value;
  978. }
  979. /**
  980. * 压缩文件夹及文件
  981. * @param string $source 需要压缩的文件夹/文件路径
  982. * @param string $destination 压缩后的保存地址
  983. * @param string $folder 文件夹前缀,保存时需要去掉的父级文件夹
  984. * @return boolean
  985. */
  986. function addZip($source, $destination, $folder = '')
  987. {
  988. if (!extension_loaded('zip') || !file_exists($source)) {
  989. return false;
  990. }
  991. $zip = new \ZipArchive;
  992. if (!$zip->open($destination, $zip::CREATE)) {
  993. return false;
  994. }
  995. $source = str_replace('\\', '/', $source);
  996. $folder = str_replace('\\', '/', $folder);
  997. if (is_dir($source) === true) {
  998. $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($source), \RecursiveIteratorIterator::SELF_FIRST);
  999. foreach ($files as $file) {
  1000. $file = str_replace('\\', '/', $file);
  1001. if (in_array(substr($file, strrpos($file, '/') + 1), array('.', '..'))) continue;
  1002. if (is_dir($file) === true) {
  1003. $zip->addEmptyDir(str_replace($folder . '/', '', $file . '/'));
  1004. } else if (is_file($file) === true) {
  1005. $zip->addFromString(str_replace($folder . '/', '', $file), file_get_contents($file));
  1006. }
  1007. }
  1008. } else if (is_file($source) === true) {
  1009. $zip->addFromString(basename($source), file_get_contents($source));
  1010. }
  1011. return $zip->close();
  1012. }
  1013. }