
PHP 的error_reporting(错误报告)机制决定哪些错误会被显示、记录或静默忽略。正确配置它对两个阶段都至关重要:开发阶段需要完全的可见性,而生产服务器上则应当记录错误但绝不对用户展示。
本指南介绍如何借助 php.ini、error_reporting() 函数以及 .htaccess 来配置 PHP 错误报告。如果不确定当前启用的是哪个 PHP 版本,请先查阅 PHP 版本指南。
快速参考
如需可打印的快速参考,请查看 PHP 速查表。
| 任务 | 配置 / 命令 |
|---|---|
| 在 php.ini 中启用所有错误 | error_reporting = E_ALL |
| 在屏幕上显示错误 | display_errors = On |
| 对用户隐藏错误(生产环境) | display_errors = Off |
| 将错误记录到文件 | log_errors = On |
| 设置自定义日志文件 | error_log = /var/log/php/error.log |
| 在运行时启用所有错误 | error_reporting(E_ALL); |
| 在运行时抑制所有错误 | error_reporting(0); |
| 在 PHP-FPM 上按目录设置错误 | .user.ini in the web root |
| 为 FPM 进程池固定错误设置 | php_admin_value[error_log] |
PHP 错误级别
PHP 将错误划分为多个级别(level)。每个级别都有名称(常量)和对应的数值。你可以使用位运算符组合多个级别,从而精确控制究竟报告哪些错误。
最常用的级别如下:
PHP 8.4 中有两处变化:E_STRICT 级别已被弃用且不再使用,同时 E_ALL 的值从 32767 降为 30719,因为 E_STRICT 已从中移除。旧教程常推荐 E_ALL & ~E_STRICT,但在当前 PHP 中它会屏蔽一个 E_ALL 已不再包含、因此毫无作用的级别。
有关错误常量的完整列表,请参阅 PHP 错误常量文档。
在 php.ini 中配置错误报告
php.ini 是 PHP 的主配置文件。在此文件中的修改会全局应用于所有使用该配置文件的 PHP 脚本。编辑完成后,需要重新加载运行 PHP 的进程:使用 mod_php 时重载 Apache,使用 FPM 时重载 PHP-FPM。CLI 命令则会在每次启动时读取 php.ini。
要查找当前生效的 php.ini 文件位置,请运行:
php --ini
启用错误报告
打开 php.ini 并设置以下指令:
; Report all errors
error_reporting = E_ALL
; Display errors on the page (development only)
display_errors = On
; Display startup sequence errors
display_startup_errors = On
display_errors。向用户显示错误信息会暴露文件路径、数据库查询和内部逻辑,可能被攻击者利用。将错误记录到文件
若要将错误写入日志文件(而非显示在屏幕上),请设置:
; Disable displaying errors
display_errors = Off
; Enable error logging
log_errors = On
; Set the path to the log file
error_log = /var/log/php/error.log
请确保该目录存在且对 Web 服务器用户可写。要创建该目录:
sudo mkdir -p /var/log/php
sudo chown www-data:www-data /var/log/php
推荐的开发环境配置
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
error_log = /var/log/php/error.log
推荐的生产环境配置
error_reporting = E_ALL & ~E_DEPRECATED
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/error.log
该配置会报告除弃用(deprecation)通知以外的所有错误,并在不向用户展示任何内容的前提下,将所选的每一条错误都记录下来。
在运行时配置错误报告
你可以在 PHP 脚本内部使用 error_reporting() 函数和 ini_set() 覆盖 php.ini 中的设置。这种运行时修改仅对当前脚本生效。
要在脚本顶部启用所有错误:
<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
要报告除通知(notice)以外的所有错误:
<?php
error_reporting(E_ALL & ~E_NOTICE);
要抑制所有错误输出(不推荐用于调试):
<?php
error_reporting(0);
运行时配置在无法访问 php.ini 的开发阶段很有用,但它不应取代生产环境中规范的服务器级配置。
在 .htaccess 中配置错误报告
如果你处在无法访问 php.ini 的共享主机环境中,可以通过 .htaccess(当 PHP 以 Apache 模块方式运行时)来配置 PHP 错误报告:
php_flag display_errors On
php_value error_reporting -1
php_flag log_errors On
php_value error_log /var/log/php/error.log
将 error_reporting 设为 -1 会启用所有可能存在的错误,包括未来 PHP 版本中新增的错误。
mod_php)方式运行时,.htaccess 指令才会生效;对于 PHP-FPM 则毫无作用。使用 .user.ini 配置错误报告
当前大多数主机都通过 PHP-FPM 或 FastCGI 而非 Apache 模块来运行 PHP,这正是上述 .htaccess 指令常常被忽略的原因。这些 SAPI 会读取一个名为 .user.ini 的按目录配置文件,它让你无需访问主 php.ini 即可获得同样的按站点控制能力。
在你想要配置的目录中创建该文件,在典型的共享主机上这个目录就是 Web 根目录:
error_reporting = E_ALL
display_errors = Off
log_errors = On
error_log = /home/user/logs/php-errors.log
PHP 会从被请求脚本所在目录开始扫描 .user.ini,并向上回溯到文档根目录,因此 Web 根目录中的一个文件即可覆盖整个站点。只有变更模式为 INI_ALL、INI_PERDIR 或 INI_USER 的指令才会被接受,而上面这四项设置都在其范围内。
修改不会立即生效。PHP 会按 user_ini.cache_ttl 设定的秒数对解析后的文件进行缓存,默认值为 300。如果某次修改看起来被忽略了,请先等待五分钟再重新加载页面,不要急于认定文件放错了目录。
在 PHP-FPM 进程池中配置错误报告
在你管理的服务器上,进程池(pool)配置才是为某个站点固定错误处理方式的正确位置。在 Ubuntu 和 Debian 上,进程池文件为 /etc/php/<version>/fpm/pool.d/www.conf,例如 Ubuntu 26.04 上是 /etc/php/8.5/fpm/pool.d/www.conf,Debian 13 上是 /etc/php/8.4/fpm/pool.d/www.conf。Fedora、RHEL 及其衍生版则使用 /etc/php-fpm.d/www.conf。
下面的示例复用了本指南前面创建的 /var/log/php 目录:
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/log/php/error.log
php_admin_flag[display_errors] = off
Fedora 和 RHEL 会在安装 PHP-FPM 软件包时创建 /var/log/php-fpm,因此你可以直接使用打包提供的 /var/log/php-fpm/www-error.log 路径。无论选择哪条路径,都必须对进程池用户可写。
php_admin_value 与 php_admin_flag 指令和 php_value、php_flag 的区别在于一点:脚本无法通过 ini_set() 覆盖它们。这正是生产环境进程池中将 display_errors 设为它们的合适选择——应用程序不应能够自行重新打开错误输出。
编辑进程池文件后需要重新加载服务。Ubuntu 和 Debian 使用带版本号的服务单元。例如 Ubuntu 26.04 使用:
sudo systemctl reload php8.5-fpm
Debian 13 使用 php8.4-fpm。Fedora、RHEL 及其衍生版使用不带版本号的服务单元:
sudo systemctl reload php-fpm
查看 PHP 错误日志
一旦启用了 log_errors,错误就会被写入 error_log 指定的文件。要实时监控日志,可使用 tail -f 命令:
sudo tail -f /var/log/php/error.log
当未设置 error_log 时,PHP 会将消息交给当前活动 SAPI 的错误记录器,因此消息落点取决于 PHP 的运行方式:
FPM 进程池的 catch_workers_output 设置并不控制 PHP 的 log_errors 指令所产生的消息。它只重定向工作进程或扩展直接写入自身标准输出和标准错误流的那些输出。普通的 PHP 错误仍会进入配置好的 PHP 日志,或者在 error_log 未设置时进入主 FPM 日志。
Nginx 本身并不执行 PHP。PHP 错误通常会进入 PHP 或 FPM 日志,但 FPM 经由 FastCGI 错误流发送的消息可能以「FastCGI sent in stderr」的形式出现在 /var/log/nginx/error.log 中。当 PHP 无法打开其配置的日志文件时就会发生这种情况,因此在预期的 PHP 日志仍然为空时,请同时检查两个日志。我们的 Nginx 日志文件指南介绍了 Nginx 日志包含的内容,500 Internal Server Error 指南则追溯了跨两个服务的失败请求。
有关相关服务命令,请参阅如何启动、停止或重启 Apache,以及如何启动、停止或重启 Nginx。
故障排查
即使 display_errors = On 仍不显示错误:请确认你编辑的是正确的 php.ini 文件。运行 php --ini 或在脚本中调用 phpinfo(),即可查看加载的是哪个配置文件以及 display_errors 的当前值。
php.ini 的修改没有生效:编辑 php.ini 后需要重新加载运行 PHP 的进程。对于使用 mod_php 的 Apache,在 Ubuntu 或 Debian 上运行 sudo systemctl reload apache2,在 Fedora 或 RHEL 上重新加载 httpd;对于 PHP-FPM,则重新加载其服务,例如 Ubuntu 26.04 上的 php8.5-fpm、Debian 13 上的 php8.4-fpm,或 Fedora 和 RHEL 上的 php-fpm。Nginx 无需重载,因为它不读取 php.ini。
日志文件中没有任何错误:请检查日志文件路径对 PHP 进程用户是否可写,以及当前生效的 php.ini 中是否设置了 log_errors = On。在 PHP-FPM 下,当 error_log 未设置时,请检查主 FPM 日志。php-fpm.conf 中的全局 error_log 指令显示了该日志的位置。
.user.ini 的修改被忽略:PHP 会按 user_ini.cache_ttl 秒数缓存该文件,默认 300 秒。在进一步排查之前,请给缓存留出过期时间。同时确认 PHP 运行在 FPM 或 FastCGI 之下,因为 mod_php 根本不会读取 .user.ini。
ini_set('display_errors', '1') 没有效果:致命解析错误(E_PARSE)发生在任何 PHP 代码运行之前,因此 ini_set() 无法捕获它们。请在 php.ini 或 .htaccess 中启用 display_errors 才能看到解析错误。
错误抑制运算符 @ 隐藏了错误:PHP 的 @ 前缀会抑制单个表达式的错误。如果某个特定函数的错误没有出现在日志中,请检查该调用是否以 @ 为前缀。
常见问题
display_errors 与 log_errors 有什么区别?display_errors 控制错误是否直接输出到浏览器或 CLI;log_errors 控制错误是否写入错误日志文件。在生产环境中,始终应将 display_errors = Off 且 log_errors = On。
我应该使用哪个 error_reporting 级别?开发阶段使用 E_ALL 以捕获每一个可能的问题;生产环境使用 E_ALL & ~E_DEPRECATED 来记录严重错误,同时抑制无需立即处理的弃用通知。
如何查看当前的错误报告级别?不带参数调用 error_reporting():它会以整数形式返回当前的位掩码。你也可以在 phpinfo() 的输出中查看。
能否将错误记录到数据库而非文件?无法经由 php.ini 直接实现。请使用通过 set_error_handler() 和 set_exception_handler() 注册的自定义错误处理程序,将错误发送到数据库、电子邮件或外部日志服务。
为什么 PHP 错误没有出现在 Nginx 错误日志中?Nginx 不执行 PHP,因此 PHP 警告通常会进入 PHP 或 PHP-FPM 配置的日志。不过 FPM 经由 FastCGI 错误流发送的消息仍可能以「FastCGI sent in stderr」的形式出现在 Nginx 错误日志中,尤其是在 PHP 无法写入其配置日志时。请先检查 PHP 或 FPM 日志,再查看 Nginx 错误日志中的 FastCGI 消息。
php.ini 位于何处?在命令行运行 php --ini,或在脚本中添加 <?php phpinfo(); ?> 并在浏览器中加载它。「Loaded Configuration File」一行会显示当前生效的路径。常见位置为 /etc/php/8.x/cli/php.ini(CLI)和 /etc/php/8.x/apache2/php.ini(Apache)。
结语
开发阶段,在 php.ini 中设置 error_reporting = E_ALL 和 display_errors = On,即可立即看到所有错误;生产环境则设置 display_errors = Off 和 log_errors = On,在不向用户暴露细节的前提下静默记录错误。
进行永久的服务器级配置请修改 php.ini;使用 error_reporting() 和 ini_set() 进行按脚本的覆盖;在没有 php.ini 访问权限的共享主机上请使用 .user.ini,或在主机仍用 Apache 模块运行 PHP 时使用 .htaccess。