<?php
declare(strict_types=1);
* +----------------------------------------------------------------------
* | ThinkAdmin Plugin for ThinkAdmin
* +----------------------------------------------------------------------
* | 版权所有 2014~2026 ThinkAdmin [ thinkadmin.top ]
* +----------------------------------------------------------------------
* | 官方网站: https://thinkadmin.top
* +----------------------------------------------------------------------
* | 开源协议 ( https://mit-license.org )
* | 免责声明 ( https://thinkadmin.top/disclaimer )
* | 会员特权 ( https://thinkadmin.top/vip-introduce )
* +----------------------------------------------------------------------
* | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
* | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
* +----------------------------------------------------------------------
*/
namespace think\admin\extend;
use SplFileInfo;
use think\admin\Exception;
* 通用工具扩展.
* @class ToolsExtend
*/
class ToolsExtend
{
* 兼容旧方式调用.
* @return array|bool
* @throws Exception
*/
public static function __callStatic(string $method, array $arguments)
{
$methods = [
'copyfile' => 'copy',
'scandirectory' => 'scan',
'findfilesarray' => 'find',
'removeemptydirectory' => 'remove',
];
if ($real = $methods[strtolower($method)] ?? null) {
return self::{$real}(...$arguments);
}
throw new Exception("method not exists: ToolsExtend::{$method}()");
}
* 扫描目录下的文件列表.
* @param string $path 扫描目录
* @param ?int $depth 扫描深度
* @param string $ext 筛选后缀
* @param bool $short 相对路径
*/
public static function scan(string $path, ?int $depth = null, string $ext = '', bool $short = true): array
{
return static::find($path, $depth, function (\SplFileInfo $info) use ($ext) {
return $info->isDir() || $ext === '' || strtolower($info->getExtension()) === strtolower($ext);
}, $short);
}
* 扫描目录并返回文件路径数组.
* @param string $path 扫描目录
* @param ?int $depth 扫描深度
* @param ?\Closure $filter 文件过滤,返回 false 表示放弃
* @param bool $short 是否返回相对于给定路径的短路径
* @return array 包含文件路径的数组
*/
public static function find(string $path, ?int $depth = null, ?\Closure $filter = null, bool $short = true): array
{
[$info, $files] = [new \SplFileInfo($path), []];
if ($info->isDir() || $info->isFile()) {
if ($info->isFile() && ($filter === null || $filter($info) !== false)) {
$files[] = $short ? $info->getBasename() : $info->getPathname();
}
if ($info->isDir()) {
foreach (static::findFilesYield($info->getPathname(), $depth, $filter) as $file) {
$files[] = $short ? substr($file->getPathname(), strlen($info->getPathname()) + 1) : $file->getPathname();
}
}
}
return $files;
}
* 深度拷贝到指定目录.
* @param string $frdir 来源目录
* @param string $todir 目标目录
* @param array $files 指定文件
* @param bool $force 强制替换
* @param bool $remove 删除文件
*/
public static function copy(string $frdir, string $todir, array $files = [], bool $force = true, bool $remove = true): bool
{
$frdir = rtrim($frdir, '\/') . DIRECTORY_SEPARATOR;
$todir = rtrim($todir, '\/') . DIRECTORY_SEPARATOR;
if (empty($files) && is_dir($frdir)) {
$files = static::find($frdir, null, function (\SplFileInfo $info) {
return $info->getBasename()[0] !== '.';
});
}
foreach ($files as $target) {
[$fromPath, $destPath] = [$frdir . $target, $todir . $target];
if ($force || !is_file($destPath)) {
is_dir($dir = dirname($destPath)) || mkdir($dir, 0777, true);
copy($fromPath, $destPath);
}
$remove && unlink($fromPath);
}
$remove && static::remove($frdir);
return true;
}
* 移除清空目录.
*/
public static function remove(string $path): bool
{
if (!file_exists($path)) {
return true;
}
if (is_file($path)) {
return unlink($path);
}
$dirs = [$path];
iterator_to_array(self::findFilesYield($path, null, function (\SplFileInfo $file) use (&$dirs) {
$file->isDir() ? $dirs[] = $file->getPathname() : unlink($file->getPathname());
}));
usort($dirs, function ($a, $b) {
return strlen($b) <=> strlen($a);
});
foreach ($dirs as $dir) {
file_exists($dir) && is_dir($dir) && rmdir($dir);
}
return !file_exists($path);
}
* 递归扫描指定目录,返回文件或目录的 SplFileInfo 对象。
* @param string $path 目录路径
* @param ?int $depth 扫描深度
* @param null|\Closure $filter 文件过滤,返回 false 表示放弃
* @param bool $appendPath 是否包含目录本身在结果中
* @param int $currDepth 当前深度,临时变量递归时使用
* @return \Generator 返回 SplFileInfo 对象的生成器
*/
public static function findFilesYield(string $path, ?int $depth = null, ?\Closure $filter = null, bool $appendPath = false, int $currDepth = 1): \Generator
{
if (file_exists($path) && is_dir($path) && (is_null($depth) || $currDepth <= $depth)) {
foreach (new \FilesystemIterator($path, \FilesystemIterator::SKIP_DOTS) as $item) {
if ($filter !== null && $filter($item) === false) {
continue;
}
if ($item->isDir() && !$item->isLink()) {
$appendPath && yield $item;
yield from static::findFilesYield($item->getPathname(), $depth, $filter, $appendPath, $currDepth + 1);
} else {
yield $item;
}
}
}
}
}