webservice调用后,json_decode返回NULL

66

使用json_encodejson_decode时出现了奇怪的行为,我找不到解决办法:

我的php应用程序调用了一个php web服务。该web服务返回的json看起来像这样:

var_dump($foo):
string(62) "{"action":"set","user":"123123123123","status":"OK"}"

现在我想要在我的应用程序中解码JSON:

$data = json_decode($foo, true)

但它返回NULL

var_dump($data):
NULL
我使用php5。 来自webservice的响应Content-Type是"text/html; charset=utf-8"(也尝试使用"application/json; charset=utf-8")。 可能的原因是什么?
24个回答

80

我曾遇到过类似的问题,而问题出在服务器上的PHP魔术引号...这是我的解决方案:

if(get_magic_quotes_gpc()){
  $param = stripslashes($_POST['param']);
}else{
  $param = $_POST['param'];
}
$param = json_decode($param,true);

4
非常感谢巴勃罗的答复!!你帮我省了很多时间!! - Alejandra
3
伙计,没想到魔术引号会引起这么大的问题,我差点就要对着显示器喊了。谢谢。 - wiggles
1
@Pablo为什么在get_magic_quotes_gpc()返回true时调用stripslashes()?这对我有用,但在get_magic_quotes_gpc之前加上(!)后,以便如果get_magic_quotes_gpc不返回true,我就调用stripslashes()。 - Junaid Qadir Shekhanzai
谢谢,你是怎么发现这个问题的?!我调试了一切,看起来都没问题,哈哈 +1 - Treemonkey
1
即使魔术引号关闭了,我仍然需要使用“stripslashes”。有何解释? - Arman P.
显示剩余5条评论

76

编辑: 对提供的字符串进行了快速检查。花括号前面的小“字符”是UTF-8字节顺序标记0xEF 0xBB 0xBF,我不知道为什么这个字节序列在这里显示为

实际上,你从中获取数据的系统将其编码为带有BOM(字节顺序标记)的UTF-8。在将其放入json_decode()之前,应该从字符串中删除前三个字节(使用substr($string, 3)即可)。

string(62) "{"action":"set","user":"123123123123","status":"OK"}"
            ^
            |
            This is the UTF-8 BOM

正如Kuroki Kaze发现的那样,这个字符肯定是导致json_decode失败的原因。以其给定的形式,该字符串并不是一个正确格式化的JSON结构(参见RFC 4627)。


1
我不这么认为。这是一个花括号。我认为每个JSON结构都应该以花括号开头。 - schouk
8
不是花括号——花括号前面有一个字符。 - Stefan Gehrig
6
我认为Stack Overflow的格式设置试图让这个问题难以回答。 :-p - Andrew Ensley
2
好的,Notepad++ 让我看到了这个字符。我的 FF3 没有显示它...非常感谢! :) - schouk
2
@StefanGehrig 这是一个旧的问题/答案,但我在这里找到了一个更好的解决方法来删除UTF-8 BOM:https://dev59.com/questions/y2kv5IYBdhLWcg3w4kl2#15423899。由于它使用`preg_replace`而不是`(mb_)substr`,因此它将处理带有和不带有BOM的字符串。如果您可以更新您的答案,那就太好了。;) - Gustavo Straube
显示剩余5条评论

36

在调试时打印最后的 JSON 错误。使用以下代码并结合 json_decode() 函数的第三个参数,以增加错误显示层数。

json_decode($so, true, 9);
$json_errors = array(
    JSON_ERROR_NONE => '没有发生错误',
    JSON_ERROR_DEPTH => '超过了最大堆栈深度',
    JSON_ERROR_CTRL_CHAR => '控制字符错误,可能编码不正确',
    JSON_ERROR_SYNTAX => '语法错误',
);
echo '最后的错误:', $json_errors[json_last_error()], PHP_EOL, PHP_EOL;

同时,可使用 json.stringify() 函数来验证您的 JSON 语法是否正确。


正如我们的一位用户刚遇到的问题:PHP.net是错误的,这是在5.3中引入的,所以可以确认@MdOliya的说法。 - kaiser

33

以上的解决方案都不适用于我,但是使用html_entity_decode($json_string)就解决了问题。


这在存储在mysql utf8表中的json字符串上运行良好。我怀疑当存储到mysql时发生了一些事情。 - CodeChap
2
谢谢!我花了数小时尝试不同的解决方案,而这是唯一有效的方法。 - wwv
1
这对我也起作用了。它需要用于解码存储在WordPress中的JSON。 - Pepper

20

试一试这个

$foo = utf8_encode($foo);
$data = json_decode($foo, true);

嗨,Olafur,utf8_encode会将一些奇怪的字符写入字符串开头。utf8_decode会在字符串开头写入一个问号。这只是一种解决方法,但它有效。我相信有更好的方法:$foo = utf8_decode($result->data); json_decode(str_replace("?", "", $foo), true); - schouk
2
这对我也起作用了,所有其他提到的答案都没有效果。 - Timo002

10

确保如果您通过POST / GET发送数据,服务器没有转义引号

$my_array = json_decode(str_replace ('\"','"', $json_string), true);

1
哥们儿...你让我高兴了一整天。这个问题简直快要把我搞疯了! - Ryan Burney

5

我在一个实际的网站上也遇到了类似的问题,在我的本地测试网站中它正常工作。为了解决这个问题,我只需添加以下代码:

json_decode(stripslashes($_GET['arr']));


这对我有用,不是UTF-8编码中的BOM,而是添加了一些斜杠。 - DJG22

5
"{"action":"set","user":"123123123123","status":"OK"}"

这个在开头的小撇号是什么?双引号之后的第一个符号。


4
我找不到一个小撇号。双引号后的第一个符号是一个大括号。 - schouk

5
我只是将这个放置了。
$result = mb_convert_encoding($result,'UTF-8','UTF-8'); 
    $result = json_decode($result);

现在它正在运行


3
昨天我花了两个小时来检查和修复那个错误,最后我发现我想要解码的JSON字符串中有'\'斜杠。所以逻辑上应该使用stripslashes函数或类似于不同PL的函数。

当然,最好的方法仍然是打印出这个变量并查看它在json_decode之后变成了什么,如果它为空,你还可以使用json_last_error()函数来确定错误,它将返回整数,但这里描述了这些int:

0 = JSON_ERROR_NONE

1 = JSON_ERROR_DEPTH

2 = JSON_ERROR_STATE_MISMATCH

3 = JSON_ERROR_CTRL_CHAR

4 = JSON_ERROR_SYNTAX

5 = JSON_ERROR_UTF8

在我的情况下,json_last_error()的输出是数字4,因此它是JSON_ERROR_SYNTAX。然后我去看了一下我想要转换的字符串本身,在最后一行中有:

'\'title\' error ...'

之后只需要进行简单的修复即可。

$json = json_decode(stripslashes($response));
if (json_last_error() == 0) { // you've got an object in $json}

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