[PHP8.3] 能够判断JSON是否正确

PHP8.2 尚未发布,但将在 PHP8.3 中引入的一项功能已经提前确定。

所以下面是相关的RFC,PHP RFC:json_validate这是一个介绍。

PHP RFC:json_validate

介绍

这个 RFC 引入了一个函数 json_validate(),它验证一个字符串是一个有效的 JSON 字符串。

同一个函数的大部分用户态实现都使用json_decode(),它在解析字符串时会生成ZVAL,如果只是为了验证会浪费不必要的处理和浪费内存。

json_validate() 使用 PHP 核心中存在的 JSON 解析器。

这与json_decode() 使用的相同,因此json_validate() 有效的任何字符串都保证为json_decode()

提议

描述

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

参数

$json

目标 JSON 字符串。

只有 UTF-8 对字符代码有效。

$深度

最大嵌套深度。

$标志

目前JSON_INVALID_UTF8_IGNORE已验证。

返回值

如果传递的字符串作为 JSON 有效,则返回 true,否则返回 false。

例子

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

结果将是真实的。

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

将是错误的。

原因是json_last_error()或者json_last_error_msg()可以在

RFC 讨论的一般说明

从 RFC 讨论中吸取的教训。

・许多用户已经测试过此功能并能够得到预期的结果。

• 社区中的大多数人都对该RFC 持积极态度。

・代码审阅者表示,代码体积小,易于维护,好处多多。

- 在 RFC 讨论期间,我们从社区收到了很多有用的反馈。

社区贡献的用例

社区提交的用例。

除了这个例子,很多用户也提供了反馈。

• 来自可信来源的 JSON 格式正确且不是很大。但是您的验证函数还需要能够处理未格式化的 JSON。

- 这不是一个很好的补充,因为它可以防止一些针对 JSON 的 DoS 攻击?

在核心中有 json_validate() 函数的原因

为什么这个函数应该在 PHP 核心中。

使用 json_decode 仅验证 json-string 的缺点

json_decode 在解析时会创建一个 ZVAL 结构,因此对内存和处理速度不友好。

使用正则表达式的缺点

使用正则表达式使维护变得困难。

用户态解决方案的缺点

在用户空间中编写 JSON 解析器并不容易。

此外,用户空间实现和 json_decode 结果可能不同。

首先,PHP 已经有一个 JSON 解析器,所以在用户空间中实现它是一件麻烦事。

PHP 已经有一个 JSON 解析器

由于 PHP 从一开始就有 JSON 解析器,所以它是安全的,因为它与 json_decode 100% 兼容。

主要项目和开发商的需求

来自主要项目和开发商的要求。

以下是可以从该功能中受益的主要项目列表。

另外,这里有一个指向需要此功能的 StackOverflow 的链接。

核心中增加了复杂性

目前 PHP 核心中存在 JSON 解析器,json_decode() 只是在使用它。

因此,没有必要为此 RFC 引入新的 JSON 解析器。

新函数将只使用现有的 JSON 解析器来解析字符串,而无需创建对象或类似的东西。

讨论期间发生的 RFC 更改

部分因 RFC 讨论而改变。

出错时抛出异常

在最初的实现中,有一个标志指定如果在验证期间发生错误是否抛出异常。

由于代码审查无法理解此类行为,因此已从实现中删除了在错误时引发异常的能力。

其他

RFC 中描述的三个示例被删除,因为它们不符合 RFC 的意图或毫无意义。

使用json_decode()的缺点改变了措辞.

向后不兼容的更改

没有向后不兼容的更改。

函数名称json_validate() 不能在用户空间中使用。

建议的 PHP 版本

PHP8.3

RFC 影响

此 RFC 不影响 SAPI、现有扩展、OPCache 等。

执行

参考

将从中受益的主要开源项目

主要 OSS 项目可获得的好处。

Symfony

class JsonValidator extends ConstraintValidator

拉拉维尔

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

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

获取格拉夫

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

尊重/确认

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

与此相关的 Stackoverflow 问题

在 PHP 中检查字符串是否为 JSON 的最快方法?

Python中的一个类似问题:如何在 Python 中检查字符串是否是有效的 JSON?

Java中的类似问题:检查文件是否为 json、java

投票

以 2/3 的赞成票通过。

投票期为 22/09/2022 至 07/10/2022。

该 RFC 获得了 18 票赞成和 1 票反对的多数票。

想法

该 RFC 最初是无论如何,如果它的格式正确,json_decode它,那为什么不从头开始json_decode呢?有一些人是这样的,但由于提议者的不断说服和提供各种用例,它被成功采用。

我不确切知道它会快多少或节省多少内存,但通过将处理从 PHP 更改为 native 可能会大大改善。

失败时获取错误内容json_last_error我必须使用JSON_THROW_ON_ERROR我不太明白为什么它不支持 .

原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308630483.html