PHP 5.2.9+MySQL 5.0.67 原有正常函数突然挂死问题排查
函数突然挂死问题排查
环境
PHP 5.2.9、MySQL 5.0.67
问题描述
一个运行多年正常的函数突然出现挂死情况,服务器未做任何变更。函数代码如下:
function getSettings($module= 'core') { global $db,$_SETTINGS_CACHE,$_SETTINGS,$JSON; $SettingsQuery = $db->query("SELECT data,displayorder,title,module,encoded FROM " . TABLE_PREFIX . "settingsfields WHERE module='$module'"); while($Setting = $db->fetch($SettingsQuery)) { $data = iif ($Setting['encoded'],$JSON->decode($Setting['data']),$Setting['data']); $module = $Setting['module']; $title = $Setting['title']; $_SETTINGS[$module][$title] = $data; $_SETTINGS_CACHE[$title] = $data; } return $_SETTINGS[$module]; }
通过strace追踪发现,程序卡在以下阶段直至达到最大执行时间:
write(4, "V\0\0\0\3SELECT data,displayorder,ti"..., 90) = 90 read(4, "\1\0\0\1\5E\0\0\2\3def\vdb_site\16settin"..., 16384) = 1802
直接在MySQL中执行查询语句SELECT data,displayorder,title,module,encoded FROM settingsfields WHERE module='core'可正常返回结果。
问题:该函数存在问题吗?为何会突然停止工作?
问题分析与原因
1. 函数存在明确的逻辑缺陷
循环内部的$module = $Setting['module'];语句属于不必要的变量覆盖:
- 函数入参
$module初始为'core',查询逻辑也是基于该值筛选记录,但循环中会将其覆盖为当前记录的module字段值。 - 若查询结果中存在
module字段值异常的记录(如空值、特殊字符),会导致$_SETTINGS[$module]的键名异常,可能引发后续数组操作的隐性问题,甚至干扰函数最终的返回值逻辑。
2. 死循环的核心触发点:JSON解码异常
从strace输出可知,MySQL已正常返回查询结果(read操作获取了1802字节数据),说明问题出在结果处理环节,而非数据库查询阶段:
- 循环中当
encoded为真时,会调用$JSON->decode($Setting['data'])解析JSON数据。PHP 5.2时代的JSON处理类(大概率为自定义/第三方实现,而非原生扩展)在遇到无效/畸形的JSON内容时,可能未正确处理错误,反而进入无限循环,最终导致函数触发最大执行时间限制而挂死。
3. 数据变更是最终诱因
服务器未做代码/配置变更,但数据库数据可能发生了变化:
- 新增或修改了
module='core'且encoded=1的记录,其data字段的JSON格式存在语法错误(如引号不闭合、缺少括号、非法转义字符等)。 - 此前的数据集无此类异常数据,因此函数可正常运行;当异常数据出现后,直接触发了JSON解码的死循环问题。
验证建议
- 检查
settingsfields表中module='core'且encoded=1的所有记录,确认data字段的JSON格式是否合法。 - 临时注释
$JSON->decode相关代码,测试函数是否仍会挂死,以此确认解码逻辑是否为问题根源。
内容的提问来源于stack exchange,提问作者Guy
相关产品推荐
相关产品推荐

