直接用file_put_contents()更合适,因其可自定义路径、格式和权限,并需加file_append | lock_ex确保并发安全;error_log()仅适合临时调试。

PHP写日志前先确认error_log()和file_put_contents()哪个更合适
直接用error_log()最省事,但默认会走系统日志或Web服务器配置路径,你未必找得到;file_put_contents()更可控,适合自定义路径、格式和权限,但得自己处理换行、并发写入和目录可写问题。
- 如果只是调试临时输出,
error_log('debug info')够用,但别依赖它查生产问题 - 正式记录操作日志(比如用户登录、订单修改),必须用
file_put_contents()并加FILE_APPEND | LOCK_EX -
error_log()在CLI和FPM下行为可能不一致,比如有些环境会丢掉时间戳
用file_put_contents()写日志时必须加LOCK_EX
多个请求同时写同一个日志文件,不加锁会导致内容错乱、换行丢失甚至部分写入被覆盖——这不是小概率事件,高并发下几乎必现。
- 正确写法:
file_put_contents('/var/log/myapp.log', $msg . "\n", FILE_APPEND | LOCK_EX) - 别用
fopen()+fwrite()手动模拟,容易漏关句柄或忘记fflush() - 如果日志量大,
LOCK_EX会造成轻微排队,但比数据损坏强得多
日志路径权限和目录存在性是上线后最常见的报错点
本地测试好好的,一上生产就failed to open stream: No such file or directory,大概率是路径里某一级目录不存在,或者Web进程用户(如www-data)没权限创建目录或写入文件。
- 写日志前先检查:
is_dir(dirname($log_path)) || mkdir(dirname($log_path), 0755, true) - 别把日志写进
/tmp还指望长期保留——某些系统会定时清理 - 避免写到Web根目录下,防止被直接下载(比如
/var/www/html/logs/)
简单日志格式别搞太复杂,但至少包含时间、来源和操作主体
纯文本日志不是为了好看,是为了快速定位“谁在什么时候干了什么”。JSON格式看着规范,但出问题时grep和tail反而更麻烦。
立即学习“PHP免费学习笔记(深入)”;
- 推荐基础格式:
date('Y-m-d H:i:s') . " [user:{$uid}] [action:login] IP:{$ip}\n" - 敏感字段(如密码、token)必须脱敏,哪怕只记
[token:***]也比明文强 - 别在日志里拼接大量变量,尤其未过滤的
$_GET或$_POST,容易引入换行或控制字符导致解析错乱











