PHP报错被隐藏的根源在于其自身错误报告与显示机制未启用,需同时满足error_reporting非0且display_errors=On,且FPM配置优先级高于php.ini,重启php-fpm才生效。

PHP 报错被隐藏,不是 Nginx 的锅,而是 PHP 自身的错误报告和显示机制被关掉了 —— 开启它需要同时满足两个条件:错误要被报告,且允许显示。
为什么 display_errors = On 却没用?
常见现象是改了 php.ini 里的 display_errors = On,但页面还是只返回 500 或空白。原因通常是:
-
error_reporting值为0或过低(比如只设E_ERROR),导致 Notice、Warning 等低级别错误根本不会触发报告 - 配置被覆盖:PHP-FPM 的
www.conf中用php_flag[display_errors] = off强制关闭,会优先于php.ini - 运行时被代码覆盖:比如某处写了
ini_set('display_errors', '0')或error_reporting(0) - CLI 和 Web SAPI 配置不同:
php -i | grep php.ini查到的是 CLI 的配置路径,而 Nginx 走的是 FPM SAPI,要用phpinfo()页面确认实际加载的php.ini和生效值
php-fpm.conf 或 www.conf 中的 php_flag 设置优先级最高
在生产环境里,php.ini 的设置常被 PHP-FPM 配置覆盖。Nginx + PHP-FPM 架构下,真正起效的是 FPM pool 配置文件(如 /etc/php/8.2/fpm/pool.d/www.conf)中的 php_flag 和 php_admin_flag:
-
php_flag[display_errors] = on:仅对当前 pool 生效,可被运行时ini_set覆盖 -
php_admin_flag[display_errors] = on:强制生效,运行时无法修改(注意:部分旧版本不支持admin_flag) -
php_admin_value[error_log] = /var/log/php/error.log:必须配,否则即使报错也不落盘 - 改完必须重启
php-fpm:sudo systemctl restart php8.2-fpm(版本号按实际调整)
开发环境推荐的最小安全组合
既要看到错误,又不能把敏感信息暴露给用户(比如数据库密码出现在 Warning 里),建议这样配:
立即学习“PHP免费学习笔记(深入)”;
-
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED:覆盖所有致命/警告类错误,过滤掉易误报的提示 -
display_errors = Off(php.ini里保持关闭) -
log_errors = On:确保错误写入日志 -
error_log = /var/log/php/error.log:指定日志路径,注意目录权限(www-data或nginx用户需有写权限) - 在入口脚本(如
index.php)开头加:ini_set('display_errors', '1'); error_reporting(E_ALL);—— 仅限开发机,上线前删掉
Nginx 层面能做的只有转发和兜底
Nginx 本身不解析 PHP,它只负责把请求甩给 PHP-FPM,并接收响应。但它可以帮你发现“错误根本没发出去”的情况:
- 检查
fastcgi_pass地址是否正确(unix:/run/php/php8.2-fpm.sock还是127.0.0.1:9000?路径/端口错会导致 502,不是 500) - 加
fastcgi_param PHP_VALUE "display_errors=1; error_reporting=E_ALL";到 location 块里,作为最后保险(但不如 FPM 配置可靠) - 确认
try_files $uri =404;没误删.php文件路径,否则直接 404,根本不会进 PHP - 查
/var/log/nginx/error.log:如果出现FastCGI sent in stderr: "Primary script unknown",说明SCRIPT_FILENAME拼错了,不是 PHP 不报错,是压根没执行
最常被忽略的一点:错误日志路径的父目录权限不对,或者磁盘已满,导致 log_errors = On 形同虚设 —— 先 ls -l /var/log/php/ 看属主,再 df -h 看空间。



















