PHP批量重命名需在循环内用pathinfo()或getExtension()获取并转小写后缀,再比对黑名单跳过;目标路径须完整,注意Windows大小写不敏感、权限及符号链接问题。

PHP中用rename()批量重命名文件但跳过特定后缀
直接用rename()本身不带过滤逻辑,必须手动判断后缀再决定是否执行。关键不是“怎么替换”,而是“在哪做判断”——得在循环里对每个$file先检查pathinfo($file, PATHINFO_EXTENSION),匹配到黑名单就continue。
常见错误是把过滤写在glob()里试图靠通配符排除,比如glob("*.php")确实能筛出PHP文件,但你要跳过PHP、保留txt/js等,就得用白名单或黑名单逻辑,不能依赖glob的模式匹配能力。
- 黑名单数组建议全小写,统一用
strtolower()处理扩展名再比对,避免.JPG和.jpg漏判 - 注意
rename()第二个参数(目标路径)必须包含完整文件名,不能只传新名字,否则会覆盖到当前目录下 - 如果目标文件已存在,
rename()默认失败且不报错(返回false),需用if (!rename(...)) { trigger_error(...); }捕获
用DirectoryIterator遍历时跳过.log和.tmp
DirectoryIterator比glob()更可控,能自然跳过目录项、隐藏文件,也方便嵌套条件判断。重点是调用$file->getExtension()获取后缀,比pathinfo()少一次字符串解析开销。
容易忽略的是:它默认遍历包括.和..,虽然isFile()能过滤掉,但若黑名单里有''(空扩展名),可能误伤无后缀文件——要明确排除$file->getExtension() === ''的情况,除非你真想处理这类文件。
立即学习“PHP免费学习笔记(深入)”;
foreach (new DirectoryIterator('/path/to/dir') as $file) {
if (!$file->isFile()) continue;
$ext = strtolower($file->getExtension());
if (in_array($ext, ['log', 'tmp', 'swp'], true)) continue;
$newName = '/path/to/dir/' . 'prefix_' . $file->getFilename();
rename($file->getPathname(), $newName);
}
Windows下rename()对大小写不敏感导致跳过失效
在Windows系统里,rename('A.TXT', 'a.txt')会成功,但file_exists('a.txt')也可能返回true,导致你以为跳过了,其实只是改了大小写。更麻烦的是,黑名单用in_array('txt', [...])能命中,但如果你用strpos($filename, '.TXT') !== false这种粗暴方式,就会漏掉。
所以必须统一走pathinfo(..., PATHINFO_EXTENSION)或$file->getExtension(),再转小写比对。别信文件名里看到的大小写,操作系统层不保证。
- Linux/macOS区分大小写,
.TXT和.txt是两个后缀;Windows不区分,但PHP函数仍按字面返回扩展名,所以仍需strtolower() - 如果源文件是
readme.TXT,pathinfo()返回TXT,不转小写直接比对'txt'会失败 - 用
mb_strtolower()替代strtolower()仅当文件名含非ASCII字符(如中文、日文),普通英文后缀用strtolower()足够
用preg_replace()改名时如何保留原扩展名不被破坏
很多人用preg_replace('/^(\w+)/', 'new_$1', $filename)结果把.php一起卷进去了,因为正则没锚定结尾。正确做法是只替换主文件名部分,扩展名单独拼接。
最稳的方式是拆开处理:$info = pathinfo($filename); $newBase = preg_replace(..., $info['filename']); $newPath = $info['dirname'] . '/' . $newBase . '.' . $info['extension'];。别图省事用单个正则包打天下,扩展名位置不固定(比如.tar.gz),pathinfo()才是可靠解法。
$filename = 'old_script.php';
$info = pathinfo($filename);
$newBase = preg_replace('/^old_/', 'new_', $info['filename']);
$newPath = $info['dirname'] . '/' . $newBase . '.' . $info['extension'];
// → 'new_script.php'
实际跑批时,最容易被忽略的是权限问题:Web服务器用户(如www-data)可能对目标目录没写权限,rename()静默失败;还有就是符号链接——rename()操作的是链接本身,不是它指向的文件,这点在部署脚本里常踩坑。










