66

There is a strange behaviour with json_encode and json_decode and I can't find a solution:

My php application calls a php web service. The webservice returns json that looks like this:

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

now I like to decode the json in my application:

$data = json_decode($foo, true)

but it returns NULL:

var_dump($data):
NULL

I use php5. The Content-Type of the response from the webservice: "text/html; charset=utf-8" (also tried to use "application/json; charset=utf-8")

What could be the reason?

SomeKittens
  • 38,868
  • 19
  • 114
  • 143
schouk
  • 763
  • 1
  • 5
  • 7

24 Answers24

80

Well, i had a similar issue and the problems was the PHP magic quotes in the server... here is my solution:

if(get_magic_quotes_gpc()){
  $param = stripslashes($_POST['param']);
}else{
  $param = $_POST['param'];
}
$param = json_decode($param,true);
Pablo
  • 5,897
  • 7
  • 34
  • 51
76

EDIT: Just did some quick inspection of the string provided by the OP. The small "character" in front of the curly brace is a UTF-8 B(yte) O(rder) M(ark) 0xEF 0xBB 0xBF. I don't know why this byte sequence is displayed as  here.

Essentially the system you aquire the data from sends it encoded in UTF-8 with a BOM preceding the data. You should remove the first three bytes from the string before you throw it into json_decode() (a substr($string, 3) will do).

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

As Kuroki Kaze discovered, this character surely is the reason why json_decode fails. The string in its given form is not correctly a JSON formated structure (see RFC 4627)

Community
  • 1
  • 1
Stefan Gehrig
  • 82,642
  • 24
  • 155
  • 189
  • 1
    I don't think so. This is a curly bracket. I think every JSON structure should begin with a curly bracket. – schouk Mar 27 '09 at 12:47
  • 8
    No not the curly brace - there is a character just before the curly brace. – Stefan Gehrig Mar 27 '09 at 13:48
  • 6
    I think SO's formatting is trying to make this a hard question to answer. :-p – Andrew Ensley Mar 27 '09 at 15:16
  • 2
    -> ok, Notepad++ lets me see this character. My FF3 doesn't display it... Many Thanks! :) – schouk Mar 27 '09 at 16:33
  • I found a way to fix this in my HTML. If you are sending a POST method using a form, use accept-charset like this: `
    `. No need to truncate input in PHP.
    – styfle Aug 11 '11 at 22:57
  • @schouk: you made my day ! The best job ever ! – Thomas Decaux Jun 06 '12 at 08:06
  • 2
    @StefanGehrig This is an old question/answer, but I found a better solution to remove the UTF-8 BOM here: http://stackoverflow.com/a/15423899/1128918. Since it uses `preg_replace` instead of `(mb_)substr` it'll handle strings with and without the BOM. It would be nice if you can update your answer. ;) – Gustavo Straube Apr 10 '15 at 15:52
  • I get NULL response by sending simple key name:test name. Then I change body to {"name":"test name"} and this gone well. – dip Jan 20 '16 at 11:56
  • JSON requires you to use double quotes `"` on key names (and literal strings). The convenient `{a: 1}` form is NOT JSON but a feature of the JavaScript parser. – Stefan Gehrig Jan 20 '16 at 12:03
  • For me, it wasn't anything special, just an extra comma in the end of an object's element. Take away : Anything which makes your JSON inconsistent, is going to throw an error. Bonus tip: don't trust jsonviewer.stack.hu – Aman Alam Oct 24 '16 at 11:07
36

Print the last json error when debugging.

json_decode( $so, true, 9 );
$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;
Also use the json.stringify() function to double check your JSON syntax.

R3tep
  • 12,512
  • 10
  • 48
  • 75
LarryBattle
  • 361
  • 3
  • 2
  • As one of our users just ran into this: PHP.net is **wrong** and this was introduced with **5.3**, so can confirm @MdOliya – kaiser Mar 03 '13 at 09:46
33

None of the solutions above worked for me, but html_entity_decode($json_string) did the trick

djb
  • 5,591
  • 5
  • 41
  • 47
  • This worked on a json string stored in a mysql utf8 table. I suspect something happens when stored to mysql. – CodeChap Nov 16 '11 at 15:39
  • 2
    Thank you!! I spent hours trying different solutions and this is the only thing that worked. – wwv Apr 18 '12 at 18:25
  • 1
    This is what worked for me too. Its needed for decoding JSON stored in Wordpress. – Pepper Nov 23 '14 at 00:03
20

Try this

$foo = utf8_encode($foo);
$data = json_decode($foo, true);
Ólafur Waage
  • 68,817
  • 22
  • 142
  • 198
  • Hi Olafur, utf8_encode writes some strange characters to the beginning of the string. utf8_decode writes a ? to the beginning of the string. This is just a workaround, but it works. I'm sure there is a better way: $foo = utf8_decode($result->data); json_decode(str_replace("?", "", $foo), true); – schouk Mar 27 '09 at 10:51
  • 2
    This worked for me to, all other mentioned answers didn't work. – Timo002 Nov 11 '13 at 10:45
10

make sure that if you sent the data by POST / GET, the server has not escape the quotes

$my_array = json_decode(str_replace ('\"','"', $json_string), true);
ikary
  • 1,093
  • 1
  • 8
  • 5
5

I just put this

$result = mb_convert_encoding($result,'UTF-8','UTF-8'); 
    $result = json_decode($result);

and it's working

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

This little apostrophe in the beginning - what is it? First symbol after the doublequote.

Kuroki Kaze
  • 8,161
  • 4
  • 36
  • 48
5

I had the similar problem in a live site. In my local site it was working fine. For fixing the same I Just have added the below code

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

amesh
  • 1,311
  • 3
  • 21
  • 51
mona
  • 51
  • 1
  • 1
3

Yesterday I spent 2 hours on checking and fixing that error finally I found that in JSON string that I wanted to decode were '\' slashes. So the logical thing to do is to use stripslashes function or something similiar to different PL.

Of course the best way is sill to print this var out and see what it becomes after json_decode, if it is null you can also use json_last_error() function to determine the error it will return integer but here are those int described:

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

In my case I got output of json_last_error() as number 4 so it is JSON_ERROR_SYNTAX. Then I went and take a look into the string it self which I wanted to convert and it had in last line:

'\'title\' error ...'

After that is really just an easy fix.

$json = json_decode(stripslashes($response));
if (json_last_error() == 0) { // you've got an object in $json}
Matija
  • 17,604
  • 2
  • 48
  • 43
1

Non of these solutions worked for me. What DID eventually work was checking the string encoding by saving it to a local file and opening with Notepad++. I found out it was 'UTF-16', so I was able to convert it this way:

$str = mb_convert_encoding($str,'UTF-8','UTF-16');
Roey B
  • 53
  • 6
1

Maybe you use thing as $ ${: these chars should be quoted.

eebbesen
  • 5,070
  • 8
  • 48
  • 70
baquiax
  • 148
  • 13
1

I had such problem with storage json-string in MySQL. Don't really know why, but using htmlspecialchars_decode berofe json_decode resolved problem.

Victoria
  • 11
  • 2
0

I was having this problem, when I was calling a soap method to obtain my data, and then return a json string, when I tried to do json_decode I just keep getting null.

Since I was using nusoap to do the soap call I tried to just return json string and now I could do a json_decode, since I really neaded to get my data with a SOAP call, what I did was add ob_start() before include nusoap, id did my call genereate json string, and then before returning my json string I did ob_end_clean(), and GOT MY PROBLEM FIXED :)

EXAMPLE

//HRT - SIGNED
//20130116
//verifica se um num assoc deco é valido
ob_start();
require('/nusoap.php');
$aResponse['SimpleIsMemberResult']['IsMember'] = FALSE;
if(!empty($iNumAssociadoTmp))
{
    try
    {
        $client = new soapclientNusoap(PartnerService.svc?wsdl',
         array( 
            // OPTS 
            'trace' => 0,
            'exceptions' => false,
            'cache_wsdl' => WSDL_CACHE_NONE
         )
        );
    //MENSAGEM A ENVIAR
    $sMensagem1 = '
        <SimpleIsMember>
            <request>
                <CheckDigit>'.$iCheckDigitAssociado.'</CheckDigit>
                <Country>Portugal</Country>
                <MemberNumber">'.$iNumAssociadoDeco.'</MemberNumber>
            </request>
        </SimpleIsMember>';
    $aResponse = $client->call('SimpleIsMember',$sMensagem1);
    $aData = array('dados'=>$aResponse->xpto, 'success'=>$aResponse->example);
    }
}
ob_end_clean();
return json_encode($aData);
0

I don't know Why? But this work:

$out = curl_exec($curl);
    $out = utf8_encode($out);
    $out = str_replace("?", "", $out);
if (substr($out,1,1)!='{'){
    $out = substr($out,3);
}
    $arResult["questions"] = json_decode($out,true);

without utf8_encode() - Don't work

Orange_shadow
  • 199
  • 2
  • 9
0

Check the encoding of your file. I was using netbeans and had to use iso windows 1252 encoding for an old project and netbeans was using this encoding since then for every new file. json_decode will then return NULL. Saving the file again with UTF-8 encoding solved the problem for me.

Quxflux
  • 3,133
  • 2
  • 26
  • 46
0

In Notepad++, select Encoding (from the top menu) and then ensure that "Encode in UTF-8" is selected.

This will display any characters that shouldn't be in your json that would cause json_decode to fail.

philipbrown
  • 554
  • 3
  • 8
0

Try using json_encode on the string prior to using json_decode... idk if will work for you but it did for me... I'm using laravel 4 ajaxing through a route param.

$username = "{username: john}";
public function getAjaxSearchName($username)
{
    $username = json_encode($username);
    die(var_dump(json_decode($username, true)));
}
John Manning
  • 39
  • 11
0

You should try out json_last_error_msg(). It will give you the error message and tell you what is wrong. It was introduced in PHP 5.5.

$foo = "{"action":"set","user":"123123123123","status":"OK"}";
$data = json_decode($foo, true);
if($data == null) {
    throw new Exception('Decoding JSON failed with the following message: '
                             . json_last_error_msg());
}

// ... JSON decode was good => Let's use the data
HNygard
  • 4,526
  • 6
  • 32
  • 40
0

Before applying PHP related solutions, validate your JSON format. That may be the problem. Try below online JSON format validator. If your JSON format is invalid, correct it first, because PHP doesn't decode invalid JSON strings.

https://jsonformatter.org/

namal
  • 1,164
  • 1
  • 10
  • 15
0

Laravel specific answer: I got the same issue in Laravel. And this did the trick for me

$result = json_decode($result->getContent(), true);
Inderpreet Singh
  • 321
  • 1
  • 10
  • I do not see this as a legitimate resolution for the asked question. It seems, at best, to be the correct answer to a different question. Posts like these make Stack Overflow pages unnecessarily long/bloated. – mickmackusa Jun 18 '21 at 06:03
  • 1
    @mickmackusa I did not add this to gain points. But to help the fellow PHP developers. Since, Laravel is a famous framework of PHP and I am sure many others like me would end up landing to this page facing the same issue like me. I don't agree you saying this illegitimate. I specifically added in bold that this is Laravel specific answer. This is just to help at the end of the day. I can delete it if it gives you satisfaction. Cheers. – Inderpreet Singh Jun 18 '21 at 11:40
  • You can do whatever you like. I have already voted to delete this answer for the reason earlier commented. – mickmackusa Jun 18 '21 at 11:46
0

In my case, when I was printing to the screen, json was fine and I copied and decode with json_deocode() function. It was working fine. But, when I was trying to put jsonString directly in the function, it was returning null because quotes were coming like these &quot;. So I used htmlspecialchars_decode() function and now it is working fine. I am new here, so if I am making any mistakes in writing answer then sorry for that. I hope it'll help somebody.

ouflak
  • 2,458
  • 10
  • 44
  • 49
Heymi
  • 1
  • 1
0

Sometimes the problem is generated when the content is compressed, so adding the Accept-Encoding: identity header can solve the problem without having to wrangle with the response.

   $opts = array(
        'http' =>
            array(                    
                'header'  =>
                    array(
                        'Accept-Encoding: identity',
                    ),
            ),           
    );

    $context = stream_context_create($opts);

    $contents = file_get_contents('URL', false, $context);
Tomás Cot
  • 992
  • 1
  • 8
  • 18
-4

i had a similar problem, got it to work after adding '' (single quotes) around the json_encode string. Following from my js file:

var myJsVar  = <?php echo json_encode($var); ?> ;    -------> NOT WORKING  
var myJsVar = '<?php echo json_encode($var); ?>' ;    -------> WORKING

just thought of posting it in case someone stumbles upon this post like me :)

harry
  • 1
  • This doesn't make sense, you'd have a string that you'd need to eval to use from JS. The question is about the json_encode call failing. – Ruan Mendes Jan 07 '11 at 20:04