file_put_contents 默认无条件覆盖原文件,即先截断再写入;追加需显式使用 file_append 标志;安全更新应采用临时文件+rename 的原子操作。

file_put_contents 默认会覆盖原文件。
它不是“选择性覆盖”,而是无条件清空再写入——哪怕只差一个字节没写完,原内容也已消失。这不是 bug,是设计行为。
默认行为就是覆盖,不加标志就别想保留旧数据
file_put_contents 的第三个参数 $flags 默认为 0,等价于显式传 0 或省略。此时函数会:
- 如果文件存在:先截断(truncate)为 0 字节,再写入新内容
- 如果文件不存在:直接创建并写入
- 不检查内容是否变化,不比对,不备份,不提示
常见误操作:
- 把日志写入配置文件路径,结果把
config.php覆盖成纯文本 - 用
$_POST['filename']拼接路径,用户传../../etc/passwd导致系统文件被清空 - 忘记加
FILE_APPEND,本想追加却删光了历史记录
追加必须显式传 FILE_APPEND,不能靠直觉
FILE_APPEND 不是“可选优化”,而是语义开关:不加它,就不是追加;加了,才跳过截断步骤,自动定位到文件末尾。
- 正确写法:
file_put_contents('log.txt', "new entry\n", FILE_APPEND) - 错误写法:
file_put_contents('log.txt', "new entry\n")(覆盖) - 更错写法:
file_put_contents('log.txt', "new entry\n", LOCK_EX)(仍覆盖,LOCK_EX只锁写过程,不改覆盖逻辑)
注意:
-
FILE_APPEND和LOCK_EX可以组合使用:FILE_APPEND | LOCK_EX - Windows 下若文件正被记事本打开,
FILE_APPEND也可能静默失败(返回false或0),务必检查返回值
生产环境别信覆盖,要用临时文件 + rename 实现原子更新
直接 file_put_contents($path, $data) 在磁盘满、进程崩溃、权限突变时,极易留下空文件或半截内容。
安全做法是三步走:
- 用
tempnam(sys_get_temp<em>dir(), 'upd</em>')创建同分区临时文件 -
file_put_contents($tmp, $data)写入,并校验返回值是否等于strlen($data) -
rename($tmp, $path)替换——该操作在 Linux/ext4、XFS、NTFS 上是原子的
关键限制:
-
rename()跨分区(如/tmp和/var/www不同挂载点)会失败,需 fallback 到copy() + unlink(),但失去原子性 - 临时文件必须和目标文件在同一目录或同设备,否则
rename()不保证原子
file_put_contents 的覆盖行为简单粗暴,但它的“简单”恰恰是陷阱来源:没有隐式保护,不自动备份,不校验写入完整性,也不抵抗并发冲突。真正可靠的替换,永远要自己控制临时路径、校验长度、处理 rename 失败、清理残留 tmp 文件。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











