551

I need a really, really fast method of checking if a string is JSON or not. I feel like this is not the best way:

function isJson($string) {
    return ((is_string($string) &&
            (is_object(json_decode($string)) ||
            is_array(json_decode($string))))) ? true : false;
}

Any performance enthusiasts out there want to improve this method?

9
  • 3
    Consider only using json_decode once... also, check the input and return values of json_decode.
    – user166390
    Commented May 18, 2011 at 8:20
  • 8
    So, which one is the answer?
    – Farid Rn
    Commented Dec 6, 2012 at 19:11
  • 12
    The ternary switch here is redundant. Your statement already evaluates as a boolean. Commented Apr 9, 2015 at 17:46
  • 1
    Accept the answer of Lewis Donovan ...it is working fine Commented Sep 4, 2018 at 13:24
  • 1
    looking at the solutions, performance vs simplicity should have been the prime focus of OP because fastest always depends on the use case, for eg., If you know you'll always deal with object/array, checking for first char of the string should suffice. Generalizing a solution can be never be "fastest"; "faster", may be.
    – Fr0zenFyr
    Commented Feb 20, 2019 at 8:45

30 Answers 30

785
Answer recommended by PHP Collective
function isJson($string) {
   json_decode($string);
   return json_last_error() === JSON_ERROR_NONE;
}

PHP >= 8.3 solution:

use json_validate() built-in function

28
  • 26
    Looks like everyone is loving this answer. Any explanation why? Commented May 18, 2011 at 17:39
  • 122
    Checking first character of string for {, [ or first symbol of any other literal can potentially greatly speed this one up when many of incoming strings are expected to be non-JSON. Commented Sep 25, 2012 at 17:03
  • 24
    $phone = '021234567'; var_dump(isJson($phone)); return true no! it should return false.
    – vee
    Commented Jan 2, 2014 at 17:12
  • 30
    Beware, this function will return true for any number also, whether you specify it as a string or a true number. 6.5 = true, '300' = true, 9 = true etc. So this might be a valid JSON value but the function might not behave as you expect, if you want to check only for valid JSON strings with {} or [];
    – BadHorsie
    Commented Feb 25, 2014 at 16:57
  • 22
    It's worth noting that this works correctly in theory. Unfortunately PHP's json_decode function has a number of bugs, which will allow invalid JSON to be parsed in odd ways. isJson('0123') should return false because 0123 is not JSON, however isJson('123') should return true because 123 is JSON. It seems that some people are not aware that JSON allows values to be more than just an object or array. Valid JSON values may be objects, arrays, numbers, strings, booleans, and null.
    – zzzzBov
    Commented May 8, 2015 at 1:30
237

Answer to the Question

The function json_last_error returns the last error occurred during the JSON encoding and decoding. So the fastest way to check the valid JSON is

// decode the JSON data
// set second parameter boolean TRUE for associative array output.
$result = json_decode($json);

if (json_last_error() === JSON_ERROR_NONE) {
    // JSON is valid
}

// OR this is equivalent

if (json_last_error() === 0) {
    // JSON is valid
}

Note that json_last_error is supported in PHP >= 5.3.0 only.

Full program to check the exact ERROR

It is always good to know the exact error during the development time. Here is full program to check the exact error based on PHP docs.

function json_validate($string)
{
    // decode the JSON data
    $result = json_decode($string);

    // switch and check possible JSON errors
    switch (json_last_error()) {
        case JSON_ERROR_NONE:
            $error = ''; // JSON is valid // No error has occurred
            break;
        case JSON_ERROR_DEPTH:
            $error = 'The maximum stack depth has been exceeded.';
            break;
        case JSON_ERROR_STATE_MISMATCH:
            $error = 'Invalid or malformed JSON.';
            break;
        case JSON_ERROR_CTRL_CHAR:
            $error = 'Control character error, possibly incorrectly encoded.';
            break;
        case JSON_ERROR_SYNTAX:
            $error = 'Syntax error, malformed JSON.';
            break;
        // PHP >= 5.3.3
        case JSON_ERROR_UTF8:
            $error = 'Malformed UTF-8 characters, possibly incorrectly encoded.';
            break;
        // PHP >= 5.5.0
        case JSON_ERROR_RECURSION:
            $error = 'One or more recursive references in the value to be encoded.';
            break;
        // PHP >= 5.5.0
        case JSON_ERROR_INF_OR_NAN:
            $error = 'One or more NAN or INF values in the value to be encoded.';
            break;
        case JSON_ERROR_UNSUPPORTED_TYPE:
            $error = 'A value of a type that cannot be encoded was given.';
            break;
        default:
            $error = 'Unknown JSON error occured.';
            break;
    }

    if ($error !== '') {
        // throw the Exception or exit // or whatever :)
        exit($error);
    }

    // everything is OK
    return $result;
}

Testing with Valid JSON INPUT

$json = '[{"user_id":13,"username":"stack"},{"user_id":14,"username":"over"}]';
$output = json_validate($json);
print_r($output);

Valid OUTPUT

Array
(
    [0] => stdClass Object
        (
            [user_id] => 13
            [username] => stack
        )

    [1] => stdClass Object
        (
            [user_id] => 14
            [username] => over
        )
)

Testing with invalid JSON

$json = '{background-color:yellow;color:#000;padding:10px;width:650px;}';
$output = json_validate($json);
print_r($output);

Invalid OUTPUT

Syntax error, malformed JSON.

Extra note for (PHP >= 5.2 && PHP < 5.3.0)

Since json_last_error is not supported in PHP 5.2, you can check if the encoding or decoding returns boolean FALSE. Here is an example

// decode the JSON data
$result = json_decode($json);
if ($result === FALSE) {
    // JSON is invalid
}
4
  • Little precision : if this json is valid but a previous decoded one is invalid, your code is going to work correctly, because : "Returns the last error (if any) occurred during the last JSON encoding/decoding."
    – Bruno
    Commented Dec 20, 2016 at 11:58
  • Thanks @Madan, the "json_decode" verification solved to me that I running PHP 7.0. Commented Feb 25, 2017 at 14:30
  • 1
    Surely json_decode could just return false for the literal false, so a check ((strlen($json) === 5) && ($json !== 'false')) should also be undertaken to avoid that edge?
    – MrMesees
    Commented Jul 11, 2017 at 8:18
  • @Bruno If the last decoding works without errors then json_last_error returns JSON_ERROR_NONE.
    – Andrea
    Commented Feb 14, 2018 at 13:50
108

All you really need to do is this...

if (is_object(json_decode($MyJSONArray))) 
{ 
    ... do something ...
}

This request does not require a separate function even. Just wrap is_object around json_decode and move on. Seems this solution has people putting way too much thought into it.

4
  • 3
    @RomanM.Kos Just to be clear, if the array is a simple array, then you need to use is_array in addition to is_object, else is_object will return false for simple arrays encoded as JSON. So @ggutenberg is right in this case. Passing the true argument to json_decode forces an object to be returned as an array. You could in theory always force the decode to an array and just check of is_array, that should work.
    – userabuser
    Commented Feb 14, 2014 at 10:24
  • @userabuser If i json_encode($array) for simple PHP array, and then do json_decode($str) i will receive object, but not array. json_decode($str, true) forces to convert into array. Why do complicated string in your code? Check for is_array(json_decode($str, true)) and some time later when you read it you will understand that decoded must be only an array. Much harder to guess is_object(json_decode($MyJSONArray)) "Oh, here i am checking for decoded is an array or not?" Commented Feb 14, 2014 at 22:35
  • @RomanM.Kos No, that's not correct, codepad.viper-7.com/OFrtsq - as I said, you can always force json_decode to return an array to save you checking for object and array, but if you don't AND you json_decode what was a simple array to begin with, you will receive an array in return on decode, not an object. You must use JSON_FORCE_OBJECT if you want to always force an object on encode IF passing a simple array.
    – userabuser
    Commented Feb 15, 2014 at 5:07
  • 29
    Downvote for saying: This request does not require a separate function even. Strictly speaking, no solution requires a separate function. The point of a function is not to make multiple lines of code look like one line of code. The point of the function is to make the JSON-checking process standard everywhere in your application, so that different programmers (or the same programmer over time) don't use different checking procedures at different stages in the flow of the program. Commented Jul 9, 2014 at 8:17
77

Using json_decode to "probe" it might not actually be the fastest way. If it's a deeply nested structure, then instantiating a lot of objects of arrays to just throw them away is a waste of memory and time.

So it might be faster to use preg_match and the RFC4627 regex to also ensure validity:

  // in JS:
  var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
         text.replace(/"(\\.|[^"\\])*"/g, '')));

The same in PHP:

  return !preg_match('/[^,:{}\\[\\]0-9.\\-+Eaeflnr-u \\n\\r\\t]/',
       preg_replace('/"(\\.|[^"\\\\])*"/', '', $json_string));

Not enough of a performance enthusiast to bother with benchmarks here however.

16
  • 16
    Complete recursive regex to verify JSON here: stackoverflow.com/questions/2583472/regex-to-validate-json/… - But it turns out PHPs json_decode is always faster than a PCRE regex. (Though it's not very optimized, no synthetic tests found, and might behave differently in Perl..)
    – mario
    Commented May 31, 2011 at 22:44
  • 3
    @vee Yes, thanks for the note. But let's keep it here [incorrectly], so nobody actually uses that in production.
    – mario
    Commented Jan 2, 2014 at 21:12
  • 1
    @cartbeforehorse Okay, thanks. I fixed the escaping wholesome for PHPs double quoted string context then.
    – mario
    Commented Jul 9, 2014 at 0:30
  • 4
    @mario Okay, I see. So basically, the PHP escapes the backslashes before the reg-exp engine gets to see it. As far as the reg-exp engine is concerned, there are half the number of backslashes in the string as what we humans see. "Like reg-exp wasn't complicated enough already" Commented Jul 9, 2014 at 8:26
  • 2
    I was curious to see if this was actually faster than using json_decode to see if a string is valid JSON so I ran some benchmarks. I ran 100,000 passes of a two-dimensional array that had been encoded using json_encode. PHP version : 5.5.34 Platform : Darwin -------------------------------------- test_json_decode : 5.608 sec. test_regex : 10.428 sec.
    – Alex Plumb
    Commented Jul 19, 2016 at 15:54
72

This will return true if your string represents a json array or object:

function isJson($str) {
    $json = json_decode($str);
    return $json && $str != $json;
}

It rejects json strings that only contains a number, string or boolean, although those strings are technically valid json.

var_dump(isJson('{"a":5}')); // bool(true)
var_dump(isJson('[1,2,3]')); // bool(true)
var_dump(isJson('1')); // bool(false)
var_dump(isJson('1.5')); // bool(false)
var_dump(isJson('true')); // bool(false)
var_dump(isJson('false')); // bool(false)
var_dump(isJson('null')); // bool(false)
var_dump(isJson('hello')); // bool(false)
var_dump(isJson('')); // bool(false)

It is the shortest way I can come up with.

7
  • Rather than var_dump, you could put this in a PHPUnit test-case. Otherwise I'm both surprised and happy to learn it's true.
    – MrMesees
    Commented Jul 11, 2017 at 8:12
  • 4
    Why does everyone else have such long winded answers when this works great? Thanks.
    – toddmo
    Commented May 13, 2018 at 17:19
  • 2
    Simply, lovely! Didn't check for "fastest way" or performance wise but this one sure covers all the cases I'd ever check for. This is a classic example for the infamous proverb "Don't use sledgehammer to crack a nut". From a programmer point of view, it is always better to keep the code simple, short and easy to understand, performance vs simplicity is another debate out of scope for this thread.
    – Fr0zenFyr
    Commented Feb 20, 2019 at 8:39
  • 1
    @j13k Identical comparison evaluates isJson('hello') to true, which isn’t valid json. Loose comparison is chosen on purpose here. I don’t have a quick solution for the empty array/object situation, except an ugly return $json == '[]' || ...
    – Cyril
    Commented Oct 11, 2019 at 10:43
  • 3
    @Cyril, apologies—I missed that case because my test function includes additional checks to short-circuit the function before calling json_decode. Because the 'hello' string triggers a JSON error, the output of the function is NULL, so an additional !is_null check is enough to yield the correct results with your test data: return $json !== false && !is_null($json) && $str != $json;
    – j13k
    Commented Oct 13, 2019 at 23:26
34

We first perform some type checks and string comparisons before attempting to decode the JSON string. This gives us the best performance because json_decode() can be slow.

/**
 * Returns true, when the given parameter is a valid JSON string.
 */
function is_json( $value ) {
    // Numeric strings are always valid JSON.
    if ( is_numeric( $value ) ) { return true; }

    // A non-string value can never be a JSON string.
    if ( ! is_string( $value ) ) { return false; }

    // Any non-numeric JSON string must be longer than 2 characters.
    if ( strlen( $value ) < 2 ) { return false; }

    // "null" is valid JSON string.
    if ( 'null' === $value ) { return true; }

    // "true" and "false" are valid JSON strings.
    if ( 'true' === $value ) { return true; }
    if ( 'false' === $value ) { return true; }

    // Any other JSON string has to be wrapped in {}, [] or "".
    if ( '{' != $value[0] && '[' != $value[0] && '"' != $value[0] ) { return false; }

    // Verify that the trailing character matches the first character.
    $last_char = $value[strlen($value) -1];
    if ( '{' == $value[0] && '}' != $last_char ) { return false; }
    if ( '[' == $value[0] && ']' != $last_char ) { return false; }
    if ( '"' == $value[0] && '"' != $last_char ) { return false; }

    // See if the string contents are valid JSON.
    return null !== json_decode( $value );
}

Extra: Use this logic to safely double-decode JSON

This function uses the same logic but either returns the decoded JSON object or the original value.

I use this function in a parser that recursively decodes a complex object. Some attributes might be decoded already by an earlier iteration. That function recognizes this and does not attempt to double decode the value again.

/**
 * Tests, if the given $value parameter is a JSON string.
 * When it is a valid JSON value, the decoded value is returned.
 * When the value is no JSON value (i.e. it was decoded already), then 
 * the original value is returned.
 */
function get_data( $value, $as_object = false ) {
    if ( is_numeric( $value ) ) { return 0 + $value; }
    if ( ! is_string( $value ) ) { return $value; }
    if ( strlen( $value ) < 2 ) { return $value; }
    if ( 'null' === $value ) { return null; }
    if ( 'true' === $value ) { return true; }
    if ( 'false' === $value ) { return false; }
    if ( '{' != $value[0] && '[' != $value[0] && '"' != $value[0] ) { return $value; }

    $json_data = json_decode( $value, $as_object );
    if ( is_null( $json_data ) ) { return $value; }
    return $json_data;
}

Note: When passing a non-string to any of the other solution in this SO question, you will get dramatically degraded performance + wrong return values (or even fatal errors). This code is bulletproof and highly performant.

9
  • 1
    I'm not sure, why this answer is downvoted and even has a delete request. My performance test clearly shows that it's the fastest method by far. Here is the performance comparison script: gist.github.com/stracker-phil/6a80e6faedea8dab090b4bf6668ee461
    – Philipp
    Commented Feb 6, 2021 at 14:52
  • 1
    +1 for sheer effort :) I think it is amazing that your test is actually faster when it actually has 8 "if" statements. I assume people won't like it because it is not at all elegant and it really is not much of an overhead difference unless you needed to check about a million bits of text. Commented Jun 10, 2021 at 20:15
  • 2
    @EnigmaPlus thanks :) And right, the code is no elegant one-liner, but the question was about finding the fastest way, not the most elegant/shortest. json_decode is shorter, but requires PHP to initialize an internal JSON-Parser instance that is quite complex and a lot slower than 8 simple ifs 😉
    – Philipp
    Commented Jun 10, 2021 at 20:29
  • 1
    Your example of $json_data = json_decode($value,null,1); returns NULL when evaluating like '{"a":5}' or '[1,2,3]'. Should be two levels, like: json_decode($value,null,2);
    – Eric P
    Commented Jan 3, 2022 at 8:29
  • 1
    is_numeric($value) should be the first evaluation.
    – Eric P
    Commented Jan 3, 2022 at 8:50
29

The simplest and fastest way that I use is following;

$json_array = json_decode( $raw_json , true );

if( $json_array == NULL )   //check if it was invalid json string
    die ('Invalid');  // Invalid JSON error

 // you can execute some else condition over here in case of valid JSON

It is because json_decode() returns NULL if the entered string is not json or invalid json.


Simple function to validate JSON

If you have to validate your JSON in multiple places, you can always use the following function.

function is_valid_json( $raw_json ){
    return ( json_decode( $raw_json , true ) == NULL ) ? false : true ; // Yes! thats it.
}

In the above function, you will get true in return if it is a valid JSON.

4
29

PHP 8.3

Native PHP function

json_validate(string $json, int $depth = 512, int $flags = 0): bool

https://wiki.php.net/rfc/json_validate

PHP < 8.3

A method that provides similar results to json_validate() above

function is_json($string) {
  return is_numeric($string)
    || in_array($string, ['null', 'true', 'false']
    || ( is_bool($string) && $string )
    || (
      !empty($string) 
      && is_string($string) 
      && is_array(json_decode($string, true)) 
      && json_last_error() === JSON_ERROR_NONE
    );
}

Sometimes it can be helpful to see if the JSON object has data, either an object or array

function has_json_data($string) {
  return !empty($string) 
    && is_string($string) 
    && is_array($array = json_decode($string, true)) 
    && !empty($array) 
    && json_last_error() === JSON_ERROR_NONE;
}
5
  • 1
    +1 for actually thinking about the problem in a real-world context. Commented Jul 9, 2014 at 8:33
  • if(is_string($string) && is_array(json_decode($string, true)) && (json_last_error() == JSON_ERROR_NONE)){ // json is valid }else{ // not valid } Commented Dec 14, 2021 at 7:40
  • see this blog post subinsb.com/php-check-if-string-is-json Commented Dec 14, 2021 at 7:41
  • 3
    As of June 2023, json_validate() is officially part of PHP 8.3 Alpha-2 release.
    – Asad Ali
    Commented Jun 26, 2023 at 11:55
  • 1
    @upful bare numbers are valid JSON, as are the values true, false, and null. And you should never use fixed values in place of constants.
    – miken32
    Commented Dec 2, 2023 at 20:54
25
function is_json($str){ 
    return json_decode($str) != null;
}

http://tr.php.net/manual/en/function.json-decode.php return value is null when invalid encoding detected.

5
  • I think this sould be: json_decode($str)!=null; or otherwise the function should be called is_not_json.
    – Yoshi
    Commented May 18, 2011 at 8:23
  • That function would be better renamed "is something other than JSON"! Commented May 18, 2011 at 8:23
  • 3
    @user166390, json_decode('null') is valid JSON according to the spec, and should return the value of null.
    – zzzzBov
    Commented May 8, 2015 at 1:23
  • 1
    Please also note that with this method is_json('false') and is_json('[]') will return false as type is not checked. I think this method should rather return $str === null || json_decode($str) !== null. Commented Aug 13, 2015 at 14:01
  • The related question of Is null valid JSON?.
    – ikhvjs
    Commented Aug 11, 2021 at 7:52
16

I found this question after coming across something similar in my work, yesterday. My solution in the end was a hybrid of some of the approaches above:

function is_JSON($string) {

  return (is_null(json_decode($string))) ? FALSE : TRUE;
}
6
  • 1
    I wasn't used too as well, hehe. Since PhpStorm and Magento Code Sniffer tool I was using always complained with me, I started adopting this approach. In the end we get cleaner code and get used to it. :P Commented Jun 24, 2020 at 22:54
  • 2
    The related question of Is null valid JSON?.
    – ikhvjs
    Commented Aug 11, 2021 at 7:52
  • Thanks for this heads up, @ikhvjs. If you wanted to anticipate this case, you could prepend the contents of the function above with the condition: if (is_null($string)) return TRUE;
    – Rounin
    Commented Aug 11, 2021 at 10:37
  • 2
    is_null already returns bool, can be shortened to return is_null(json_decode($string));
    – hanshenrik
    Commented Jul 22, 2022 at 18:06
  • possibly more consistent with the name of the function, one would expect true to be returned for a valid JSON formatted $string... so: return !is_null(json_decode($string));
    – berend
    Commented Feb 17, 2023 at 10:42
14

This will do it:

function isJson($string) {
    $decoded = json_decode($string); // decode our JSON string
    if ( !is_object($decoded) && !is_array($decoded) ) {
        /*
        If our string doesn't produce an object or array
        it's invalid, so we should return false
        */
        return false;
    }
    /*
    If the following line resolves to true, then there was
    no error and our JSON is valid, so we return true.
    Otherwise it isn't, so we return false.
    */
    return (json_last_error() == JSON_ERROR_NONE);
}

if ( isJson($someJsonString) ) {
    echo "valid JSON";
} else {
    echo "not valid JSON";
}

As shown in other answers, json_last_error() returns any error from our last json_decode(). However there are some edge use cases where this function alone is not comprehensive enough. For example, if you json_decode() an integer (eg: 123), or a string of numbers with no spaces or other characters (eg: "123"), the json_last_error() function will not catch an error.

To combat this, I've added an extra step that ensures the result of our json_decode() is either an object or an array. If it's not, then we return false.

To see this in action, check these two examples:

4
  • 1
    "hello" is a valid JSON, and it's not an object neither an array, json_last_error() is enough
    – JoniJnm
    Commented Aug 13, 2019 at 8:59
  • 1
    json_last_error() returns error code 4 when you json_decode() the string "hello". Example here: 3v4l.org/lSsEo Commented Aug 15, 2019 at 12:14
  • 1
    Your code is wrong, hello is not a valid JSON, but "hello" is 3v4l.org/OEJrQ
    – JoniJnm
    Commented Sep 6, 2019 at 11:46
  • Same for false, 46783, null, etc. All valid json.
    – miken32
    Commented Dec 3, 2023 at 14:14
14

Using PHPBench with the following class, the below results were achieved:

<?php

declare(strict_types=1);

/**
 * @Revs(1000)
 * @Iterations(100)
 */
class BenchmarkJson
{
    public function benchCatchValid(): bool
    {
        $validJson = '{"validJson":true}';
        try {
            json_decode($validJson, true, 512, JSON_THROW_ON_ERROR);
            return true;
        } catch(\JsonException $exception) {}
        return false;
    }

    public function benchCatchInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        try {
            json_decode($invalidJson, true, 512, JSON_THROW_ON_ERROR);
            return true;
        } catch(\JsonException $exception) {}
        return false;
    }

    public function benchLastErrorValid(): bool
    {
        $validJson = '{"validJson":true}';
        json_decode($validJson, true);
        return (json_last_error() === JSON_ERROR_NONE);
    }

    public function benchLastErrorInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        json_decode($invalidJson, true);
        return (json_last_error() === JSON_ERROR_NONE);
    }

    public function benchNullValid(): bool
    {
        $validJson = '{"validJson":true}';
        return (json_decode($validJson, true) !== null);
    }

    public function benchNullInvalid(): bool
    {
        $invalidJson = '{"invalidJson"';
        return (json_decode($invalidJson, true) !== null);
    }
}

6 subjects, 600 iterations, 6,000 revs, 0 rejects, 0 failures, 0 warnings
(best [mean mode] worst) = 0.714 [1.203 1.175] 1.073 (μs)
⅀T: 721.504μs μSD/r 0.089μs μRSD/r: 7.270%
suite: 1343ab9a3590de6065bc0bc6eeb344c9f6eba642, date: 2020-01-21, stime: 12:50:14
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+
| benchmark     | subject               | set | revs | its | mem_peak   | best    | mean    | mode    | worst   | stdev   | rstdev | diff  |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+
| BenchmarkJson | benchCatchValid       | 0   | 1000 | 100 | 2,980,168b | 0.954μs | 1.032μs | 1.016μs | 1.428μs | 0.062μs | 6.04%  | 1.33x |
| BenchmarkJson | benchCatchInvalid     | 0   | 1000 | 100 | 2,980,184b | 2.033μs | 2.228μs | 2.166μs | 3.001μs | 0.168μs | 7.55%  | 2.88x |
| BenchmarkJson | benchLastErrorValid   | 0   | 1000 | 100 | 2,980,184b | 1.076μs | 1.195μs | 1.169μs | 1.616μs | 0.083μs | 6.97%  | 1.54x |
| BenchmarkJson | benchLastErrorInvalid | 0   | 1000 | 100 | 2,980,184b | 0.785μs | 0.861μs | 0.863μs | 1.132μs | 0.056μs | 6.54%  | 1.11x |
| BenchmarkJson | benchNullValid        | 0   | 1000 | 100 | 2,980,168b | 0.985μs | 1.124μs | 1.077μs | 1.731μs | 0.114μs | 10.15% | 1.45x |
| BenchmarkJson | benchNullInvalid      | 0   | 1000 | 100 | 2,980,184b | 0.714μs | 0.775μs | 0.759μs | 1.073μs | 0.049μs | 6.36%  | 1.00x |
+---------------+-----------------------+-----+------+-----+------------+---------+---------+---------+---------+---------+--------+-------+

Conclusion: The fastest way to check if json is valid is to return json_decode($json, true) !== null).

1
  • very nice :) i admire you
    – Mahdi
    Commented Feb 19, 2020 at 11:27
9

Easy method is to check the json result..

$result = @json_decode($json,true);
    if (is_array($result)) {
        echo 'JSON is valid';
    }else{
        echo 'JSON is not valid';
    }
7

While PHP 8.3 which is still in development, will come with new memory-efficient json_validate() function, you can use it with older PHP versions (7.1 and newer) thanks to amazing Symfony Polyfill component.

Simply add following package to your project:

composer require symfony/polyfill-php83

and use it in your application:

if (json_validate($data)) {
  // do sometihng
}

Thanks to this approach, you can use new PHP features in older applications and migrate to PHP 8.3 without any code changes in the future as your code will automatically use the built-in function when it's available.

6

in GuzzleHttp:

/**
 * Wrapper for json_decode that throws when an error occurs.
 *
 * @param string $json    JSON data to parse
 * @param bool $assoc     When true, returned objects will be converted
 *                        into associative arrays.
 * @param int    $depth   User specified recursion depth.
 * @param int    $options Bitmask of JSON decode options.
 *
 * @return mixed
 * @throws \InvalidArgumentException if the JSON cannot be decoded.
 * @link http://www.php.net/manual/en/function.json-decode.php
 */
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
{
    $data = \json_decode($json, $assoc, $depth, $options);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_decode error: ' . json_last_error_msg());
    }

    return $data;
}

/**
 * Wrapper for JSON encoding that throws when an error occurs.
 *
 * @param mixed $value   The value being encoded
 * @param int    $options JSON encode option bitmask
 * @param int    $depth   Set the maximum depth. Must be greater than zero.
 *
 * @return string
 * @throws \InvalidArgumentException if the JSON cannot be encoded.
 * @link http://www.php.net/manual/en/function.json-encode.php
 */
function json_encode($value, $options = 0, $depth = 512)
{
    $json = \json_encode($value, $options, $depth);
    if (JSON_ERROR_NONE !== json_last_error()) {
        throw new \InvalidArgumentException(
            'json_encode error: ' . json_last_error_msg());
    }

    return $json;
}
6
//Tested thoroughly, Should do the job:
public static function is_json(string $json):bool
{
    json_decode($json);
    if (json_last_error() === JSON_ERROR_NONE) {
        return true;
    }
    return false;
}
6

The RFC for the json_validate() function is implemented and will be part of PHP 8.3

This method will be the fastest and most efficient way to achieve what the question is asking for.

github - implementation code

rfc - of json_validate()

1
  • Maybe you want to edit this question now that 8.3 has been released and there's documentation for the function.
    – miken32
    Commented Dec 2, 2023 at 20:26
5

Earlier i was just checking for a null value, which was wrong actually.

    $data = "ahad";
    $r_data = json_decode($data);
    if($r_data){//json_decode will return null, which is the behavior we expect
        //success
    }

The above piece of code works fine with strings. However as soon as i provide number, it breaks up.for example.

    $data = "1213145";
    $r_data = json_decode($data);

    if($r_data){//json_decode will return 1213145, which is the behavior we don't expect
        //success
    }

To fix it what i did was very simple.

    $data = "ahad";
    $r_data = json_decode($data);

    if(($r_data != $data) && $r_data)
        print "Json success";
    else
        print "Json error";
1
  • Nice solution. Handles the typing issue very well!
    – Chaoix
    Commented Aug 15, 2014 at 19:40
5

We need to check if passed string is not numeric because in this case json_decode raises no error.

function isJson($str) {
    $result = false;
    if (!preg_match("/^\d+$/", trim($str))) {
        json_decode($str);
        $result = (json_last_error() == JSON_ERROR_NONE);
    }

    return $result;
}
3

Another simple way

function is_json($str)
{
    return is_array(json_decode($str,true));
}
3
  • 1
    This isn't correct. Any PHP type can be encoded into JSON such as objects, strings, etc and the json_decode function is expected to return them. This is only true if you are always decoding arrays and no other variable types.
    – Chaoix
    Commented Aug 15, 2014 at 19:38
  • @Chaoix using json_decode($str,true) makes it convert objects to arrays so it will pass the is_array check. You correct about strings, integers, etc. though. Commented Mar 18, 2015 at 10:05
  • I see the what you mean about the second parameter on json_encode. I still think @Ahad Ali's solution is a much better one in terms of typing and only doing a json_decode once in your algorithms.
    – Chaoix
    Commented Mar 26, 2015 at 17:08
2

I've tried some of those solution but nothing was working for me. I try this simple thing :

$isJson = json_decode($myJSON);

if ($isJson instanceof \stdClass || is_array($isJson)) {
   echo("it's JSON confirmed");
} else {
   echo("nope");
}

I think it's a fine solutiuon since JSON decode without the second parameter give an object.

EDIT : If you know what will be the input, you can adapt this code to your needs. In my case I know I have a Json wich begin by "{", so i don't need to check if it's an array.

1
  • Your JSON could potentially just be an array, in which case it would be an array rather than instead of stdClass $foo = "[1, 1, 2, 3]"; var_dump(json_decode($foo)); => array(4) { [0]=> int(1) [1]=> int(1) [2]=> int(2) [3]=> int(3) } Commented Feb 13, 2018 at 21:48
2

Should be something like this:

 function isJson($string)
 {
    // 1. Speed up the checking & prevent exception throw when non string is passed
    if (is_numeric($string) ||
        !is_string($string) ||
        !$string) {
        return false;
    }

    $cleaned_str = trim($string);
    if (!$cleaned_str || !in_array($cleaned_str[0], ['{', '['])) {
        return false;
    }

    // 2. Actual checking
    $str = json_decode($string);
    return (json_last_error() == JSON_ERROR_NONE) && $str && $str != $string;
}

UnitTest

public function testIsJson()
{
    $non_json_values = [
        "12",
        0,
        1,
        12,
        -1,
        '',
        null,
        0.1,
        '.',
        "''",
        true,
        false,
        [],
        '""',
        '[]',
        '   {',
        '   [',
    ];

   $json_values = [
        '{}',
        '{"foo": "bar"}',
        '[{}]',
        '  {}',
        ' {}  '
    ];

   foreach ($non_json_values as $non_json_value) {
        $is_json = isJson($non_json_value);
        $this->assertFalse($is_json);
    }

    foreach ($json_values as $json_value) {
        $is_json = isJson($json_value);
        $this->assertTrue($is_json);
    }
}
6
  • I like that you're checking if it's a string. Goes well in combination with the first solution to avoid ErrorException if the string is array or object.
    – sykez
    Commented Jan 3, 2020 at 14:45
  • I am glad you can write code to speed up internal ph funcs. I think my computer was crashing trying json_decode a number. this 200 lines of code is definitely less assembly code. Can you write code in 0s and 1s? I am just joking with you my friend. My argument in the form of a joke is do you really think and benchmarked all this much code to be faster than Php internally written in C a lower level program? This function has all sorts of breakpoints you are literally wasting more human time worrying about CPU time that you are mathematically speaking only increasing if it makes any difference.
    – Neo
    Commented Jan 22, 2023 at 20:05
  • I went and found the source code for you: github.com/php/php-src/blob/master/ext/json/json.c
    – Neo
    Commented Jan 22, 2023 at 20:05
  • The function itself is only 18 lines of codes. Even including the unittest it's only around 60 lines. I'm sure you are a joker. 2nd it's written purely in PHP to solve the issues we have here, it's also easy to understand and implement. I'm sure it's only takes time in miliseconds each time calling the function. 3rd unless you can give some better solution in PHP, please do, otherwise it's so inappropriate to mention C here, or you just showing off your C skill sir?
    – Tinh Dang
    Commented Jan 24, 2023 at 4:42
  • It's so weird to see someone comparing a solution gave 5 years ago, with a function very recently added in PHP 8.3 (few months ago) written in C implemented directly in core of PHP, then talk about nonsense topic. Anyway please go and add a new answer, and don't forget to mention that from 8.3 we can use json_validate and use some form of joke you have there to bring joy to the world.
    – Tinh Dang
    Commented Jan 24, 2023 at 5:12
2

Hi here's a little snippet from my library, in this first condition I'm just checking if the data is json then return it if correctly decoded, please note the substr usage for performance ( I haven't seen yet any json file not begining neither by { or [

$input=trim($input);
if ((substr($input, 0, 1) == '{' && substr($input, -1) == '}') or (substr($input, 0, 1) == '[' && substr($input, -1) == ']')) {
    $output = json_decode($input, 1);
    if (in_array(gettype($output),['object','array'])) {
        #then it's definitely JSON
    }
}
2
  • There have been 34 answers posted to this question, many of which also subscribe to the (mistaken) belief that JSON has to represent an array or an object. Is this answer doing anything different from the other 3 dozen answers?
    – miken32
    Commented Dec 5, 2018 at 15:57
  • 1
    I beleive this answer has many benefits, for most use cases we already know we're expecting a json string, so this is checking for the curly brackets so if they're not found, there won't be the need to json_decode. +1 from me. Commented Oct 10, 2021 at 8:41
1

I don't know about performance or elegance of my solution, but it's what I'm using:

if (preg_match('/^[\[\{]\"/', $string)) {
    $aJson = json_decode($string, true);
    if (!is_null($aJson)) {
       ... do stuff here ...
    }
}

Since all my JSON encoded strings start with {" it suffices to test for this with a RegEx. I'm not at all fluent with RegEx, so there might be a better way to do this. Also: strpos() might be quicker.

Just trying to give in my tuppence worth.

P.S. Just updated the RegEx string to /^[\[\{]\"/ to also find JSON array strings. So it now looks for either [" or {" at the beginning of the string.

1
function isJson($string) {
    $obj = json_decode($string);
    return json_last_error() === JSON_ERROR_NONE && gettype($obj ) == "object";
}

this works and doesn't return true for numbers

new update

The above solution does not have good performance if the JSON is long and you don't need to use $obj

if you just want check, it's better to use below function

function isJson($string) {
    if(is_numeric($string)) return false;
    json_decode($string);
    return json_last_error() === JSON_ERROR_NONE;
}
3
  • 1
    IMHO the best solution if you also want to actually use the decoded object, should it be json Commented Sep 23, 2021 at 16:07
  • you're right. I updated the answer Commented Sep 28, 2021 at 18:18
  • A number is valid JSON.
    – miken32
    Commented Dec 2, 2023 at 20:39
1

Update: json_validate() Will Be live in PHP 8.3

FYI:

I am working on an RFC to add a new function in php that is able to validate-only a json-string without generating and object/array in the process.

Why a validation-only function? because json_decode() creates an array/object while parsing the json-string, affecting the amount of memory being use; this means that max memory limit can be reach while validating a json-string.

To give you an idea, check this code performance_test_json_validate()_vs_json_decode():

In that test we can see that the new function json_validate() uses 0 MB to validate the json-string, while json_decode() needed 109 MB to do it (because it creates an in memory array/object while parsing.

This is Work In Progress at the moment, but I am posting this as I am interested in your opinion about it (not if you think is worth to have it or not, I mean , from technical point of view).

Github: https://github.com/php/php-src/pull/9399

RFC (Work in progress): https://wiki.php.net/rfc/json_validate

Looking forward for your opinion/support on this.

Thanks in advance.

0
0

Expanding on this answer How about the following:

<?php

    $json = '[{"user_id":13,"username":"stack"},{"user_id":14,"username":"over"}]';
    //$json = '12';

    function isJson($string) {
        json_decode($string);
        if(json_last_error() == JSON_ERROR_NONE) {
            if(substr($string,0,1) == '[' && substr($string,-1) == ']') { return TRUE; }
            else if(substr($string,0,1) == '{' && substr($string,-1) == '}') { return TRUE; }
            else { return FALSE; }
        }
    }

    echo isJson($json);
?>
2
  • 3
    Shouldn't the substring check be made before executing the decode to save time if the error is found in that check? I would imagine that 4 substring checks would be faster than a json_decode, but if someone could back me up with this assumption I'd appreciate any thoughts on this.
    – Mark
    Commented Aug 7, 2015 at 15:04
  • That's a fare argument. I don't know the processing time involved, but if it's faster then yes. Commented Aug 17, 2015 at 11:11
0

Another suggestion from me :)

function isJson(string $string) {
  return ($result = json_decode($string, true)) ? $result : $string;
}
0

This is what I recommend

if (!in_array(substr($string, 0, 1), ['{', '[']) || !in_array(substr($string, -1), ['}', ']'])) {
  return false;
} else {
  json_decode($string);
  return (json_last_error() === JSON_ERROR_NONE);
}
1
  • The following are valid JSON strings and will not pass your checks: 2352, "foo", null
    – miken32
    Commented Dec 2, 2023 at 20:57
-2

Freshly-made function for PHP 5.2 compatibility, if you need the decoded data on success:

function try_json_decode( $json, & $success = null ){
  // non-strings may cause warnings
  if( !is_string( $json )){
    $success = false;
    return $json;
  }

  $data = json_decode( $json );

  // output arg
  $success =

    // non-null data: success!
    $data !==  null  ||

    // null data from 'null' json: success!
    $json === 'null' ||

    // null data from '  null  ' json padded with whitespaces: success!
    preg_match('/^\s*null\s*$/', $json );

  // return decoded or original data
  return $success ? $data : $json;
}

Usage:

$json_or_not = ...;

$data = try_json_decode( $json_or_not, $success );

if( $success )
     process_data( $data );
else what_the_hell_is_it( $data );

Some tests:

var_dump( try_json_decode( array(), $success ), $success );
// ret = array(0){}, $success == bool(false)

var_dump( try_json_decode( 123, $success ), $success );
// ret = int(123), $success == bool(false)

var_dump( try_json_decode('      ', $success ), $success );
// ret = string(6) "      ", $success == bool(false)

var_dump( try_json_decode( null, $success ), $success );
// ret = NULL, $success == bool(false)

var_dump( try_json_decode('null', $success ), $success );
// ret = NULL, $success == bool(true)

var_dump( try_json_decode('  null  ', $success ), $success );
// ret = NULL, $success == bool(true)

var_dump( try_json_decode('  true  ', $success ), $success );
// ret = bool(true), $success == bool(true)

var_dump( try_json_decode('  "hello"  ', $success ), $success );
// ret = string(5) "hello", $success == bool(true)

var_dump( try_json_decode('  {"a":123}  ', $success ), $success );
// ret = object(stdClass)#2 (1) { ["a"]=> int(123) }, $success == bool(true)

Not the answer you're looking for? Browse other questions tagged or ask your own question.