本地开发应开启 display_errors 便于调试,线上必须关闭并启用 log_errors 写入安全日志;审计日志需用 Monolog 避免并发锁和路径泄露;error_reporting 线上仅保留 E_ERROR | E_WARNING | E_PARSE;logrotate 必须配置权限与轮转策略。

本地开发环境默认开启 display_errors,线上必须关闭
本地环境常设 display_errors = On 便于快速看到错误堆栈,但线上若开启,PHP Fatal error 或 Warning 会直接输出到 HTML 响应体,泄露路径、扩展名、数据库结构等敏感信息。线上必须设为 Off,同时确保 log_errors = On 和 error_log 指向可写日志文件(如 /var/log/php/error.log)。
容易踩的坑:display_errors 可被 ini_set() 动态覆盖,但线上代码里调用 ini_set('display_errors', '1') 仍会生效——务必全局搜索并删除这类语句。
审计日志在本地可写文件,线上必须用 Monolog + StreamHandler
本地用 file_put_contents('audit.log', $line, FILE_APPEND | LOCK_EX) 看似简单,但线上高并发时 LOCK_EX 会导致请求排队、响应延迟飙升;更严重的是,若日志路径在 Web 目录下(如 ./logs/audit.log),攻击者可通过 https://example.com/logs/audit.log 直接下载全部操作记录。
线上必须:
立即学习“PHP免费学习笔记(深入)”;
- 日志路径放在 Web 根目录外,例如
/var/log/myapp/audit.log - 用
Monolog\Logger('audit')创建独立 channel,绑定StreamHandler - 禁用
LineFormatter中的%context%直接输出(避免数组变Array字符串丢失细节) - 对
user_id、ip、target_id等字段做最小化脱敏(如substr($ip, 0, -3) . 'xxx')
error_reporting 级别差异:本地 E_ALL,线上只开 E_ERROR | E_WARNING | E_PARSE
本地设 error_reporting = E_ALL 能捕获 Notice 和 Deprecated,方便发现潜在问题;但线上开启 E_NOTICE 会导致日志爆炸式增长(比如未定义数组键、变量未初始化),掩盖真正致命错误。
线上推荐配置:
-
error_reporting = E_ERROR | E_WARNING | E_PARSE(PHP 8+ 可用E_CORE_ERROR | E_COMPILE_ERROR | E_ERROR | E_WARNING更精准) - 若需临时排查,改完立刻回滚,切勿长期开启
E_ALL -
track_errors = Off(避免$php_errormsg全局变量污染)
线上必须启用 logrotate,本地通常忽略
线上日志不轮转,/var/log/php/error.log 几天就能撑爆磁盘;而本地开发跑几天可能才几 KB,没人配 logrotate。但上线前必须确认系统已配置:
- logrotate 配置文件存在(如
/etc/logrotate.d/php) - 包含
rotate 30、daily、compress、missingok等关键指令 - 日志文件权限为
640,属主属组匹配 PHP 进程用户(如www-data:adm)
最易被忽略的是权限和组设置——logrotate 以 root 执行,但压缩后的日志若属主不是 web 进程用户,PHP 就无法继续写入新日志。



















