敏感配置文件须移出web根目录并用绝对路径引入,数据库密码等敏感信息应通过环境变量传递,错误处理需关闭display_errors、设置error_reporting、注册shutdown函数捕获致命错误,并用set_exception_handler处理php8+的typeerror。

敏感配置文件必须移出 Web 根目录
直接放在 /var/www/html/config.php 这类路径下,一旦 PHP 解析失败或 Nginx/Apache 配置出错,源码就会裸露——这不是“可能”,而是真实发生过的漏洞。正确做法是把配置文件放到 Web 无法访问的位置,比如 /var/www/config/database.php(假设 Web 根目录是 /var/www/html/),然后在入口脚本中用绝对路径引入:require '/var/www/config/database.php';。这样哪怕用户拼出 https://site.com/config/database.php,服务器也只会返回 404,根本不会触发文件读取逻辑。
数据库密码等敏感值别硬编码,走环境变量
硬写在 PHP 文件里的 $db_pass = '123456'; 是最常见也是最危险的泄露点。Nginx 中应通过 fastcgi_param DB_PASS "s3cr3t!"; 注入,PHP 里用 getenv('DB_PASS') 或 $_ENV['DB_PASS'] ?? '' 读取。开发阶段可用 .env 文件配合 vizualab/phpdotenv 加载,但上线前必须删掉 .env,只依赖服务器环境变量运行——否则 Git 提交、FTP 误传都可能让它暴露。
set_error_handler() 本身不隐藏错误,必须配合三件事
很多人以为注册了 set_error_handler() 就万事大吉,结果线上页面还是打印出一堆路径和 SQL 错误。这是因为:set_error_handler() 只接管处理逻辑,不阻止输出;display_errors = On 时错误照常打到浏览器;致命错误(如 Fatal error: Call to undefined function)压根不会进这个回调。
- 必须提前关闭输出:
ini_set('display_errors', '0'); - 要过滤级别:
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED); - 必须补漏致命错误:
register_shutdown_function()+error_get_last()判断是否为E_ERROR、E_PARSE等类型,并只记日志、不 echo
PHP 8.0+ 还要注意:类型错误(如传 string 给 int 参数)会抛 TypeError 异常,得用 set_exception_handler() 捕获,set_error_handler() 对它无效。
自定义错误页面不能只靠 HTTP 状态码跳转
单纯在 Nginx 里配 error_page 500 /500.html; 很危险——如果 PHP 崩溃前已输出部分 HTML,再跳转就可能混杂原始错误堆栈。更稳妥的方式是框架级拦截(如 ThinkPHP 的 ExceptionHandler 类),或在入口统一捕获后渲染模板。关键点有三个:
- 错误页面模板(如
500.html)不能含任何 PHP 逻辑,纯静态 HTML + CSS - 确保模板路径不在 Web 可写目录下,避免被上传覆盖
- 所有错误响应必须先清空输出缓冲:
ob_end_clean();,再http_response_code(500);输出页面
最容易被忽略的是:错误页面本身如果包含动态内容(比如试图读取 session 或调用数据库),反而可能触发新错误,导致循环崩溃或信息二次泄露。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











