# RFC: json_validate function

- Status: Implemented (PHP 8.3)
- Authors: Juan Carlos Morales, dev.juan.morales@gmail.com
- Date: 2022-08-14
- Version: 0.9
- Target: PHP 8.3
- Implementation: https://github.com/php/php-src/pull/9399
- Original: https://wiki.php.net/rfc/json_validate
- Page: https://externals.io/rfc/json_validate
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

## Votes

### json_validate (closed)

Yes: 18 · No: 1

Voters: ashnazg (Yes), beberlei (Yes), bmajdak (Yes), bukka (Yes), crell (Yes), cschneid (Yes), dharman (Yes), fibbarth (Yes), girgias (Yes), mfonda (Yes), ocramius (No), reywob (Yes), santiagolizardo (Yes), seld (Yes), sergey (Yes), svpernova09 (Yes), tandre (Yes), timwolla (Yes), villfa (Yes)

## Discussions on the mailing list

- [RFC json_validate() - status: Under Discussion](https://externals.io/message/118467.md) — started on 2022-08-25, 61 messages
- [\[VOTE\] json_validate](https://externals.io/message/118685.md) — started on 2022-09-22, 1 messages
- [RFC json_validate Accepted](https://externals.io/message/118784.md) — started on 2022-10-07, 1 messages

---

## Introduction

This RFC introduces a new function called json\_validate() to validate if an string contains a valid json.

Most userland implementations use json\_decode() which by design generates a ZVAL(object/array/etc.) while parsing the string, ergo using memory and processing that could be save.

The proposed function will use the exact same JSON parser that already exists in the PHP core, which is also use by json\_decode(), this garantees that what is valid in *json\_validate()* is also valid in *json\_decode()*.

## Proposal

### Description

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

### Parameters

**`json`**

The json string being analyzed.

This function only works with UTF-8 encoded strings.

Note:

PHP implements a superset of JSON as specified in the original » RFC 7159.

**`depth`**

Maximum nesting depth of the structure being decoded.

**`flags`**

Bitmask of **JSON\_INVALID\_UTF8\_IGNORE**. The behavior of this constant is described on the [JSON constants page](https://www.php.net/manual/en/json.constants.php).

### Return values

Returns **true** if the string passed contains a valid json, otherwise returns **false**.

### Examples

**1. Validate a valid json-string**

```php
var_dump(json_validate('{ "test": { "foo": "bar" } }'));
```

Result will be

```php
bool(true)
```

**2. Validate an invalid json-string**

```php
var_dump(json_validate('{ "": "": "" } }'));
```

Result will be

```php
bool(false)
```

Errors during validation can be fetch by using [json\_last\_error()](https://www.php.net/manual/es/function.json-last-error.php) and/or [json\_last\_error\_msg()](https://www.php.net/manual/es/function.json-last-error-msg.php).

## General notes from discussion of the RFC

- Different users have tested the functionality and obtained the promised results. Also their feedback about it was positive.
- Most part of the community in the mailing list showed a positive opinion about this RFC, and looks forward for its integration into PHP.
- The ones that checked the code also agree that is small implementation, easy to maintain, and at the same time provides a big benefit for such small implementation.
- The community got involve very actively in the discussion of the RFC and provided all kind of useful feedback, and also took the time to test json\_validate() by themselves.

## Use cases contributed by the community

Eventhough not reduce to only these examples, during discussion in mailing list, some users expressed:

> “Yes well-formed JSON from a trusted source tends to be small-ish. But a validation function also needs to deal with non-well-formed JSON, otherwise you would not need to validate it.”

> “If with a new function (json\_validate()) it becomes much easier to defend against a Denial-of-Service attack for some parts of a JSON API, then this can be a good addition just for security reasons.”

> “fast / efficient validation of a common communication format reduces the attack surface for Denial-of-Service attacks.”

## Reasons to have json\_validate() function in the core

Based on discussion of the RFC in the mailing list

### Disadvantages of using json\_decode to only validate a json-string

By design, json\_decode() generates a ZVAL (object/array/etc.) while parsing the string, ergo using memory and processing for it, that is not needed if the only thing to discover is if a string contains a valid json or not.

### Disadvantages of using regex

Using a regex for this task forces different, error-prone, hard to maintain, implementations.

### Disadvantages of userland solutions

- Writing a JSON parser is no trivial
- They need to be up-to-date with the existing PHP JSON parser used by **json\_decode()** already, otherwise a json-string valid in **userland solution** might not be valid json-string for **json\_decode()** or vice-versa.
- Is redundant work writing a JSON Parser in the userland, as PHP already has one.

### PHP already has a JSON parser

As previously mentioned, PHP already has a JSON parser used by json\_decode(). The proposed function will use that parser, guaranteeing 100% compatibility between **json\_decode()** and **json\_validate()**

### Needs from major projects and developers

In the “References” section, there is a list of major open-source php projects that could benefit with this new function.

Also in the mentioned section a link to one of the most popular StackOverflow questions is provided, which somehow reflects the need from our developers to have a feature like this included.

Please check the “References” section.

### Complexity added in the core

At the moment, there is a JSON parser in the core, used by *json\_decode()* to do its job, so there is no need to write a new JSON parser for this RFC; the proposed function will use the existing JSON parser exclusively to parse an string without generating any object/array/etc. in memory for it.

## Reasons NOT to have json\_validate() function in the core

One member of the mailing list expressed that:

- Incorporating such a small implementation that can be achieve with userland code is not a good idea.

Quote:

> “If we keep the tendency to pollute already bloated standard library with an army of small functions that could have not exists and be replaced with normal PHP counterparts IMHO we'll end with frustration from developers as I believe DX slowly falls down here.”

- json\_validate() would only be useful for edge cases.

Quote:

> “A &#96;json\_decode()&#96; is a substitute that IMO solves 99% of use cases. If I'd follow your logic and accept every small addition that handles 1% of use cases, somebody will raise another RFC for simplexml\_validate\_string or yaml\_validate and the next PhpToken::validate. All above can be valid if we trust that people normally validate 300MB payloads to do nothing if they DON'T fail and there is nothing strange about that.”

- The user also provided an implementation of a JSON parser written in pure PHP. <https://gist.github.com/brzuchal/37e888d9b13937891c3e05fead5042bc>

## Changes in the RFC that happened during discussion

### Throw Exception on error

In my initial implementation, the developer had the option to provide a flag to indicate that in case of error during validation an exception should be throw.

The ability to throw an exception on error was removed from the implementation, as this was pointed not only by most of user in the mailing list (with good reasons), but also during code review; as it does not make sense to have such a behavior.

I also have to admit that after they showed their arguments, I changed my mind, and now I also think it makes sense to have such a behavior in the function.

So removing the ability to throw exception on error was removed from implementation.

### Others

- I removed 3 of the originally provided examples in the RFC because did not adjust to the RFC purpose or were not clear.
- I had to adjust the wording in this RFC document regarding disadvantage of using json\_decode() as pointed here: 
    - [PR comment from user drealecs](https://github.com/php/php-src/pull/9399#discussion_r955626844)

## Backward Incompatible Changes

None, as this is a new function only.

**json\_validate** will no longer be available as a function name.

## Proposed PHP Version(s)

next PHP 8.x

## RFC Impact

This RFC has no impact on SAPIs, existing extensions, Opcache, etc.

## Future Scope

\- (To be defined by future discussions if needed)

## Proposed Voting Choices

\- (To be defined)

## Implementation

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

## References

### Major Open-Source projects that will benefit out of this

[Symfony Framework](https://github.com/symfony/symfony/blob/870eeb975feb1abb4b8a1722e1fd57beeab2b230/src/Symfony/Component/Validator/Constraints/JsonValidator.php)

```php
class JsonValidator extends ConstraintValidator
```

[Laravel Framework](https://github.com/laravel/framework/blob/302a579f00ebcb2573f481054cbeadad9c970605/src/Illuminate/Validation/Concerns/ValidatesAttributes.php)

```php
    public function validateJson($attribute, $value)
    {
        if (is_array($value)) {
            return false;
        }
 
        if (! is_scalar($value) && ! is_null($value) && ! method_exists($value, '__toString')) {
            return false;
        }
 
        json_decode($value);
 
        return json_last_error() === JSON_ERROR_NONE;
    }
```

[Laravel Framework](https://github.com/laravel/framework/blob/61eac9cae4717699ecb3941b16c3d775820d4ca2/src/Illuminate/Support/Str.php)

```php
    public static function isJson($value)
    {
```

[Magento](https://github.com/magento/magento2/blob/7c6b6365a3c099509d6f6e6c306cb1821910aab0/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php)

```php
    protected function isValidJsonValue($value)
    {
        if (in_array($value, ['null', 'false', '0', '""', '[]'])
            || (json_decode($value) !== null && json_last_error() === JSON_ERROR_NONE)
        ) {
            return true;
        }
        //JSON last error reset
        json_encode([]);
        return false;
    }
```

[Magento](https://github.com/magento/magento2/blob/7c6b6365a3c099509d6f6e6c306cb1821910aab0/lib/internal/Magento/Framework/Serialize/JsonValidator.php)

```php
    public function isValid($string)
    {
        if ($string !== false && $string !== null && $string !== '') {
            json_decode($string);
            if (json_last_error() === JSON_ERROR_NONE) {
                return true;
            }
        }
        return false;
    }
```

[getgrav](https://github.com/getgrav/grav/blob/3e7f67f589267e61f823d19824f3ee1b9a8a38ff/system/src/Grav/Common/Data/Validation.php)

```php
    public static function validateJson($value, $params)
    {
        return (bool) (@json_decode($value));
    }
```

[Respect / Validation](https://github.com/Respect/Validation/blob/3dcd859d986f1b586b5539ea19962723ab7352ed/library/Rules/Json.php)

```php
final class Json extends AbstractRule
{
    /**
     * {@inheritDoc}
     */
    public function validate($input): bool
    {
        if (!is_string($input) || $input === '') {
            return false;
        }
 
        json_decode($input);
 
        return json_last_error() === JSON_ERROR_NONE;
    }
}
```

[Respect / Validation](https://github.com/Respect/Validation/blob/3dcd859d986f1b586b5539ea19962723ab7352ed/library/Rules/Json.php)

```php
final class Json extends AbstractRule
{
    /**
     * {@inheritDoc}
     */
    public function validate($input): bool
    {
        if (!is_string($input) || $input === '') {
            return false;
        }
 
        json_decode($input);
 
        return json_last_error() === JSON_ERROR_NONE;
    }
}
```

[Prestashop](https://github.com/PrestaShop/PrestaShop/blob/24f9e510ecb0cb002ac3f4834f3210e8d9359899/classes/Validate.php)

```php
    public static function isJson($string)
    {
        json_decode($string);
 
        return json_last_error() == JSON_ERROR_NONE;
    }
```

[Wordpress CLI](https://github.com/wp-cli/wp-cli/blob/f3e4b0785aa3d3132ee73be30aedca8838a8fa06/php/utils.php)

```php
function is_json( $argument, $ignore_scalars = true ) {
    if ( ! is_string( $argument ) || '' === $argument ) {
        return false;
    }
 
    if ( $ignore_scalars && ! in_array( $argument[0], [ '{', '[' ], true ) ) {
        return false;
    }
 
    json_decode( $argument, $assoc = true );
 
    return json_last_error() === JSON_ERROR_NONE;
}
```

[JOOMLA CMS](https://github.com/joomla/joomla-cms/blob/09d14c65f25f9bc76f2698e69c4d7b35f43bc848/libraries/src/Form/Field/AccessiblemediaField.php)

```php
if (\is_string($value)) {
    json_decode($value); //<------ HERE
 
    // Check if value is a valid JSON string.
    if ($value !== '' && json_last_error() !== JSON_ERROR_NONE) {
        /**
         * If the value is not empty and is not a valid JSON string,
         * it is most likely a custom field created in Joomla 3 and
         * the value is a string that contains the file name.
        */
        if (is_file(JPATH_ROOT . '/' . $value)) {
            $value = '{"imagefile":"' . $value . '","alt_text":""}';
        } else {
            $value = '';
        }
    }
```

### Stackoverflow questions related to this

In PHP, this question is one of the most high ranked questions related to json &amp;&amp; php in stackoverflow, **“Fastest way to check if a string is JSON in PHP?”**. [The question](https://stackoverflow.com/questions/6041741/fastest-way-to-check-if-a-string-is-json-in-php)

Viewed 484k times. [The ranking](https://stackoverflow.com/questions/tagged/php%20json?sort=MostVotes&edited=true)

Person asking how to do exactly this, also providing a real use case; eventhough in python, the programming language is not important. [In Python](https://stackoverflow.com/questions/5508509/how-do-i-check-if-a-string-is-valid-json-in-python)

Someone has also doing exactly this , in JAVA. [In Java](https://stackoverflow.com/questions/3679479/check-if-file-is-json-java)

## Vote

Voting started 2022-09-22 and will end on 2022-10-07 at 00:00:00 UTC time zone.

**Vote: json\_validate** — Yes: 18 · No: 1 (closed)
