rfc:json_validate

This is an old revision of the document!


PHP RFC: json_validate

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.

Proposal

Description

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.

Return values

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

Examples

1. Validate a valid json-string

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

Result will be

bool(true)

2. Validate an invalid json-string

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

Result will be

bool(false)

Errors during validation can be fetch by using json_last_error() and/or json_last_error_msg().

Reasons to have json_validate() function in the core

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 json_validate() might not be valid json-string for json_decode() or vice-versa.
  • We already have a JSON parser in PHP, that is used by json_decode(); reusing the existing JSON Parser provides 100% compatibility between the validation of a json-string, and json_decode().

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:

  1. 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.”

  1. json_validate() would only be useful for edge cases.

Quote:

“A `json_decode()` 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.”

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

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.

Open Issues

- No open issues

Future Scope

- (To be defined by future discussions if needed)

Proposed Voting Choices

- (To be defined)

Implementation

References

Major Open-Source projects that will benefit out of this

Symfony Framework

class JsonValidator extends ConstraintValidator

Laravel Framework

    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

    public static function isJson($value)
    {

Magento

    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

    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

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

Respect / Validation

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

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

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

Wordpress CLI

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

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 = '';
        }
    }

In PHP, this question is one of the most high ranked questions related to json && php in stackoverflow, “Fastest way to check if a string is JSON in PHP?”. The question

Viewed 484k times. The ranking

Person asking how to do exactly this, also providing a real use case; eventhough in python, the programming language is not important. In Python

Someone has also doing exactly this , in JAVA. In Java

Open questions

Should we remove the capability of json_validate() to use the flag JSON_THROW_ON_ERROR? During the discussion in the inernals mailing list the user Rowan Tommins rowan.collins@gmail.com raised this concern.

rfc/json_validate.1661612588.txt.gz · Last modified: 2022/08/27 15:03 by juan_morales