rfc:is_json

PHP RFC: is_json

Preliminary note

If the name of the function needs to be change, I will change it; the functionality is the important thing here

Introduction

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

Most userland implementations to achieve this are done using json_decode() which by design generates an object/array while parsing the string, ergo using memory and processing, that could be save.

Proposal

Description

is_json(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, JSON_THROW_ON_ERROR. The behavior of these constants is described on the JSON constants page.

Function description, examples, technical strategy, current JSON parser, etc.

Return values

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

Extra behavior

-

Examples

-

Fundaments/Reasons

Disadvantages of using json_decode

By design, json_decode() generates an object/array 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.

Disadvantages of using regex

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

Needs from major projects and developers

In the “References” section, there is a list of major open-source php projects needing this feature; also in th mntioned section can find a link to one of the most popular StackOverflow questions, which somehow reflects the need from our developers to have a feature like this included.

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 in memory for it.

Backward Incompatible Changes

None, as this is a new function only.

is_json will no longer be available as a function name, could break potential userland implementations.

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)

Proposed Voting Choices

- (To be defined)

Implementation

- (To be done later after pushing to github)

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

    private function getJSONString($input)
    {
        $output = json_decode($input);
        return $output ? $this->_jsonEncoder->encode($output) : '{}';
    }

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));
    }

Symfony htp-kernel

    public function getPrettyJson()
    {
        $decoded = json_decode($this->getContent()); //<------ here 
 
        return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null;
    }

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

humhub

    public function actionIndex()
    {
        Yii::$app->response->statusCode = 204;
 
        if(!SecuritySettings::isReportingEnabled()) {
            return;
        }
 
        $json_data = file_get_contents('php://input');
        if ($json_data = json_decode($json_data)) { //<----- json_decode() just to check if is valid json-string only
            $json_data = json_encode($json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
            $json_data = preg_replace('/\'nonce-[^\']*\'/', "'nonce-xxxxxxxxxxxxxxxxxxxxxxxx'", $json_data);
            Yii::error($json_data, 'web.security');
        }
    }

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

Rejected Features

- No rejected features currently.

rfc/is_json.txt · Last modified: 2022/08/17 14:04 by juan_morales