51

I got a very strange problem.

I have a JSON webservice.

When i check it with this website http://www.freeformatter.com/json-formatter.html#ad-output

Everything is OK.

But when i load my JSON with this code :

  $data = file_get_contents('http://www.mywebservice');

if(!empty($data))
{

    $obj = json_decode($data);

 switch (json_last_error()) {
    case JSON_ERROR_NONE:
        echo ' - JSON_ERROR_NONE';
    break;
    case JSON_ERROR_DEPTH:
        echo ' - JSON_ERROR_DEPTH';
    break;
    case JSON_ERROR_STATE_MISMATCH:
        echo ' - JSON_ERROR_STATE_MISMATCH';
    break;
    case JSON_ERROR_CTRL_CHAR:
        echo ' -  JSON_ERROR_CTRL_CHAR';
    break;
    case JSON_ERROR_SYNTAX:
        echo "\r\n\r\n - SYNTAX ERROR \r\n\r\n";
    break;
    case JSON_ERROR_UTF8:
        echo ' - JSON_ERROR_UTF8';
    break;
    default:
        echo ' - Unknown erro';
    break;
}

I got the error : SYNTAX ERROR

WHICH IS NOT HELP FULL AT ALL.

It is a nightmare.

I see that with PHP 5.5 i could use this function : http://php.net/manual/en/function.json-last-error-msg.php

(but i did not succeed to install PHP 5.5 yet, and i m not sure this function will give me more detail)

BenMorel
  • 34,448
  • 50
  • 182
  • 322

17 Answers17

94

I faced the same issue, actually there are some hidden characters unseen and you need to remove it. Here's a global code that works for many cases:

<?php
$checkLogin = file_get_contents("http://yourwebsite.com/JsonData");

// This will remove unwanted characters.
// Check http://www.php.net/chr for details
for ($i = 0; $i <= 31; ++$i) { 
    $checkLogin = str_replace(chr($i), "", $checkLogin); 
}
$checkLogin = str_replace(chr(127), "", $checkLogin);

// This is the most common part
// Some file begins with 'efbbbf' to mark the beginning of the file. (binary level)
// here we detect it and we remove it, basically it's the first 3 characters 
if (0 === strpos(bin2hex($checkLogin), 'efbbbf')) {
   $checkLogin = substr($checkLogin, 3);
}

$checkLogin = json_decode( $checkLogin );
print_r($checkLogin);
?>
Kris Khairallah
  • 1,537
  • 13
  • 16
  • 6
    Dear sir, you have no idea how much this helped me. I looked everywhere for the solution and i almost gave up. Sir you are a godsend. – SkyPunch Nov 23 '14 at 08:43
  • Still wondering why this is not part of core PHP at version 7.0.x. (face palm) – George Onofrei Aug 15 '16 at 20:06
  • +1 for BOM, didn't come to mind. @GeorgeOnofrei, single responsibility principle would dictate that it's not the purpose of this function to perform sanitization if the string contains invalid chars, or a BOM which is technically not part of the JSON document itself! – BenMorel Jun 06 '17 at 11:48
  • This helped in my case... `for ($i = 0; $i <= 31; ++$i) { $checkLogin = str_replace(chr($i), "", $checkLogin); }` But why?? – Sampgun Oct 20 '17 at 17:56
  • I was getting this error from a payment gateway API response. This was the fix for the syntax error. Specifically filtering out the 'efbbbf'. – JSG Jul 26 '19 at 15:56
  • anyway I can view this hidden char ? – neobie Mar 08 '21 at 05:14
65

Removing the BOM (Byte Order Mark) is often-times the solution you need:

function removeBOM($data) {
    if (0 === strpos(bin2hex($data), 'efbbbf')) {
       return substr($data, 3);
    }
    return $data;
}

You shouldn't have a BOM, but if it's there, it is invisible so you won't see it!!

see W3C on BOM's in HTML

use BOM Cleaner if you have lot's of files to fix.

Alive to die - Anant
  • 70,531
  • 10
  • 51
  • 98
Greg Rundlett
  • 1,056
  • 9
  • 11
  • 4
    I have changed encoding from `UTF-8` TO `UTF-8 without BOM` by `Notepad++` from `top menu of Notepad++>Format>UTF-8 without BOM` – deadfish Nov 11 '16 at 10:48
  • Lost almost 1 hour trying a million things before finding this answer... thanks heaps! – dmmd Jan 24 '18 at 04:30
34

I solved this issue adding stripslashes to the string, before json_decode.

$data = stripslashes($data); 
$obj = json_decode($data);
gskema
  • 3,141
  • 2
  • 20
  • 39
hobbito
  • 519
  • 5
  • 5
  • This doesn't work for me like [the `removeBOM()` answer](https://stackoverflow.com/a/31594983/3416774) – Ooker Jan 13 '22 at 09:09
7

To put all things together here and there, I've prepared JSON wrapper with decoding auto corrective actions. Most recent version can be found in my GitHub Gist.

abstract class Json
{
    public static function getLastError($asString = FALSE)
    {
        $lastError = \json_last_error();

        if (!$asString) return $lastError;

        // Define the errors.
        $constants = \get_defined_constants(TRUE);
        $errorStrings = array();

        foreach ($constants["json"] as $name => $value)
            if (!strncmp($name, "JSON_ERROR_", 11))
                $errorStrings[$value] = $name;

        return isset($errorStrings[$lastError]) ? $errorStrings[$lastError] : FALSE;
    }

    public static function getLastErrorMessage()
    {
        return \json_last_error_msg();
    }

    public static function clean($jsonString)
    {
        if (!is_string($jsonString) || !$jsonString) return '';

        // Remove unsupported characters
        // Check http://www.php.net/chr for details
        for ($i = 0; $i <= 31; ++$i)
            $jsonString = str_replace(chr($i), "", $jsonString);

        $jsonString = str_replace(chr(127), "", $jsonString);

        // Remove the BOM (Byte Order Mark)
        // It's the most common that some file begins with 'efbbbf' to mark the beginning of the file. (binary level)
        // Here we detect it and we remove it, basically it's the first 3 characters.
        if (0 === strpos(bin2hex($jsonString), 'efbbbf')) $jsonString = substr($jsonString, 3);

        return $jsonString;
    }

    public static function encode($value, $options = 0, $depth = 512)
    {
        return \json_encode($value, $options, $depth);
    }

    public static function decode($jsonString, $asArray = TRUE, $depth = 512, $options = JSON_BIGINT_AS_STRING)
    {
        if (!is_string($jsonString) || !$jsonString) return NULL;

        $result = \json_decode($jsonString, $asArray, $depth, $options);

        if ($result === NULL)
            switch (self::getLastError())
            {
                case JSON_ERROR_SYNTAX :
                    // Try to clean json string if syntax error occured
                    $jsonString = self::clean($jsonString);
                    $result = \json_decode($jsonString, $asArray, $depth, $options);
                    break;

                default:
                    // Unsupported error
            }

        return $result;
    }
}

Example usage:

$json_data = file_get_contents("test.json");
$array = Json::decode($json_data, TRUE);
var_dump($array);
echo "Last error (" , Json::getLastError() , "): ", Json::getLastError(TRUE), PHP_EOL;
Pang
  • 9,564
  • 146
  • 81
  • 122
Krzysztof Przygoda
  • 1,217
  • 1
  • 17
  • 24
7

in my case:

json_decode(html_entity_decode($json_string));

Oleg Averkov
  • 304
  • 3
  • 5
4

I have the same problem, receiving JSON_ERROR_CTRL_CHAR and JSON_ERROR_SYNTAX.
This is my fix.

$content = json_decode(json_encode($content), true);
3

After trying all the solution without the result this is the one worked for me.

Hope it will help someone

$data = str_replace('&quot;', '"', $data);
Bheru Lal Lohar
  • 880
  • 9
  • 17
1

You haven't show your JSON but this sound like it could be an Invalid UTF-8 sequence in argument, most online validator wont catch it. make sure your data is UTF-8 and also check if you have foreign characters. You don't need PHP5 to see your error, use error_log() to log the problems.

meda
  • 45,103
  • 14
  • 92
  • 122
1

I had the same issues. I took the following steps:

  1. changed the JSON text encoding

    $json = utf8_encode($json);
    
  2. I then viewed the plain text before decoding. I found crazy symbols like

    ï

  3. then I just stripped it off

    $json = str_replace(array('ï',''), '',$json);
    

    and I successfully decoded my JSON

Siong Thye Goh
  • 3,518
  • 10
  • 23
  • 31
1

please first clean json data and then load.

1

A JSON string must be double-quoted, the JSON isn't valid because you don't need to escape ' character.

char = unescaped /
  escape (
      %x22 /          ; "    quotation mark  U+0022
      %x5C /          ; \    reverse solidus U+005C
      %x2F /          ; /    solidus         U+002F
      %x62 /          ; b    backspace       U+0008
      %x66 /          ; f    form feed       U+000C
      %x6E /          ; n    line feed       U+000A
      %x72 /          ; r    carriage return U+000D
      %x74 /          ; t    tab             U+0009
      %x75 4HEXDIG )  ; uXXXX                U+XXXX

The ' is not in the list.

See this list of special character used in JSON:

\b  Backspace (ascii code 08)
\f  Form feed (ascii code 0C)
\n  New line
\r  Carriage return
\t  Tab
\"  Double quote
\\  Backslash character

Check out this site for more documentation.

Ömürcan Cengiz
  • 2,085
  • 3
  • 22
  • 28
1

I faced this issue as well and it was so frustrating for me. after hours of trying different solutions on the internet. I noticed that the encoding of the file is in UTF-8 with BOM as var_dump() was echoing a weird character &#65279; before the JSON.

I converted the sample.json file I was working with from UTF-8 with BOM to UTF-8 ... In VS CODE add the below to your settings.json or make sure the below settings code is as seen below (so that any file you create will be encoded in UTF-8 by default;

"files.encoding": "utf8",

Then you'll see something like the below screenshot on your VSCode toolbar. (For json_decode() to work, the file has to be encoded in UTF-8)

enter image description here

But in my case, the JSON file I created was having a UTF-8 with BOM encoding which is why when I was doing json_decode($json, true) it was returning null (Syntax Error when I var_dump(json_last_error_msg()) )

enter image description here

  1. Click on the UTF-8 with BOM, then you will get the dropdown,
  2. Click Save with Encoding,
  3. You should get the below screenshot, then you click on UTF-8.

enter image description here

That will resave your file with UTF-8 encoding and you can go ahead and check your code. json_decode() will work fine. Can't believe I spent hours trying to figure out what could be wrong.

Happy Coding!

0

I faced the same issue, The reason is the responsed texts look like a json, but it is actually a text in HTML format. You can echo your text (json look-alike) in JSON format, to see what is actual inside:

$response = file_get_contents('http://www.mywebservice');
header('Content-Type: application/json');
echo $response;

This function file_get_contents will return some extra HTML codes. In my case, I remove those unwanted characters :

$response = str_replace('<head></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">', '',$response );
$response = str_replace('</pre></body>', '',$response );

Here is the complete code:

$response = file_get_contents('http://www.mywebservice');
$response = str_replace('<head></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">', '',$response );
$response = str_replace('</pre></body>', '',$response );
$response = json_decode($response);
header('Content-Type: application/json');            
$error = json_last_error_msg() ;
echo $error;

if ($error == null){echo "This is truly a JSON : <br>"}
echo $response;
Dylan B
  • 796
  • 8
  • 16
-1

One problem from my side, is that there were some invalid numbers starting with 0, Ex: "001", "002", "003".

     "expectedToBeReturned":1,
     "inventoryNumber":001,
     "remindNote":"",

Replace 001 with 1 and it works.

Stefan Pintilie
  • 677
  • 8
  • 5
-2

I had same issue. For me it was causing by echo "<br/><pre>". I was trying to pass json string to another php file using exit(json_encode(utf8ize($resp_array))); At the beginning of file i had decleared break line tag... So this was error for me. Removing this break line tag , i was able to decoding my json string an other php file..

Phoenix404
  • 898
  • 1
  • 14
  • 29
-2

I had same issue. For me it was causing by echo "<br/><pre>".

I was trying to pass json string to another php file using :

exit(json_encode(utf8ize($resp_array)));

At the beginning of file I had decleared break line tag... So this was error for me. Removing this break line tag , I was able to [...]

Mindsers
  • 662
  • 8
  • 25
cccc
  • 1
  • this isn't the same issue as described in the question, but it is a very common type of problem and can be hard to spot so it is good to have it mentioned. – Simba Oct 11 '17 at 12:44
-2

This code worked for me. Basically it removes hidden characters.

    function cleanString($val)
    {
        $non_displayables = array(
        '/%0[0-8bcef]/',            # url encoded 00-08, 11, 12, 14, 15
        '/%1[0-9a-f]/',             # url encoded 16-31
        '/[\x00-\x08]/',            # 00-08
        '/\x0b/',                   # 11
        '/\x0c/',                   # 12
        '/[\x0e-\x1f]/',            # 14-31
        '/x7F/'                     # 127
        );
        foreach ($non_displayables as $regex)
        {
            $val = preg_replace($regex,'',$val);
        }
        $search  = array("\0","\r","\x1a","\t");
        return trim(str_replace($search,'',$val));
    }