PHP错误日志与调试:WP_DEBUG、日志分析与故障定位
一、为什么先开日志而不是先猜
WordPress白屏是最让人慌的故障:页面一片空白,没有报错,没有提示。多数人的第一反应是换主题、关插件、重启服务器,其实打开日志三分钟就能看到真因。
PHP错误分三级:Fatal致命错误直接终止脚本,这是白屏和500的元凶;Warning警告不终止,但说明逻辑有问题;Notice提示只是不规范,不影响运行。排错先盯Fatal。
反直觉点在于,WordPress的白屏九成是PHP致命错误(调用了不存在的函数、类、语法错误),不是数据库连接失败。数据库出错WP会明确提示建立数据库连接错误,不会白屏。
常见的致命错误来源就三类:插件升级后用了PHP新版本废弃的函数;主题里手滑改了php文件漏分号;两个插件函数名冲突。
按出现频率排,插件问题占白屏事故的七成以上,主题问题占两成,核心文件被改只占一成。所以排错先从插件下手。
| 错误级别 | 表现 | 是否终止请求 | 优先级 |
|---|---|---|---|
| Fatal Error | 白屏、500 | 是 | 最高,先查 |
| Parse Error | 整个站打不开 | 是 | 最高,多半是改坏了php |
| Warning | 功能异常但页面能出 | 否 | 次之 |
| Notice | 无明显症状 | 否 | 排完Fatal再看 |
二、WP_DEBUG的正确开法
wp-config.php里四个常量决定调试行为。线上的标准配置是:WP_DEBUG开、WP_DEBUG_LOG开、WP_DEBUG_DISPLAY关。错误写进wp-content/debug.log,访客看不到。
最忌讳的做法是把WP_DEBUG_DISPLAY也开着,让错误直接显示在页面上。这会暴露服务器路径、数据库表名等敏感信息,给攻击者递刀。
场景示例一:上线后某个产品页白屏。
在wp-config.php加define(‘WP_DEBUG_LOG’, true),define(‘WP_DEBUG_DISPLAY’, false)。
刷新一次那个白屏页面,打开wp-content/debug.log,最底下一行Fatal就写明了出错的插件和行号。
| 常量 | 线上值 | 作用 |
|---|---|---|
| WP_DEBUG | true | 总开关 |
| WP_DEBUG_LOG | true | 错误写入debug.log |
| WP_DEBUG_DISPLAY | false | 不在页面显示错误 |
| SCRIPT_DEBUG | false | 不加载未压缩js/css |
排完错别让日志一直写。debug.log会无限增长,几周后写爆磁盘。两种处理:加日志轮转,或定位修复后把WP_DEBUG关回false。磁盘被日志写满导致整站不可用,是真实发生过的事故。日志管理的整体方法见 独立站日志管理。
三、按现象分流:白屏、500、慢
不同现象对应不同日志,别拿着PHP日志找慢查询。先把故障现象归类,再去翻对应的日志。
白屏和500看PHP错误日志;页面能开但加载超过5秒,看PHP-FPM慢日志和MySQL慢查询;数据库类问题看慢查询日志和索引,方法见 独立站数据库优化。
场景示例二:产品列表页加载8秒。先看PHP错误日志,没有Fatal;再开PHP-FPM慢日志,发现请求卡在一个查询上;最后在MySQL慢日志里定位到那条没有索引的WHERE,加索引后降到0.4秒。
还有一类是PHP-FPM进程池打满。表现为偶发502,高峰期出现。这时候看的是Nginx错误日志,不是PHP错误日志。
进程池打满说明并发请求超过了pm.max_children配置,要么调大进程数,要么优化慢查询减少单请求耗时。
| 现象 | 先看哪里 | 典型根因 |
|---|---|---|
| 整站白屏 | PHP Fatal日志 | 插件致命错误或语法错 |
| 后台能进前台白屏 | PHP Fatal日志 | 主题functions.php报错 |
| 页面5秒以上 | PHP-FPM慢日志 | 慢SQL或外部请求阻塞 |
| 偶发502 | Nginx错误日志 | PHP-FPM进程池打满 |
与Nginx访问日志的区别要清楚:访问日志记录谁在什么时候请求了什么URL,PHP错误日志记录代码哪里出错。前者用于分析爬虫和流量,见 独立站日志分析;后者用于修bug,是本文重点。
四、插件冲突的二分定位法
日志指向某个报错文件,但你不确定是哪个插件引起的,用二分法:先禁用一半插件,复现问题;问题还在说明在这一半里,问题消失说明在另一半。几轮就能缩到具体插件。
主题问题同理。临时切到默认主题(Twenty Twenty-Four),如果白屏消失,就是当前主题的问题;还在,就回到插件二分。
PHP版本升级后出问题,多半是旧插件用了废弃函数。升级前先在测试环境跑一遍,兼容性检查方法见 独立站PHP版本升级。
| 步骤 | 动作 | 判定 |
|---|---|---|
| 1 | 全部插件禁用 | 问题消失→插件冲突 |
| 2 | 启用一半插件 | 复现→在这一半 |
| 3 | 继续二分 | 两轮内锁定具体插件 |
| 4 | 换默认主题 | 消失→主题问题 |
场景示例四:升级PHP 8.2后产品页白屏。日志提示call to undefined函数each(),这是PHP 8.1废弃的函数。
找到出错的那个旧插件,要么升级到兼容新版的版本,要么暂时停用。不要为了一个旧插件把PHP版本降回去。
修复后再观察一周,确认没有新的Fatal冒出来,再把WP_DEBUG关回false。
FAQ 常见问题
WordPress白屏了,第一步该做什么?
线上可以开WP_DEBUG_DISPLAY让错误显示在页面上吗?
debug.log会不会把磁盘写满?
页面能打开但特别慢,看PHP错误日志有用吗?
怎么快速定位是哪个插件引起的白屏?
PHP错误日志和Nginx访问日志有什么区别?
写在最后
排错最大的成本不是技术,是方向。对着错的日志翻半小时,不如先花一分钟判断这是白屏、500还是慢,再去翻对应的日志。
落地三步:wp-config里长期保持WP_DEBUG_LOG开、display关;白屏先看Fatal,慢先看慢日志;插件冲突用二分法两轮定位。
还有一个新手容易犯的错:把display_errors在php.ini里全局打开调试,调完忘了关。
结果线上每一个Warning都暴露在页面上,被爬虫抓去缓存,搜索结果里出现服务器路径。调完务必改回Off。
日志轮转建议用logrotate,按天切割,保留最近14天。这样debug.log不会无限增长,出问题又能回溯到两周内的记录。
最后提醒:修复后不要立刻关日志。再观察7天,确认没有新的Fatal冒出来,再把WP_DEBUG关回false,避免问题复发却没有记录。
还有一个细节:debug.log的权限。它在wp-content目录下,Web进程可写。
如果服务器配置错误,外部可能直接通过访问/wp-content/debug.log下载到你的错误日志,里面有路径、插件名、SQL错误。
所以要么把debug.log放到web根目录之外,要么在Nginx里禁止访问这个文件。这是常被忽略的信息泄露点。
还有一个新手误区:遇到白屏就去改主题、换插件,却从不想看日志。
其实打开wp-config加两行配置、刷新一次页面、打开debug.log,三分钟就能看到真因。跳过这步直接乱改,往往把好的也改坏了。
养成”先看日志再动手”的习惯,排错效率会高一个数量级。
最后一句:线上WP_DEBUG_LOG可以常开,但display永远关。日志是给你看的,不是给访客看的。
把这四条记牢:开日志、关显示、复现、二分。排错就这四步,不需要玄学。
下次再遇到白屏,先别慌着重启,先打开debug.log。错误早就写在那里了,只是没人去看。
把这套流程固化下来,比死记一百个报错字符串有用得多。下次再来新人,直接让他照着这四步走,不用每次都从头摸索半天,浪费宝贵的排错时间和团队人力成本。这才是真正的效率杠杆所在。
一句可以记住的话:线上排错的第一动作不是重启,是打开debug.log——错误早就写在那里了。
