线上环境必须关闭PHP错误显示:display_errors=Off、error_reporting设为0或过滤低危项、log_errors=On并指定可写日志路径;优先修改php.ini并重启服务;同时关闭expose_php、html_errors、track_errors。

PHP线上环境如何关闭所有错误显示
线上环境绝不能暴露错误信息给用户,否则可能泄露路径、数据库结构甚至敏感代码逻辑。display_errors 必须关,但光关它还不够——error_reporting 和 log_errors 也要同步调准。
-
display_errors = Off:这是最直接的开关,必须设为Off(注意不是0或False) -
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT:保留记录级别,但不显示;线上建议用0彻底关闭报告,或用E_ALL & ~E_NOTICE & ~E_DEPRECATED过滤低危项 -
log_errors = On:确保错误写入日志,别让它消失 -
error_log = /var/log/php/error.log:指定日志路径,确认该目录存在且 PHP 进程有写权限(常见坑:日志路径没写权限,结果错误既不显示也不落盘)
php.ini、.htaccess、ini_set 哪个优先级最高
优先级顺序是:Apache .htaccess > php.ini > ini_set()。但线上环境通常禁用 .htaccess 覆盖(AllowOverride None),且禁止运行时修改关键安全项(如 ini_set('display_errors', '0') 在某些 SAPI 下会被忽略)。
- 推荐只改
php.ini,重启 PHP-FPM 或 Apache 生效,最可靠 -
.htaccess仅在 Apache +AllowOverride All时有效,且不支持所有指令(如error_log就不被允许) -
ini_set()在 CLI 或部分 FastCGI 场景下可能无效,且无法覆盖display_errors的初始值(它在脚本启动前已锁定)
为什么开了 log_errors 却没看到错误日志
常见原因是日志路径不可写,或错误等级被 error_reporting 过滤掉了。另一个隐蔽问题是:PHP 没有权限往 error_log 指定的目录写文件,尤其当用了自定义路径但没配 SELinux 上下文或 systemd PrivateTmp=true 时。
- 用
php -i | grep error_log确认实际生效的error_log路径 - 执行
ls -ld /var/log/php/检查属主和权限(通常应属www-data或nginx用户) - 临时测试:在脚本里写
error_log('test from php', 3, '/var/log/php/test.log');,看能否写入 - 如果用的是容器或 systemd 服务,检查是否启用了
PrivateTmp=true——这会让/tmp和日志路径失效
额外要关的三个危险配置项
除了错误显示,还有几个默认开启的“调试友好型”选项在线上属于高危项,必须手动关闭:
立即学习“PHP免费学习笔记(深入)”;
-
expose_php = Off:关掉响应头里的X-Powered-By: PHP/8.x.x,减少指纹暴露 -
html_errors = Off:避免错误信息被渲染成 HTML 表格(即使display_errors=On已关,此选项仍影响格式输出) -
track_errors = Off:禁用全局$php_errormsg变量,防止意外泄露上一条错误内容
改完配置后务必验证:php -m | grep -i "opcache\|xdebug" 确保没加载 Xdebug(它会绕过 display_errors 直接输出堆栈),再用 php -i | grep -E "(display_errors|error_reporting|log_errors|expose_php)" 确认所有值符合预期。最易忽略的是:开发环境改了配置,但上线时漏同步 php-fpm pool 的 php_admin_flag 设置,导致 Nginx 下的 PHP 仍继承默认值。











