处理文件替换需按场景选方法:小文本用file_get_contents+str_replace,大日志用fopen+fgets流式处理,结构化配置须用专用解析器,跨编码/跨行/正则需严格校验修饰符与编码。

别用 file_get_contents 处理超过 5MB 的文件,会直接触发内存耗尽错误;真正“高效”取决于你面对的是小文本、大日志、结构化配置,还是跨行 HTML 片段——方法选错,不是慢,是崩。
小文件用 file_get_contents + str_replace 最快
这是唯一能靠单次函数调用完成的方案,适合模板、ini 片段、JSON 配置(前提是纯文本且无嵌套结构)。关键不是“快”,而是原子性可控。
- 必须检查
file_get_contents返回值:若为false,说明文件不存在或权限不足,后续替换会静默失败 - 中文替换出错?先用
mb_detect_encoding判定源编码,再用mb_convert_encoding统一转 UTF-8 - 写入时加
LOCK_EX:比如file_put_contents($path, $new, LOCK_EX),避免并发写导致内容截断 - 操作前手动备份:
copy($path, $path . '.bak'),别依赖“撤销”——PHP 不提供回滚
大日志文件必须用 fopen + fgets 流式处理
100MB 的 access.log 用 file_get_contents 会吃掉同等内存,而 fgets 只存一行,内存占用恒定在几 KB。但默认读取长度是 1024 字节,超长行会被砍断。
- 显式传长度参数:
fgets($fp, 8192),否则可能切开 URL 或 JSON 字段 -
fgets保留末尾的\n,替换后别多写一次换行,否则空行爆炸 - 二进制文件(.png/.pdf)绝对不能用此法——
fgets按文本解析,会破坏字节流 - Linux 下优先用
sed -i:比如sed -i 's/http:\/\/old.com/https:\/\/new.com/g' big.log,比 PHP 快 10 倍且不占 PHP 内存
正则替换必须加 u 修饰符,否则中文全跪
正则在 Notepad++ 里能匹配,PHP 里返回原串?八成是编码或修饰符问题。preg_replace 默认按字节匹配,UTF-8 中文占 3 字节,不加 u 就当 3 个乱码字符处理。
立即学习“PHP免费学习笔记(深入)”;
- 含中文的模式必须带
/u:比如preg_replace('/姓名:(.+?)/u', '姓名:张三', $content) - 跨行匹配要加
s修饰符:/pattern/s让.匹配换行符,否则.*在 HTML 标签间直接失效 - 用户输入的搜索词必须过
preg_quote($search, '/'),否则$search = 'a.b'会变成正则漏洞 - 别在循环里拼接正则:
'/v' . $old_version . '/'每次都重新编译,提成常量或变量复用
配置文件别字符串替换,JSON/INI 要走专用流程
str_replace('DB_HOST=127.0.0.1', 'DB_HOST=10.0.0.1', $content) 看似简单,但会把 DB_HOST_BACKUP 也一起改掉;更糟的是,JSON 里漏个逗号或 BOM 头,json_decode 直接返回 null,你还以为替换成功了。
- INI 文件:用
parse_ini_file($path, true, INI_SCANNER_RAW)读,自己实现write_ini_file()保持格式,别手写字符串拼接 - JSON 文件:必须
$data = json_decode($content, true); if (json_last_error() !== JSON_ERROR_NONE) { die('JSON 解析失败'); } - 生产环境禁止直接覆盖:生成
config.new→file_put_contents→rename()原子切换,防止写到一半服务读到半截配置 - 嵌套字段赋值前先判空:
isset($cfg['database']) || $cfg['database'] = [];,否则$cfg['database']['host'] = 'xxx'报 Notice
最易被忽略的点:所有方法都依赖文件编码一致性。同一个项目里,有的文件是 UTF-8 without BOM,有的带 BOM,有的是 GBK——str_replace 和 preg_replace 都会错位。动手前先批量查编码,别等替换了才发现中文变方块。



















