为什么JSON_UNESCAPED_LINE_TERMINATORS不能取消换行?

bxjv4tth  于 2023-03-24  发布在  其他
关注(0)|答案(2)|浏览(136)

基于documentation,我希望JSON_UNESCAPED_LINE_TERMINATORS在编码JSON时保留未转义的换行符(\n),以便作为实际的换行符:
JSON_UNESCAPED_LINE_TERMINATORS(整数)
当提供JSON_UNESCAPED_UNICODE时,行终止符保持未转义。它使用与PHP 7.1之前相同的行为,但没有此常量。从PHP 7.1.0开始可用。
最小示例:

$ php -r 'echo json_encode(["foo" => "bar\nbaz"], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS) . "\n";'
{"foo":"bar\nbaz"}

我期望:

{"foo":"bar
baz"}

(Note这是一个有效的JSON;只有\" * 必须 * 在字符串中转义。)
为什么这个选项不像预期的那样工作?

5lhxktic

5lhxktic1#

[编辑]我错误地阅读了JSON规范:字符串中未编码的换行符 * 不是 * 有效的JSON。从U+0000到U+001 F * 的控制字符 * 必须 * 被转义。PHP不包含未编码的换行符是正确的,尽管文档显然可以改进!

我必须去源代码才能找到答案。在这种情况下,“行终止符”仅指晦涩的Unicode代码点U+2028 LINE SEPARATOR和U+2029 PARAGRAPH SEPARATOR:

/* Escape U+2028/U+2029 line terminators, UNLESS both
                   JSON_UNESCAPED_UNICODE and
                   JSON_UNESCAPED_LINE_TERMINATORS were provided */
                } else if ((options & PHP_JSON_UNESCAPED_UNICODE)
                    && ((options & PHP_JSON_UNESCAPED_LINE_TERMINATORS)
                        || us < 0x2028 || us > 0x2029)) {

这与Unicode定义的行结束符相冲突:
Unicode标准定义了许多字符,符合标准的应用程序应将其识别为行终止符:

LF:    Line Feed, U+000A
VT:    Vertical Tab, U+000B
FF:    Form Feed, U+000C
CR:    Carriage Return, U+000D
CR+LF: CR (U+000D) followed by LF (U+000A)
NEL:   Next Line, U+0085
LS:    Line Separator, U+2028
PS:    Paragraph Separator, U+2029
6g8kf2rb

6g8kf2rb2#

这是一些冲突规范的结果。

  • JavaScript不允许字符串中出现未转义的行结束符。
  • JSON应该是JavaScript的一个子集。
    • 因此,* JSON也不允许字符串中有行结尾。

然而,JSON和javascript对什么构成“行结束”有不同的定义,JSON更宽松。JSON允许U+2028和U+2029,但javascript没有。(我在这里说的是过去式,因为ES 5更新了javascript的规范,允许它们。)
与此同时,PHP会尽力保证您的安全。例如,默认情况下,它会转义/,即使它不需要按照规范进行转义,以防您在HTML中嵌入JSON,并可能在JSON中包含文本</script>,这会破坏HTML。因此,默认情况下,PHP会使其成为<\/script>。您可以使用JSON_UNESCAPED_SLASHES关闭此功能,但实际上并不需要这样做,除非你真的想减少有效负载中的字节数。任何JSON解析器都会将/\/视为相同。
默认情况下,PHP也会转义所有非ASCII字符。有更多的理由关闭它,让你的JSON更容易阅读,也可以保存更多的字节,你可以用JSON_UNESCAPED_UNICODE来做到这一点。但是,现在,你有可能在你的数据中出现那些讨厌的行结尾,这可能会破坏一些解析器。(具体来说,他们会破坏javascript eval() pre-ES 5,您可能不应该使用它来解析JSON,但有些人会这样做。使用与转义正斜杠相同的逻辑,尽管这在技术上是不必要的。所以这两个字符默认编码。几乎不需要关闭它 *,但是如果您确实想关闭,JSON_UNESCAPED_LINE_TERMINATORS为您提供了选项。
如果你没有使用JSON_UNESCAPED_UNICODE,所有非ASCII字符都会被转义,所以JSON_UNESCAPED_LINE_TERMINATORS没有任何作用。

  • 这些字符是罕见的字符,所以它们可能不在你的字符串中。如果它们存在,它们只会出现一次或两次,所以转义它们不会导致大量的膨胀。

注意:与JSON_UNESCAPED_SLASHES的比较不是我自己的:它是在the Github discussion proposing this change in PHP中提出的。

相关问题