123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- <?php
- namespace ba;
- use Throwable;
- use PhpZip\ZipFile;
- use FilesystemIterator;
- use RecursiveIteratorIterator;
- use RecursiveDirectoryIterator;
- /**
- * 访问和操作文件系统
- */
- class Filesystem
- {
- /**
- * 是否是空目录
- */
- public static function dirIsEmpty(string $dir): bool
- {
- if (!file_exists($dir)) return true;
- $handle = opendir($dir);
- while (false !== ($entry = readdir($handle))) {
- if ($entry != "." && $entry != "..") {
- closedir($handle);
- return false;
- }
- }
- closedir($handle);
- return true;
- }
- /**
- * 递归删除目录
- * @param string $dir 目录路径
- * @param bool $delSelf 是否删除传递的目录本身
- * @return bool
- */
- public static function delDir(string $dir, bool $delSelf = true): bool
- {
- if (!is_dir($dir)) {
- return false;
- }
- $files = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
- RecursiveIteratorIterator::CHILD_FIRST
- );
- foreach ($files as $fileInfo) {
- if ($fileInfo->isDir()) {
- self::delDir($fileInfo->getRealPath());
- } else {
- @unlink($fileInfo->getRealPath());
- }
- }
- if ($delSelf) {
- @rmdir($dir);
- }
- return true;
- }
- /**
- * 删除一个路径下的所有相对空文件夹(删除此路径中的所有空文件夹)
- * @param string $path 相对于根目录的文件夹路径 如`c:BuildAdmin/a/b/`
- * @return void
- */
- public static function delEmptyDir(string $path): void
- {
- $path = str_replace(root_path(), '', rtrim(self::fsFit($path), DIRECTORY_SEPARATOR));
- $path = array_filter(explode(DIRECTORY_SEPARATOR, $path));
- for ($i = count($path) - 1; $i >= 0; $i--) {
- $dirPath = root_path() . implode(DIRECTORY_SEPARATOR, $path);
- if (!is_dir($dirPath)) {
- unset($path[$i]);
- continue;
- }
- if (self::dirIsEmpty($dirPath)) {
- self::delDir($dirPath);
- unset($path[$i]);
- } else {
- break;
- }
- }
- }
- /**
- * 检查目录/文件是否可写
- * @param $path
- * @return bool
- */
- public static function pathIsWritable($path): bool
- {
- if (DIRECTORY_SEPARATOR == '/' && !@ini_get('safe_mode')) {
- return is_writable($path);
- }
- if (is_dir($path)) {
- $path = rtrim($path, '/') . '/' . md5(mt_rand(1, 100) . mt_rand(1, 100));
- if (($fp = @fopen($path, 'ab')) === false) {
- return false;
- }
- fclose($fp);
- @chmod($path, 0777);
- @unlink($path);
- return true;
- } elseif (!is_file($path) || ($fp = @fopen($path, 'ab')) === false) {
- return false;
- }
- fclose($fp);
- return true;
- }
- /**
- * 路径分隔符根据当前系统分隔符适配
- * @param string $path 路径
- * @return string 转换后的路径
- */
- public static function fsFit(string $path): string
- {
- return str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
- }
- /**
- * 解压Zip
- * @param string $file ZIP文件路径
- * @param string $dir 解压路径
- * @return string 解压后的路径
- * @throws Throwable
- */
- public static function unzip(string $file, string $dir = ''): string
- {
- if (!file_exists($file)) {
- throw new Exception("Zip file not found");
- }
- $zip = new ZipFile();
- try {
- $zip->openFile($file);
- } catch (Throwable $e) {
- $zip->close();
- throw new Exception('Unable to open the zip file', 0, ['msg' => $e->getMessage()]);
- }
- $dir = $dir ?: substr($file, 0, strripos($file, '.zip'));
- if (!is_dir($dir)) {
- @mkdir($dir, 0755);
- }
- try {
- $zip->extractTo($dir);
- } catch (Throwable $e) {
- throw new Exception('Unable to extract ZIP file', 0, ['msg' => $e->getMessage()]);
- } finally {
- $zip->close();
- }
- return $dir;
- }
- /**
- * 创建ZIP
- * @param array $files 文件路径列表
- * @param string $fileName ZIP文件名称
- * @return bool
- * @throws Throwable
- */
- public static function zip(array $files, string $fileName): bool
- {
- $zip = new ZipFile();
- try {
- foreach ($files as $v) {
- if (is_array($v) && isset($v['file']) && isset($v['name'])) {
- $zip->addFile(root_path() . str_replace(root_path(), '', Filesystem::fsFit($v['file'])), $v['name']);
- } else {
- $saveFile = str_replace(root_path(), '', Filesystem::fsFit($v));
- $zip->addFile(root_path() . $saveFile, $saveFile);
- }
- }
- $zip->saveAsFile($fileName);
- } catch (Throwable $e) {
- throw new Exception('Unable to package zip file', 0, ['msg' => $e->getMessage(), 'file' => $fileName]);
- } finally {
- $zip->close();
- }
- if (file_exists($fileName)) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * 递归创建目录
- * @param string $dir 目录路径
- * @return bool
- */
- public static function mkdir(string $dir): bool
- {
- if (!is_dir($dir)) {
- return mkdir($dir, 0755, true);
- }
- return false;
- }
- /**
- * 获取一个目录内的文件列表
- * @param string $dir 目录路径
- * @param array $suffix 要获取的文件列表的后缀
- * @return array
- */
- public static function getDirFiles(string $dir, array $suffix = ['php']): array
- {
- $files = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($dir), RecursiveIteratorIterator::LEAVES_ONLY
- );
- $fileList = [];
- foreach ($files as $file) {
- if (!$file->isDir() && in_array($file->getExtension(), $suffix)) {
- $filePath = $file->getRealPath();
- $name = str_replace($dir, '', $filePath);
- $name = str_replace(DIRECTORY_SEPARATOR, "/", $name);
- $fileList[$name] = $name;
- }
- }
- return $fileList;
- }
- /**
- * 将一个文件单位转为字节
- * @param string $unit 将b、kb、m、mb、g、gb的单位转为 byte
- * @return int byte
- */
- public static function fileUnitToByte(string $unit): int
- {
- preg_match('/([0-9.]+)(\w+)/', $unit, $matches);
- if (!$matches) {
- return 0;
- }
- $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
- return (int)($matches[1] * pow(1024, $typeDict[strtolower($matches[2])] ?? 0));
- }
- }
|