FileService.php 37 KB

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