JSON7 min readExamples run on PHP 8.5.10

json_validate()

Learn how PHP 8.4 json_validate() checks whether a string is syntactically valid JSON, how depth and flags work, and when to use json_decode() instead.

Signature

json_validate(string $json, int $depth = 512, int $flags = 0): bool
Available since PHP 8.3.07.48.08.18.28.38.48.5All versions →

Purpose

json_validate() answers one question: is this string syntactically valid JSON? It returns a boolean and never builds the array or object that the text describes. That makes it useful when you only need a yes or no, such as screening a stored payload, checking a field before saving it, or rejecting malformed input early. Because no decoded structure is created, it needs less memory than json_decode() when you would throw the result away.

The manual lists the function as available from PHP 8.3, so it is present in PHP 8.4.

Signature

Parameters and defaults

  • $json: the string to check. It must be UTF-8 encoded.
  • $depth: the maximum nesting depth. The default is 512. The value must be greater than 0 and no larger than 2147483647.
  • $flags: defaults to 0. The only flag accepted at present is JSON_INVALID_UTF8_IGNORE.

Return value and failure cases

The function returns true when the text is valid JSON and false otherwise. A false result is not an exception. To find out why validation failed, call json_last_error() or json_last_error_msg() straight afterwards.

A ValueError is thrown, instead of returning false, when the arguments themselves are unacceptable: a $depth outside the allowed range, or a $flags value that is not a valid flag. Treat these as programming errors, not as bad user input.

If json_validate() returns true, json_decode() will decode the same string successfully, provided you pass the same depth and flags.

Example 1: valid and invalid text

Any JSON value is valid at the top level, not only objects and arrays. Scalars such as numbers, strings and null pass. Trailing commas, single-quoted strings and empty input do not.

Example
<?php
$inputs = [
    '{"name":"Ada","tags":["php","json"]}',
    '[1, 2, 3]',
    '"text"',
    '42',
    'null',
    '{"name":"Ada",}',
    "{'name':'Ada'}",
    '',
];
$results = [];
foreach ($inputs as $input) {
    $results[] = json_validate($input);
}
echo json_encode($results), "\n";
Output
[true,true,true,true,true,false,false,false]

Example 2: limiting depth

The depth limit applies to the parser stack, so do not assume that counting visible brackets gives a sufficient limit. In PHP 8.4, [1] needs a limit of at least 2, [[1]] needs at least 3, and the three-level object below needs at least 4. A well-formed document still returns false when the limit is too small.

Example
<?php
echo json_encode([
    json_validate('[1]', 2),
    json_validate('[[1]]', 2),
    json_validate('[[1]]', 3),
    json_validate('{"a":{"b":{"c":1}}}', 4),
    json_validate('{"a":{"b":{"c":1}}}', 3),
]), "\n";
Output
[true,false,true,true,false]

A small depth is a handy guard when the input comes from outside your program, because it caps how complex a payload you are willing to accept.

Example 3: reading the error message and using the flag

After a call, json_last_error_msg() describes the outcome. The helper below packages the result and message together. The last two lines show a string containing the invalid UTF-8 byte \xFF: it fails normally, but passes when JSON_INVALID_UTF8_IGNORE is given.

Example
<?php
function check(string $json, int $flags = 0): string {
    $valid = json_validate($json, 512, $flags);
    return json_encode(['valid' => $valid, 'message' => json_last_error_msg()]);
}
echo check('{"a":1}'), "\n";
echo check('{"a":1'), "\n";
$bad = "\"a\xFF\"";
echo check($bad), "\n";
echo check($bad, JSON_INVALID_UTF8_IGNORE), "\n";
Output
{"valid":true,"message":"No error"}
{"valid":false,"message":"Syntax error"}
{"valid":false,"message":"Malformed UTF-8 characters, possibly incorrectly encoded"}
{"valid":true,"message":"No error"}

Edge cases

  • Syntax only: the function does not know your data model. {"age":"not a number"} is valid JSON even if your application expects an integer. Check the structure separately.
  • Empty or whitespace-only strings are not valid JSON, so they return false.
  • The error state belongs to the most recent call. Read it immediately, before calling another JSON function.
  • The manual notes that PHP implements a superset of the original RFC 7159 specification, so rely on the function's result rather than on your own assumptions about the grammar.
  • Only JSON_INVALID_UTF8_IGNORE is accepted for $flags. Flags that help json_decode(), such as JSON_THROW_ON_ERROR, are not valid here and cause a ValueError.

Common mistakes

  1. Validating and then decoding. Calling json_validate() right before json_decode() makes PHP parse the text twice, because decoding already validates. If you need the data, decode once and check for failure. Use json_validate() when you do not need the decoded value right away.
  2. Treating false as an exception. Bad JSON just gives false. Only invalid arguments raise ValueError.
  3. Passing 0 or a negative depth. The depth has to be at least 1.
  4. Forgetting the encoding. Input must be UTF-8. Text in another encoding may fail with a malformed UTF-8 error.
  5. Reading the error too late. Another JSON call in between can overwrite the message you wanted.
  6. Assuming validity means safety. A valid document can still be huge or hold unexpected values. Combine the depth limit with your own size and content checks.
  • json_decode() turns a JSON string into PHP data.
  • json_last_error() returns the numeric code of the last JSON error.
  • json_last_error_msg() returns a readable message for the last json_validate(), json_encode() or json_decode() call.

Recap

json_validate() checks syntax and returns a boolean without creating decoded data. Set $depth to limit nesting, use JSON_INVALID_UTF8_IGNORE only when you deliberately tolerate bad UTF-8, and read json_last_error_msg() for the reason behind a false. When you need the decoded value, call json_decode() once instead of validating first.

Tested examples

Valid and invalid JSON strings
<?php
$inputs = [
    '{"name":"Ada","tags":["php","json"]}',
    '[1, 2, 3]',
    '"text"',
    '42',
    'null',
    '{"name":"Ada",}',
    "{'name':'Ada'}",
    '',
];
$results = [];
foreach ($inputs as $input) {
    $results[] = json_validate($input);
}
echo json_encode($results), "\n";
Output
[true,true,true,true,true,false,false,false]
Limiting nesting depth
<?php
echo json_encode([
    json_validate('[1]', 2),
    json_validate('[[1]]', 2),
    json_validate('[[1]]', 3),
    json_validate('{"a":{"b":{"c":1}}}', 4),
    json_validate('{"a":{"b":{"c":1}}}', 3),
]), "\n";
Output
[true,false,true,true,false]
Error messages and the invalid UTF-8 flag
<?php
function check(string $json, int $flags = 0): string {
    $valid = json_validate($json, 512, $flags);
    return json_encode(['valid' => $valid, 'message' => json_last_error_msg()]);
}
echo check('{"a":1}'), "\n";
echo check('{"a":1'), "\n";
$bad = "\"a\xFF\"";
echo check($bad), "\n";
echo check($bad, JSON_INVALID_UTF8_IGNORE), "\n";
Output
{"valid":true,"message":"No error"}
{"valid":false,"message":"Syntax error"}
{"valid":false,"message":"Malformed UTF-8 characters, possibly incorrectly encoded"}
{"valid":true,"message":"No error"}