迁移至新服务器与PHP7.4时json_decode及unserialize失败排查
问题排查与解决方案
核心原因剖析
问题根源在于PHP 7.4对JSON/序列化数据的校验规则更严格,以及新旧服务器的ODBC驱动字符集处理逻辑差异:
- PHP 5.5的
json_decode和unserialize对ASCII控制字符(0-31、127号)容忍度极高,即使数据包含这类字符也能尝试解码;但PHP 7.4开始遵循严格的JSON规范,这类控制字符会直接触发Unexpected control character found错误。 - 数据库采用
SQL_Latin1_General_CP1_CI_AS排序规则(对应Windows-1252编码),SERVER1的ODBC驱动可能在数据读取时自动过滤了控制字符,而SERVER2的驱动原样返回了这些字符,导致PHP 7.4解码失败。
分步排查与修复
1. 核对ODBC字符集配置
- 分别查看两台服务器的ODBC数据源管理器(ODBC Data Source Administrator),确认**字符集(Character Set)**配置是否一致,建议统一设置为
SQL_Latin1_General_CP1_CI_AS或Windows-1252。 - 检查PHP数据库连接代码,确保连接字符串中指定了匹配的字符集参数,例如:
$dsn = "Driver={SQL Server};Server=SERVER2;Database=your_db;CharacterSet=SQL_Latin1_General_CP1_CI_AS"; $conn = odbc_connect($dsn, $user, $pass);
2. 对比原始数据的十六进制输出
在两台服务器上运行以下代码,读取数据库数据并输出十六进制,验证控制字符的存在差异:
$rawData = odbc_result($conn, "your_text_column"); // 输出十六进制字符串,查看是否包含0x00-0x1F或0x7F字符 echo bin2hex($rawData);
- 若SERVER1的输出无控制字符,说明其驱动自动过滤;若SERVER2存在这类字符,需调整驱动配置或手动处理。
3. 临时兼容修复
如果无法立即调整ODBC配置,可在读取数据后清除控制字符,兼容新旧服务器:
// 仅清除ASCII控制字符,保留正常字符 $cleanData = preg_replace('/[\x00-\x1F\x7F]/u', '', $rawData); // 执行解码 $jsonData = json_decode($cleanData); $serializedData = unserialize($cleanData);
/u修饰符确保Unicode字符不会被误过滤,仅针对ASCII控制字符生效。
4. 长期规范方案
- 将数据库文本字段的排序规则迁移至
UTF8MB4_GENERAL_CI,彻底避免字符集转换带来的问题; - 在数据写入数据库前提前清除控制字符,从源头杜绝无效数据:
$processedData = preg_replace('/[\x00-\x1F\x7F]/u', '', $originalData); // 执行写入操作 odbc_exec($conn, "INSERT INTO your_table (your_text_column) VALUES ('$processedData')");
额外验证项
- 检查SERVER2的PHP
mbstring扩展配置,确认mbstring.internal_encoding与数据库字符集匹配; - 对比两台服务器的ODBC驱动版本,不同版本的驱动对字符集的处理逻辑可能存在差异。
内容的提问来源于stack exchange,提问作者Dutchie432
相关产品推荐
相关产品推荐

