生产环境必须关闭错误回显并安全记录错误:设 display_errors = Off、log_errors = On 且指定 error_log 路径,禁用代码中 ini_set 临时开启,catch 中不输出异常详情,Web 服务器层和自定义错误处理器需同步兜底。

生产环境必须关闭错误回显,同时确保错误被安全记录——不是“不让它发生”,而是“让它只去该去的地方”。
关掉 display_errors 是硬性底线
PHP 默认开启 display_errors = On,一旦出错,堆栈、文件绝对路径、数据库连接字符串甚至密码都可能直接打在页面上。攻击者刷新几次 500 页面,就能拼出你的 config.php 路径和 $db_password 值。
- 在
php.ini中设为display_errors = Off,并重启 Web 服务(Apache/Nginx)或 php-fpm - 别用
ini_set('display_errors', '1')在代码里临时打开——它容易被遗忘,且对解析错误(如语法错误)完全无效 - 多配置场景下要留意覆盖关系:php-fpm pool 配置中可用
php_admin_flag[display_errors] = off强制锁定,防脚本绕过 - 验证是否生效:写个测试脚本
<?php trigger_error('test', E_USER_WARNING); ?>,访问后页面空白才算成功;也可查phpinfo()中 “Local Value” 是否为 Off
错误必须进日志,不能丢也不能乱放
关显示 ≠ 关错误。不记录,等于在生产环境闭眼开车。
- 启用
log_errors = On,并明确指定error_log = /var/log/php/app_errors.log(Linux)或error_log = C:\php\logs\app_errors.log(Windows) - 路径需确保 PHP 进程有写权限;避免留空或用
syslog,前者会退化到 Web 服务器日志(难定位),后者缺请求上下文(如 URI、IP) - 错误级别建议设为
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT,既覆盖关键问题,又避免E_NOTICE日志爆炸 - 可在入口文件(如
index.php)开头加ini_set('error_log', '/path/to/app_errors.log');做二次确认
catch 里别 echo 异常详情
很多人以为用了 try-catch 就安全了,结果在 catch 块里写 echo $e->getMessage() 或 var_dump($e),照样把 SQL 语句、参数值、完整堆栈全吐出去。
立即学习“PHP免费学习笔记(深入)”;
- 正确做法:只记录原始异常,前端返回通用提示,例如“操作失败,请稍后重试”
- 记录推荐用
error_log($e->__toString(), 4)或写入自定义日志文件(注意防范日志注入) - 如需区分错误类型,用自定义错误码(如
ERR_PAYMENT_TIMEOUT),而非暴露异常细节 - 绝对不要在
catch中调用debug_print_backtrace()—— 它专为开发设计,上线即高危
Web 服务器层和自定义处理器要兜底
PHP 层关了,不代表错误不会从 Nginx/Apache 漏出来。PHP 崩溃、超时、FastCGI 异常响应时,Web 服务器可能原样返回错误体。
- Apache 下,在
.htaccess或虚拟主机配置中加php_flag display_errors off - Nginx 下,确保
fastcgi_param PHP_VALUE "display_errors=Off"已配置,漏配就失效 - 用
set_error_handler()拦截传统错误(E_WARNING等),回调中只记录、不输出,并返回 true 阻止默认处理 - 自定义处理器里别打印
$_SERVER或$_REQUEST,否则等于把全部 GET/POST 参数、请求头、服务器路径一股脑公开



















