64

I'm trying handle bad json data when parsed through json_decode(). I'm using the following script:

if(!json_decode($_POST)) {
 echo "bad json data!";
 exit;
}

If $_POST equals:

'{ bar: "baz" }'

Then json_decode handles the error fine and spits out "bad json data!"; However, if I set $_POST to something like "invalid data", it gives me:

Warning: json_decode() expects parameter 1 to be string, array given in C:\server\www\myserver.dev\public_html\rivrUI\public_home\index.php on line 6
bad json data!

Do I need to write a custom script to detect valid json data, or is there some other nifty way to detect this?

asked Feb 27, 2010 at 16:55
2
  • $_POST is always an array containing the x-www-form-urlencoded parameters passed via POST. How do you send your data to your PHP script? Commented Feb 27, 2010 at 16:58
  • The included json functions in PHP are not much help. They have a lot of issues. Take a look at json.org to find a good library. Commented Feb 27, 2010 at 17:02

8 Answers 8

131

Here are a couple of things about json_decode :

  • it returns the data, or null when there is an error
  • it can also return null when there is no error : when the JSON string contains null
  • it raises a warning where there is a warning -- warning that you want to make disappear.

To solve the warning problem, a solution would be to use the [`@` operator][2] *(I don't often recommend using it, as it makes debuging a lot more harder... But here, there is not much of a choice)* :
$_POST = array(
 'bad data'
);
$data = @json_decode($_POST);

You'd then have to test if $data is null -- and, to avoid the case in which json_decode returns null for null in the JSON string, you could check json_last_error, which (quoting) :

Returns the last error (if any) occurred by last JSON parsing.


Which means you'd have to use some code like the following :
if ($data === null
 && json_last_error() !== JSON_ERROR_NONE) {
 echo "incorrect data";
}
answered Feb 27, 2010 at 17:01
Sign up to request clarification or add additional context in comments.

2 Comments

As Harry Bosch pointed out in another answer, you need only check for JSON_ERROR_NONE !== json_last_error()
PHP 8 returns the error if a function fails with "@" (instead of returning false as before).
48

Since PHP 7.3, the json_decode function will accept a new JSON_THROW_ON_ERROR option that will let json_decode throw an exception instead of returning null on error.


Example:

try { 
 json_decode("{", false, 512, JSON_THROW_ON_ERROR); 
} 
catch (\JsonException $exception) { 
 echo $exception->getMessage(); // displays "Syntax error" 
}
answered May 1, 2019 at 14:58

4 Comments

This should be the accepted answer. JSON_THROW_ON_ERROR constant
I received an exception: "Warning: Use of undefined constant JSON_THROW_ON_ERROR - assumed 'JSON_THROW_ON_ERROR' (this will throw an Error in a future version of PHP) in <file_path>
@domdambrogia The JSON_THROW_ON_ERROR constant is only available from PHP 7.3
doesn't work on 7.3.24 the error is there but couldn't catch it
28

You can also use json_last_error : http://php.net/manual/en/function.json-last-error.php

which as documentation says :

Returns the last error (if any) occurred during the last JSON encoding/decoding.

here is an example

json_decode($string);
switch (json_last_error()) {
 case JSON_ERROR_NONE:
 echo ' - No errors';
 break;
 case JSON_ERROR_DEPTH:
 echo ' - Maximum stack depth exceeded';
 break;
 case JSON_ERROR_STATE_MISMATCH:
 echo ' - Underflow or the modes mismatch';
 break;
 case JSON_ERROR_CTRL_CHAR:
 echo ' - Unexpected control character found';
 break;
 case JSON_ERROR_SYNTAX:
 echo ' - Syntax error, malformed JSON';
 break;
 case JSON_ERROR_UTF8:
 echo ' - Malformed UTF-8 characters, possibly incorrectly encoded';
 break;
 default:
 echo ' - Unknown error';
 break;
}
answered Jul 30, 2013 at 15:31

2 Comments

This is completely unnecessary in PHP 5.5 with php.net/manual/en/function.json-last-error-msg.php
You could do something like this with json_last_error_msg: if (JSON_ERROR_NONE !== json_last_error()) throw new Exception(json_last_error_msg());
12

This is how Guzzle handles json

 /**
 * Parse the JSON response body and return an array
 *
 * @return array|string|int|bool|float
 * @throws RuntimeException if the response body is not in JSON format
 */
public function json()
{
 $data = json_decode((string) $this->body, true);
 if (JSON_ERROR_NONE !== json_last_error()) {
 throw new RuntimeException('Unable to parse response body into JSON: ' . json_last_error());
 }
 return $data === null ? array() : $data;
}
answered Jun 9, 2017 at 3:41

Comments

11

I just broke my head over a json syntax error in what appeared to be perfect json: {"test1":"car", "test2":"auto"} from a url encoded string.

But in my case some of the above was html encoded, as adding html_entity_decode($string) did the trick.

$ft = json_decode(html_entity_decode(urldecode(filter_input(INPUT_GET, 'ft', FILTER_SANITIZE_STRING))));

Hopefully this will save someone else some time.

Tomáš Fejfar
11.2k8 gold badges58 silver badges85 bronze badges
answered Aug 21, 2016 at 2:01

Comments

3

I just spent an hour going through all the possible solutions on this page. I took the liberty of collective all these possible solutions into one function, to make it quicker and easier to try and debug.

I hope it can be of use to someone else.

<?php
/**
 * Decontaminate text
 *
 * Primary sources:
 * - https://stackoverflow.com/questions/17219916/json-decode-returns-json-error-syntax-but-online-formatter-says-the-json-is-ok
 * - https://stackoverflow.com/questions/2348152/detect-bad-json-data-in-php-json-decode
 */
function decontaminate_text(
 $text,
 $remove_tags = true,
 $remove_line_breaks = true,
 $remove_BOM = true,
 $ensure_utf8_encoding = true,
 $ensure_quotes_are_properly_displayed = true,
 $decode_html_entities = true
){
 if ( '' != $text && is_string( $text ) ) {
 $text = preg_replace( '@<(script|style)[^>]*?>.*?</\1円>@si', '', $text );
 $text = str_replace(']]>', ']]&gt;', $text);
 if( $remove_tags ){
 // Which tags to allow (none!)
 // $text = strip_tags($text, '<p>,<strong>,<span>,<a>');
 $text = strip_tags($text, '');
 }
 if( $remove_line_breaks ){
 $text = preg_replace('/[\r\n\t ]+/', ' ', $text);
 $text = trim( $text );
 }
 if( $remove_BOM ){
 // Source: https://stackoverflow.com/a/31594983/1766219
 if( 0 === strpos( bin2hex( $text ), 'efbbbf' ) ){
 $text = substr( $text, 3 );
 }
 }
 if( $ensure_utf8_encoding ){
 // Check if UTF8-encoding
 if( utf8_encode( utf8_decode( $text ) ) != $text ){
 $text = mb_convert_encoding( $text, 'utf-8', 'utf-8' );
 }
 }
 if( $ensure_quotes_are_properly_displayed ){
 $text = str_replace('&quot;', '"', $text);
 }
 if( $decode_html_entities ){
 $text = html_entity_decode( $text );
 }
 /**
 * Other things to try
 * - the chr-function: https://stackoverflow.com/a/20845642/1766219
 * - stripslashes (THIS ONE BROKE MY JSON DECODING, AFTER IT STARTED WORKING, THOUGH): https://stackoverflow.com/a/28540745/1766219
 * - This (improved?) JSON-decoder didn't help me, but it sure looks fancy: https://stackoverflow.com/a/43694325/1766219
 */
 }
 return $text;
}
// Example use
$text = decontaminate_text( $text );
// $text = decontaminate_text( $text, false ); // Debug attempt 1
// $text = decontaminate_text( $text, false, false ); // Debug attempt 2
// $text = decontaminate_text( $text, false, false, false ); // Debug attempt 3
$decoded_text = json_decode( $text, true );
echo json_last_error_msg() . ' - ' . json_last_error();
?>

I'll maintain it here: https://github.com/zethodderskov/decontaminate-text-in-php/blob/master/decontaminate-text-preparing-it-for-json-decode.php

answered Sep 17, 2019 at 16:26

Comments

2
/**
 * 
 * custom json_decode 
 * handle json_decode errors
 * 
 * @param type $json_text
 * @return type
 */
public static function custom_json_decode($json_text) {
 $decoded_array = json_decode($json_text, TRUE);
 switch (json_last_error()) {
 case JSON_ERROR_NONE:
 return array(
 "status" => 0,
 "value" => $decoded_array
 );
 case JSON_ERROR_DEPTH:
 return array(
 "status" => 1,
 "value" => 'Maximum stack depth exceeded'
 );
 case JSON_ERROR_STATE_MISMATCH:
 return array(
 "status" => 1,
 "value" => 'Underflow or the modes mismatch'
 );
 case JSON_ERROR_CTRL_CHAR:
 return array(
 "status" => 1,
 "value" => 'Unexpected control character found'
 );
 case JSON_ERROR_SYNTAX:
 return array(
 "status" => 1,
 "value" => 'Syntax error, malformed JSON'
 );
 case JSON_ERROR_UTF8:
 return array(
 "status" => 1,
 "value" => 'Malformed UTF-8 characters, possibly incorrectly encoded'
 );
 default:
 return array(
 "status" => 1,
 "value" => 'Unknown error'
 );
 }
}
Tomáš Fejfar
11.2k8 gold badges58 silver badges85 bronze badges
answered Sep 18, 2016 at 17:21

Comments

-1

For PHP 5.2+ . Note the first check.

<?php
class JsonUtil {
 static function decode($json, $associative = null, $depth = null) {
 if (strtolower(trim($json)) === "null") {
 return null;
 }
 
 if (is_null($associative)) {
 $res = json_decode($json);
 }
 else {
 if (is_null($depth)) {
 $depth = 512;
 }
 
 $res = json_decode($json, $associative, $depth);
 }
 
 if (is_null($res)) {
 throw new Exception("Unable to decode JSON");
 }
 
 return $res;
 }
}
answered Feb 10, 2023 at 17:20

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.