20

好的,我正在运行一个公共 JSONP API,数据由我的 PHP 服务器提供。我刚读了这篇文章:

基本上,如果我的 JSON 字符串包含 U+2028 字符(Unicode 行分隔符)或 U+2029 字符(Unicode 段落分隔符),那么这是完全有效的 JSON。但是,当使用 JSONP 时,JSON 将作为 JavaScript 执行,并且 JavaScript 中的任何字符串都不能包含文字 U+2028 或 U+2029,因为它会破坏 JavaScript。显然,只要您使用正确的 JSON 解析器,这通常不是问题,但在 JSONP 的情况下,浏览器就是JSON 解析器。

本质上,如果这些字符在我发送到客户端的 JSONP 数据中的字符串中,这将在字符串中抛出一个行或段落中断,这会破坏 JavaScript 并停止它的执行。这是一种可能性,因为 API 正在发回一些客户端输入的数据。有人可能会在数据库中输入 U+2028 或 U+2029,因此当我将其作为 JSONP 发回时,它会破坏使用我的 API 的任何实现。

所以我的问题是,在 PHP 中,我如何清理/输出转义 JSON 数据以删除或转义 U+2028 和 U+2029 字符,然后再将其发送到客户端?

目前,我的流程正在对数据数组执行json_encode并将该数据发送到客户端。我应该通过遍历数组并对其进行过滤来转义数据,还是一次转义所有 JSON 编码的字符串?

另一件事是我不确定如何在 PHP 中转义 U+2028 和 U+2029 字符。我可以做一个 str_replace 吗?我不确定 str_replace 是否是多字节安全的,并且没有 mb_str_replace函数,除非我使用一些定制的函数。那么如何删除/转义那些 unicode 字符呢?

非常感谢。

4

2 回答 2

22

您可以在 PHP 端或 JavaScript 端,或两者都替换U+2028, U+2029,只要它至少发生一次(它是幂等的)就没有关系。"\u2028""\u2029"

您可以只使用普通的字符串替换函数。它们不需要是“多字节安全的”,您可以在任何 Unicode 编码中轻松做到这一点(UTF-8、UTF-16、UTF-32 都一样好)。上次我检查时 PHP 没有 Unicode 转义序列,这只是 PHP 是个笑话的另一个原因,但您可以使用\xUTF-8 转义...

(简而言之,没有多字节字符串替换函数的原因是因为它是多余的——它与非多字节字符串替换函数完全相同。)

// Javascript
data = data.replace("\u2028", "\\u2028").replace("\u2029", "\\u2029");

// PHP
$data = str_replace("\xe2\x80\xa8", '\\u2028', $data);
$data = str_replace("\xe2\x80\xa9", '\\u2029', $data);

或者你可以什么都不做,因为 PHP 在默认情况下会转义非 Unicode 字符json_encode()

// Safe
echo json_encode("\xe2\x80\xa9");
--> "\u2029"

// Correct JSON, but invalid Javascript...
// (Well, technically, JSON root must be array or object)
echo json_encode("\xe2\x80\xa9", JSON_UNESCAPED_UNICODE);
--> "
"
于 2013-01-06T04:57:24.553 回答
1

值得指出的是,这不再是必要的。

默认情况下,对所有json_encode()非 ASCII 字符(包括 U+2028 和 U+2029)进行编码,并转义正斜杠,即使 JSON 规范不需要转义。逃避它并没有什么害处,而且在某些情况下它可能更安全。因此,默认情况下,这些字符无论如何都会被转义。

常量输出未转义的JSON_UNESCAPED_UNICODEUnicode,可以节省字节。然而,正如斜线字符被转义,因为它在某些情况下可能是危险的,所以 U+2028 和 U+2029也被转义,因为它们在某些情况下也是危险的。在您提出问题时情况并非如此:此功能最近已添加到 PHP 中

JSON_UNESCAPED_SLASHES(这些额外的转义可以分别用和关闭JSON_UNESCAPED_LINE_TERMINATORS。)

于 2017-07-14T16:35:54.437 回答