
本文介绍如何在 PHP 中安全、可靠地解析格式不规范的 JSON 文本——特别是多个 JSON 对象紧邻拼接(无换行、无逗号、键名缺失引号)的场景,并提供可直接运行的修复与解析方案。
本文介绍如何在 PHP 中安全、可靠地解析格式不规范的 JSON 文本——特别是多个 JSON 对象紧邻拼接(无换行、无逗号、键名缺失引号)的场景,并提供可直接运行的修复与解析方案。
在实际开发中,我们常会遇到“伪 JSON”文件:表面类似 JSON,但因日志生成工具缺陷、旧系统导出逻辑不严谨等原因,导致结构非法——例如多个 JSON 对象直接拼接,且键名未加双引号(如 {timestamp":"...),对象间无分隔符(如 }{ 紧连)。这类数据无法直接通过 json_decode() 解析,必须先进行预处理修复。
以如下典型坏 JSON 为例:
{timestamp":"2022-03-25 00:25:41.476+00","order_id":"1659616"}{timestamp":"2022-03-25 00:18:51.892+00","order_id":"1560808"}{timestamp":"2022-03-25 00:23:52.267+00","order_id":"1727305"}其核心问题有三:
立即学习“PHP免费学习笔记(深入)”;
- 键名 timestamp 和 order_id 缺失左引号(应为 "timestamp");
- 多个对象之间缺少分隔符(需将 }{ 替换为 }, {);
- 整体非合法 JSON 数组(需包裹成 [...] 才能被 json_decode() 识别)。
✅ 推荐处理流程如下(完整可运行代码):
<?php
// 步骤 1:读取整个文件内容(注意:file() 按行读取不适用,改用 file_get_contents)
$content = file_get_contents('abovefile.txt');
// 步骤 2:逐项修复语法错误
$fixed = $content;
$fixed = str_replace('{timestamp":', '{"timestamp":', $fixed); // 修复 timestamp 键
$fixed = str_replace('{order_id":', '{"order_id":', $fixed); // 修复 order_id 键
$fixed = str_replace('}{', '},{', $fixed); // 插入逗号分隔
$fixed = '[' . $fixed . ']'; // 封装为 JSON 数组
// 步骤 3:解析为 PHP 数组
$data = json_decode($fixed, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('JSON 解析失败:' . json_last_error_msg());
}
// 步骤 4:遍历提取所需字段
foreach ($data as $item) {
echo "时间戳: {$item['timestamp']}, 订单ID: {$item['order_id']}\n";
}
?>⚠️ 注意事项:
- 避免使用 file():原问题中 foreach(file(...)) 基于换行分割,而本例无换行符,会导致整行被当作单个“行”,无法拆分对象。务必改用 file_get_contents() 一次性读取全文。
- 修复需精准匹配:str_replace 是轻量解法,但仅适用于键名固定、格式高度一致的场景;若存在其他非法键(如 user_id、status),需扩展替换规则或改用正则(如 preg_replace('/{([^"]+)/', '{"$1', $content))。
- 健壮性增强建议:生产环境应添加 json_last_error() 校验,并对空值、编码异常(如 BOM)做预处理(可用 trim($content, "\xEF\xBB\xBF") 清除 UTF-8 BOM)。
- 内存考量:对于超大文件(GB 级),上述全量加载不适用,需采用流式解析(如逐字符扫描 } 边界 + 分段修复),但复杂度显著上升,一般建议先评估数据规模再选型。
总结:面对非标准 JSON,核心思路是「先修复,再解析」。通过字符串预处理补全语法要素(引号、分隔符、容器结构),即可复用 PHP 原生 json_decode() 的高性能与可靠性,无需引入第三方解析器。关键在于理解损坏模式,并设计幂等、可验证的修复步骤。











