2

在我的脚本中,我使用 cURL 发送数据,并启用了 CURLOPT_RETURNTRANSFER。响应是 json 编码的数据。当我尝试 json_decode 时,它​​返回 null。然后我发现响应在字符串()的开头包含 utf-8 BOM 符号。

有一些实验:


$data = $data = curl_exec($ch);
echo $data;

结果是 {"field_1":"text_1","field_2":"text_2","field_3":"text_3"}

$data = $data = curl_exec($ch);
echo mb_detect_encoding($data);

结果 - UTF-8

$data = $data = curl_exec($ch);
echo mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
// identical to echo mb_convert_encoding($data, 'UTF-8', 'UTF-8');

结果 - {"field_1":"text_1","field_2":"text_2","field_3":"text_3"}


有帮助的一件事是删除前 3 个符号:

if (substr($data, 0, 3) == pack('CCC', 239, 187, 191)) {
    $data = substr($data, 3);
}

但是,如果会有另一个 BOM 怎么办?所以问题是:如何检测 cURL 响应的正确编码?或者如何检测到什么 BOM?或者也许如何用 BOM 转换响应?

4

3 回答 3

5

恐怕您已经自己找到了答案——这是个坏消息,因为我知道没有更好的答案。

BOM 不应该在那里,发件人有责任不将其发送。

但我可以向你保证,BOM 要么存在要么不存在,如果存在,那就是你知道的那三个字节。

您可以稍微快一点并处理另一个 N BOM,只需稍作改动:

$__BOM = pack('CCC', 239, 187, 191);
// Careful about the three ='s -- they're all needed.
while(0 === strpos($data, $__BOM))
    $data = substr($data, 3);

第三方 BOM 检测器不会有任何不同。这样,即使 cURL 稍后开始剥离不需要的 BOM,您也会被覆盖。

可能的原因

一些 JSON 优化器和过滤器可能会决定输出需要 BOM。此外,也许更简单的是,编写生成 JSON 的脚本的人无意中在开始 PHP 标记之前包含了一个 BOM。Apache,不关心 BOM 是什么,看到开始标记之前有数据,因此将其发送并隐藏在 PHP 流本身中。这有时也会导致“无法添加标题:输出已开始”错误。

内容检测

您可以验证 JSON 是有效的 UTF-8、BOM 还是非 BOM,但需要mb_string支持并且您必须使用严格模式来获取一些边缘情况:

if (false === mb_detect_encoding($data, 'UTF-8', true)) {
    // JSON contains invalid sequences (erroneously NOT JSON encoded)
}

我建议不要尝试纠正可能的编码错误;您可能会破坏自己的代码,并且还必须维护其他人的工作。

于 2012-09-20T09:49:00.610 回答
0

此页面详细介绍了类似的问题:Wordpress 自动生成的 PHP 页面中的 BOM

基本上,当 JSON 生成器是用 PHP 编写的并且编辑器以某种方式在开始<?php标记之前潜入 BOM 时,就会发生这种情况。由于您的客户端语言是 PHP,我假设这是相关的。

您可以使用substr比较将其去掉——BOM 只出现在文档的开头。但是,如果您可以控制 JSON 源,则应改为从源文档中删除 BOM。

于 2012-09-20T09:48:21.373 回答
0

“{”之前的字符永远不会超过 3 个。这 3 个字符是 UTF-8 中的一个字符。所以如果你只是做 $data = substr($data, 3); 你会好起来的。

在这里查看更多信息:json_decode 在 webservice 调用后返回 NULL

于 2012-09-20T09:50:37.317 回答