file_get_contents与file_put_contents需配合file_exists、is_readable/is_writable校验,处理中文要统一UTF-8编码并显式转码,大文件应改用流式操作,写入须加LOCK_EX防并发覆盖,且二者仅适用于小文本操作。

str_replace 能搞定大多数情况,但直接遍历写文件极易出错——空文件、乱码、并发覆盖、误改二进制文件,都是高频翻车点。别信“一行脚本搞定”,关键在控制粒度和防御性处理。
file_get_contents + str_replace 写回前必须校验三件事
这是最常用也最容易崩的组合。不是函数有问题,而是调用链太脆弱。
-
file_get_contents返回false时继续替换,结果把null写进文件 → 文件变空。必须先判断:if ($content === false) { throw new RuntimeException("无法读取 {$path}"); } - 中文替换失败?大概率是编码不一致。
mb_detect_encoding($content)检测源文件编码,必要时用mb_convert_encoding($content, 'UTF-8', $encoding)统一后再替换 -
file_put_contents默认不加锁。多人同时跑脚本或 Web 请求触发时,可能两个进程同时写同一文件 → 部分内容丢失。务必加LOCK_EX标志:file_put_contents($path, $newContent, LOCK_EX)
RecursiveDirectoryIterator 遍历时要跳过这四类路径
盲目 foreach 所有 .php 文件,极可能扫到 vendor/、node_modules/ 或缓存目录,轻则慢,重则改坏依赖。
- 构造迭代器时传
FilesystemIterator::SKIP_DOTS,跳过.和.. - 用
$file->isFile()和$file->isWritable()双重过滤,跳过目录、符号链接、只读文件 - 扩展名判断用
pathinfo($file->getPathname(), PATHINFO_EXTENSION),比substr($file->getFilename(), -4)更可靠(比如index.php.bak) - 显式排除危险目录:
if (stripos($file->getPathname(), '/vendor/') !== false) continue;,同理过滤/cache/、/logs/、/.git/
preg_replace 替换含换行的内容必须加 s 修饰符
想替换跨多行的代码块(比如注释、HTML 标签、数组定义),str_replace 失效,但 preg_replace 不加修饰符照样跪。
立即学习“PHP免费学习笔记(深入)”;
-
.默认不匹配换行符,所以preg_replace('/<div>.*/', '', $content) 什么也抓不到。必须加 <code>s:preg_replace('/<div>.*/s', '', $content)<li>用户输入的搜索词含正则元字符(如 <code>.、*、[)?先用preg_quote($search, '/')转义,否则直接执行会报PREG_NO_ERROR错误甚至崩溃 -
preg_replace替换失败返回null,不是原字符串。必须判断:if ($newContent === null) { /* 处理错误 */ } - 批量处理时,正则模式别在循环里拼接(如
'/' . $keyword . '/'),会反复编译。提取为常量或变量复用 - 自带预览:所有匹配项列出来,可逐个点开确认上下文,避免误替
user_id时把user_id_card也干掉 - 天然过滤:填
*.php就只扫 PHP 文件,不会碰.png、.log、.lock - 原子撤销:替换后 Ctrl+Z 一键全撤,比从
.bak恢复快得多;且 Git 未 commit 前,git checkout -- .也能秒回滚
VS Code 全局替换比脚本更安全的三个理由
对中小项目(Ctrl+Shift+H,不是偷懒,是规避真实风险。
真正麻烦的不是“怎么换”,而是“换错了谁来兜底”。备份只是底线,预判哪些文件不该动、哪些内容不能裸替、哪些上下文必须人工核对,才决定一次批量操作到底稳不稳。



















