json_decode对于一个字符串变量返回NULL

7

我在使用json_decode时遇到了一个非常奇怪的问题,以下是相关代码:

$url="http://localhost:8983/solr/db/select?wt=json&rows=1&q=94305";
$string=file_get_contents($url);
echo $string; echo '<br><br>';
$json=json_decode($string);
var_dump($json);

我得到了以下结果:
{"responseHeader":{"status":0,"QTime":0,"params":{"q":"94305","wt":"json","rows":"1"}},"response":{"numFound":165,"start":0,"docs":[{"price":"","tags":"ATMs","phone_n":"","location":"37.42409897,-122.1709976 ","store":"Discover ATM","store_id":"478602","state":"CA","latitude":"37.42409897","address":"459 LAGUNITA","zipcode_n":"94305","longitude":"-122.1709976\r","url":"Discover_ATM_459_LAGUNITA_Stanford_CA_94305","city":"Stanford","category":"ATMs","text":["","CA","459 LAGUNITA","94305","Stanford"],"spell":["Discover ATM"]}]}}

NULL 

看起来我无法解析这个字符串。不过,当我像这样做(直接复制上面字符串的输出并将其放入$string中)时:

$string='{"responseHeader":{"status":0,"QTime":0,"params":{"q":"94305","wt":"json","rows":"1"}},"response":{"numFound":165,"start":0,"docs":[{"price":"","tags":"ATMs","phone_n":"","location":"37.42409897,-122.1709976 ","store":"Discover ATM","store_id":"478602","state":"CA","latitude":"37.42409897","address":"459 LAGUNITA","zipcode_n":"94305","longitude":"-122.1709976\r","url":"Discover_ATM_459_LAGUNITA_Stanford_CA_94305","city":"Stanford","category":"ATMs","text":["","CA","459 LAGUNITA","94305","Stanford"],"spell":["Discover ATM"]}]}}';
$json=json_decode($string);
var_dump($json);

json_decode 能正常工作。为什么在这里却在第一部分得到 NULL 值?


3
检查字符串中的BOM(字节顺序标记)。 - Navneet Singh
也许响应末尾包含一个换行符? - John Dvorak
尝试使用print_r($string)代替echo $string。 - John Dvorak
首先,使用我在答案中发布的代码检查是否发生了解析JSON数据的错误。数据确切来自哪里? - Navneet Singh
我在发布之前已经检查了BOM。print_r与echo打印的内容完全相同。 - user570494
不要只是回显,要发布 echo bin2hex($string) 的输出。 - Salman A
2个回答

4

你的代码看起来不错,让我们更进一步,调查一下$output的真实内容。选择一个能处理ASCII范围的表示形式会有所帮助,因为这些范围是肉眼无法看见的。

echo bin2hex($output);

这会生成一个庞大的字符串,但你主要关心字符串的开头和结尾。

如果这看起来可行,可以创建一个中间表示:

echo preg_replace('@[\x00-\x1f\x7f-\xff]@e', '" (0x" . dechex(ord("\\0")) . ") "', $output);

它可以将ASCII范围内的任何字符替换为十六进制表示,使其更易于识别 :)

更新

根据以上内容的调查,你的字符串似乎在中间包含一个回车符 - \r

"CA","latitude":"37.42409897","
                            ^

如果无法通过其他方式解决,您可以使用preg_replace()删除它们。

preg_replace("/\r(?!\n)/", '', $output);

这将删除任何没有后面跟随 \n\r


中间有一些差异:370d222c与3720222c。 - user570494
1
@user570494 不确定为什么你在中间有一个回车符,但这可能会导致问题...我已经更新了我的答案,提供了一个hackish的解决方案...最好知道solr为什么首先给出那个结果。 - Ja͢ck
preg_replace("/\r(?!\n)/", '', $output); 可以正常工作!非常感谢! - user570494
@user570494 真是太奇怪了! :) 我会更加深入地研究为什么solr会给你这些结果的;-) - Ja͢ck

3

该字符串中可能存在一些NULL字节。

可以使用以下方法将其移除:

$string = trim($string, "\x0");
$json=json_decode($string);
var_dump($json);

在此页面上将内容类型更改为json:http://localhost:8983/solr/db/select?wt=json&rows=1&q=94305

header('Content-type:application/json; charset=utf-8');

移除BOM(字节顺序标记)

if (substr($string, 0,3) == pack("CCC",0xef,0xbb,0xbf)) { 
$string = substr($string, 3); 
}

检查解析 JSON 数据时是否发生错误

   $json_errors = array(
         JSON_ERROR_NONE => 'No error has occurred',
         JSON_ERROR_DEPTH => 'The maximum stack depth has been exceeded',
         JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded',
         JSON_ERROR_SYNTAX => 'Syntax error',
        );
        echo 'Last error : ',

 $json_errors[json_last_error()], PHP_EOL, PHP_EOL;

尝试了 $string = trim($string, "\x0");,但没有成功。 - user570494
没有成功删除BOM。(其实根本就没有BOM存在)。 - user570494
然后,您可以通过将接收到的JSON字符串的bin2hex与实际JSON字符串的bin2hex进行匹配来执行最后的操作 ,请检查此函数 - Navneet Singh
我不确定问题出在哪里。尝试使用CURL而不是file_get_content(),并在打印之前使用addslashes将其转换为JSON字符串,然后使用stripslasges进行解码。 - Navneet Singh
bin2hex为我找到了问题。非常感谢您的帮助!我很感激。 - user570494
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接