最稳妥直接的方式是用file_get_contents读模板、str_replace或printf注入变量、file_put_contents写入;需过滤路径防穿越、校验返回值、处理编码与换行,超1MB或批量超1000时改用fopen流式写入。

PHP用file_get_contents和file_put_contents批量读写通知文件最稳妥
直接用file_get_contents读取模板,再用str_replace或printf注入变量,最后file_put_contents写入目标路径——这是最轻量、无依赖、兼容 PHP 5.6+ 的做法。不用引入模板引擎或队列,适合一次性生成几十到几百个通知文件(如用户欢迎信、订单确认单)。
常见错误是硬编码路径拼接:$path = 'notices/' . $user_id . '.txt',没做basename()过滤,导致路径穿越;或者忽略file_put_contents返回值,写失败也不报错。
- 模板文件建议放在
./templates/notice.txt,内容含占位符如{name}、{order_id} - 批量处理前先
is_dir('./output/') || mkdir('./output/', 0755, true)确保输出目录存在 - 每次写入后检查
file_put_contents返回值是否为false,并error_log("write failed: $path")
用fopen/fwrite控制大文件写入节奏,避免内存溢出
当单个通知内容超 1MB 或批量超 1000 个时,file_get_contents会把整个模板加载进内存,容易触发memory_limit错误。此时改用流式写入更安全。
典型场景:导出带 HTML 表格的账单通知,每个约 200KB,要生成 500 份。
立即学习“PHP免费学习笔记(深入)”;
- 用
$fp = fopen($output_path, 'w')打开文件,而不是file_put_contents - 模板中用
%s占位,调用fprintf($fp, $template, $name, $amount)逐段写入 - 写完必须
fclose($fp),否则文件句柄泄漏,后续fopen可能返回false
注意file_put_contents的FILE_APPEND和LOCK_EX参数冲突
有人想用FILE_APPEND | LOCK_EX实现多进程并发写同一日志文件,但file_put_contents在追加模式下不支持LOCK_EX——它会静默忽略锁,导致内容错乱。这不是 bug,是 PHP 文档明确写的限制。
如果你真需要并发写通知(比如多个 CLI 进程同时生成用户通知),正确做法是:每个进程写独立文件,最后用 shell 合并;或改用flock手动加锁:
$fp = fopen('notify_queue.log', 'c');
if (flock($fp, LOCK_EX)) {
fwrite($fp, "sent to {$user_id}
");
fflush($fp);
flock($fp, LOCK_UN);
}
fclose($fp);
Windows 下路径分隔符和换行符容易引发通知格式错乱
PHP 在 Windows 上默认用
换行,但某些邮件服务或终端只认
;另外__DIR__ . '/templates/'在 Windows 会变成C:path opp emplates,斜杠方向不对虽不影响读取,但用realpath()或str_replace('\', '/', __DIR__)统一更稳妥。
- 通知内容含换行时,统一用
,发邮件前再按需替换为 - 路径拼接一律用
dirname(__FILE__) . DIRECTORY_SEPARATOR . 'templates' - 用
mb_internal_encoding('UTF-8')避免中文文件名在file_put_contents中变乱码
md5_file($output_path)是否匹配预期哈希,比加一堆日志更可靠。



















