应使用 filemtime 获取文件修改时间戳并与当前时间比对判断是否超期,注意检查返回值是否为 false,结合 is_file 过滤目录,用 unlink 安全删除,推荐 scandir 遍历并手动过滤。

用 filemtime 判断文件修改时间是否超期
PHP 没有内置的“文件过期”判断函数,得靠 filemtime 获取最后修改时间戳,再和当前时间比对。注意:不是创建时间(filectime 在 Linux 下是 inode 修改时间,不可靠),也不是访问时间(fileatime 容易被缓存或脚本触发干扰)。实际清理逻辑应基于修改时间,最符合“旧文件”的语义。
关键点:
-
filemtime返回整数时间戳,失败时返回false,必须显式检查,否则false > time() - $seconds会隐式转成0,导致误删 - 建议统一用
time()计算基准,避免用date('U')或strtotime('now')带来额外开销或时区歧义 - 若目录含大量文件,先用
is_file()过滤掉子目录,避免对目录调用filemtime报 warning
用 unlink 安全删除文件,避开权限与符号链接陷阱
unlink 是删除文件的正确方式,但直接调用前必须确认目标是普通文件且有写权限。常见翻车点:
- 对符号链接调用
unlink会删链接本身(不是目标),这通常符合预期;但如果误把目录当文件传入,unlink会失败并触发 warning —— 所以务必先is_file($path) - Linux 下若文件被进程占用(如日志正被
tail -f查看),unlink仍成功(文件系统层面删除),但磁盘空间不会立刻释放,需等进程关闭 fd —— 这属于系统行为,PHP 无法干预 - Windows 下若文件只读,
unlink会失败,可先chmod($path, 0644)再删(注意:仅对当前用户有效,且需 PHP 有 chmod 权限)
遍历目录时优先用 scandir 而非 glob,避免通配符误匹配
清理指定目录下所有旧文件,推荐用 scandir + 手动过滤,而不是 glob($dir . '/*')。原因很实际:
立即学习“PHP免费学习笔记(深入)”;
-
glob在路径含空格、中文或特殊字符时容易出错,且不返回.和..,看似省事,实则丢失控制权 -
scandir返回完整数组,可明确跳过.、..和子目录,逻辑更透明;配合foreach逐个处理,也方便加日志或计数 - 如果目录层级深、需递归清理,别硬套
scandir自己写递归 —— 改用RecursiveDirectoryIterator更稳,但单层清理没必要引入迭代器复杂度
完整示例:清理 /var/log/myapp/ 下 7 天前的 .log 文件
$logDir = '/var/log/myapp/';
$days = 7;
$threshold = time() - ($days * 86400);
<p>if (is_dir($logDir)) {
$files = scandir($logDir);
foreach ($files as $file) {
$path = $logDir . $file;
if ($file === '.' || $file === '..' || !is_file($path)) {
continue;
}
if (pathinfo($file, PATHINFO_EXTENSION) !== 'log') {
continue;
}
$mtime = @filemtime($path); // @ 抑制 warning,但后面仍要判 false
if ($mtime === false || $mtime > $threshold) {
continue;
}
if (@unlink($path)) {
error_log("Deleted old log: $path");
} else {
error_log("Failed to delete: $path");
}
}
}这段代码没用异常、没依赖扩展,跑在 PHP 5.6+ 都没问题。真正容易被忽略的是:@unlink 的错误抑制只藏 warning,不解决权限问题;如果批量删失败,得去查 error_log 或用 clearstatcache() 避免 stat 缓存干扰 —— 尤其在高并发写入场景下。



















