cURL 使用 utf-8 BOM 获得响应

Res*_*lov 2 php curl byte-order-mark utf-8

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

有一些实验:


$data = $data = curl_exec($ch);
echo $data;
Run Code Online (Sandbox Code Playgroud)

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

$data = $data = curl_exec($ch);
echo mb_detect_encoding($data);
Run Code Online (Sandbox Code Playgroud)

结果 - 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');
Run Code Online (Sandbox Code Playgroud)

结果 - {"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);
}
Run Code Online (Sandbox Code Playgroud)

但是,如果还有另一个 BOM 呢?所以问题是:如何检测 cURL 响应的正确编码?或者如何检测 BOM 已到?或者也许如何使用 BOM 转换响应?

LSe*_*rni 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);
Run Code Online (Sandbox Code Playgroud)

第三方 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)
}
Run Code Online (Sandbox Code Playgroud)

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