合法JSON需用json_decode()配合json_last_error()判断:先trim去空和BOM,再解析并检查错误码是否为JSON_ERROR_NONE,仅判null会误杀合法null值。

用 json_decode() 判断是否为合法 JSON 字符串
PHP 没有原生的“JSON 文件类型检测”函数,最可靠的方式是读取文件内容后尝试解析:如果 json_decode() 返回非 null 值(且没触发警告),说明内容是合法 JSON。注意必须传入第二个参数 true 或 false 显式控制返回数组或对象,否则空 JSON 对象 {} 解码后是空对象,但 json_last_error() 才是判断依据。
常见错误现象:json_decode(file_get_contents($file)) === null 不能直接断定非法 —— 因为 JSON 中的 null、空字符串、false 都会返回 null,必须配合 json_last_error() === JSON_ERROR_NONE 判断。
- 先用
file_get_contents($file)读取全部内容(确保文件不大,避免内存溢出) - 调用
json_decode($content, true),然后立即检查json_last_error() - 若
json_last_error() !== JSON_ERROR_NONE,说明不是合法 JSON 格式 - 额外建议:用
trim($content) === ''排除空文件干扰
检查文件扩展名和 MIME 类型不靠谱
仅靠 .json 后缀或 finfo_file() 返回 application/json 无法确认内容真实合法性。很多场景下用户可任意改后缀,或服务端未正确设置 MIME;finfo 实际依赖文件头部字节特征,而 JSON 是纯文本,无固定 magic bytes,容易误判为 text/plain。
使用场景:上传文件校验时,不能跳过内容解析只信后缀。曾遇到用户上传名为 data.json 的 CSV 内容,后缀+MIME 全对,但后续解析直接报错。
立即学习“PHP免费学习笔记(深入)”;
-
pathinfo($file, PATHINFO_EXTENSION) === 'json'只能作为快速过滤,不可替代内容验证 -
finfo_open(FILEINFO_MIME_TYPE)对 JSON 文件返回text/plain很常见,不可依赖 - 若需预检,可加一行
if (substr(trim($content), 0, 1) !== '{' && substr(trim($content), 0, 1) !== '[') { return false; }快速排除明显非 JSON
大文件或流式 JSON 的处理陷阱
当文件超过几 MB,file_get_contents() 容易触发内存限制或超时。此时不能硬解全量,但 PHP 也没有内置流式 JSON 解析器(如 Python 的 ijson)。可行折中方案是截取开头一段做轻量验证。
性能影响:完整解析 10MB JSON 在默认配置下可能失败,memory_limit 和 max_execution_time 都需调整;但生产环境不应盲目调高,应优先拒绝非法输入。
- 用
fopen()+fgets()读前 1KB,检查是否以{或[开头,并包含成对引号、冒号等基本结构 - 仍需最终用
json_decode()全量解析 —— 轻量检查只是防崩,不是替代 - 注意 BOM:UTF-8 BOM(
\xEF\xBB\xBF)会导致json_decode()直接失败,建议先用ltrim($content, "\xEF\xBB\xBF")
为什么不用 is_json() 这类封装函数?
社区常见封装如 function is_json($string) { return is_string($string) && is_null(json_decode($string)) && json_last_error() === JSON_ERROR_NONE; } 是错的 —— is_null(json_decode('null')) 为真,但它是合法 JSON。正确逻辑必须分离“解码结果是否为 null”和“解析过程是否出错”。
容易被忽略的地方:JSON 中允许的空白字符(U+2028、U+2029 行分隔符)在旧版 PHP(json_last_error() 返回 JSON_ERROR_SYNTAX,即使内容符合标准。如需兼容,得提前替换或升级 PHP。
- 正确封装核心逻辑:
$decoded = json_decode($content, true); return $decoded !== null || (json_last_error() === JSON_ERROR_NONE && $content === 'null'); - 更稳妥写法:统一用
json_last_error() === JSON_ERROR_NONE作为唯一判定依据,忽略json_decode()返回值是否为null - 别忘了
json_decode()默认返回对象,若业务需要数组,务必传true,否则isset($obj->key)会和数组行为不一致











