递归改后缀需先用is_dir()判目录类型,过滤.和..,检查文件存在性与目标路径唯一性,用pathinfo安全取名,注意跨文件系统需copy+unlink,严格比较readdir()返回值。

递归函数必须先判断是否为目录,否则会报错
PHP 的 rename() 只能操作文件或空目录,对非空目录直接调用会失败。所以递归前必须用 is_dir() 明确区分类型——如果当前项是目录,就继续递归;如果是文件,才尝试改后缀。常见错误是把 scandir() 返回的 . 和 .. 当作真实目录处理,导致 rename() 对它们执行操作而报错。
关键检查点:
- 用
in_array($item, ['.', '..'])过滤掉特殊目录项 - 用
is_dir($full_path)判断后再决定走递归分支还是改名分支 - 改名前必须确保
file_exists($old_path)且!file_exists($new_path),否则可能覆盖或静默失败
改后缀本质是重命名,不是“改类型”
rename() 不校验文件内容,只改磁盘上的名字。比如把 report.asp 改成 report.php,PHP 解析器不会因此就去执行它——前提是 Web 服务器配置允许该后缀被解析。但如果你只是想批量替换后缀用于整理或迁移,这一步就够了。
实际改名逻辑要拆解清楚:
- 用
pathinfo($filename, PATHINFO_EXTENSION)安全取扩展名(比strrpos()+substr()更可靠) - 用
pathinfo($filename, PATHINFO_FILENAME)取不含扩展名的主名 - 拼新路径时必须用完整绝对路径:
rename($old_full, $new_full),不能只传文件名 - Windows 下路径分隔符建议统一用
/或DIRECTORY_SEPARATOR,避免\引发转义问题
PHP7 中 readdir() 循环必须用严格比较
在 while (($file = readdir($handle)) !== false) 这类循环里,!== false 是强制要求。因为 readdir() 可能返回字符串 "0"(比如存在名为 0.txt 的文件),而 != false 会把它当成 false 提前终止循环——这是 PHP7 仍保留的经典陷阱。
其他易错细节:
-
opendir()失败时返回false,需提前检查:if (!$handle) { die("无法打开目录"); } - 递归调用前建议加深度限制(比如传入
$depth参数并递增),防止无限嵌套或栈溢出 - 大量文件时,建议用
set_time_limit(0)避免超时中断
跨文件系统 rename() 会失败,得换方案
当源路径和目标路径不在同一挂载点(比如从 /tmp 改到 /home),rename() 在 Linux 下直接返回 false。此时必须改用 copy() + unlink() 组合,并手动检查 copy() 是否成功、unlink() 是否执行——否则容易留下重复文件。
更稳妥的写法:
if (!rename($old, $new)) {
if (copy($old, $new) && unlink($old)) {
// 成功
} else {
error_log("重命名失败: {$old} -> {$new}");
}
}
这个分支在 PHP7 下依然有效,但要注意 copy() 不保留原文件权限和时间戳,如需精确还原,得额外调用 chmod() 和 touch()。
file_exists() 和 is_writable() 检查,尤其在线上环境。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











