PHP json_decode 不适用于由 Node 12 格式良好的 JSON.stringify 引起的单个未配对代理项

标签 php node.js utf-8 surrogate-pairs

Node 12 现在使用 Well-formed JSON.stringify它为单独的代理人输出转义序列。当有一个单独的代理被转义时,PHP 无法对此进行 json_decode。

以 Node.js 中的以下代码示例为例。

var a = '𝘥𝘦𝘴𝘪𝘨𝘯𝘦𝘳 𝘢𝘯𝘥 𝘪𝘭𝘭𝘶𝘴𝘵𝘳𝘢𝘵𝘰𝘳';
JSON.stringify(a.slice(0, 15));

// Node 10 output: 
'"𝘥𝘦𝘴𝘪𝘨𝘯𝘦�"';

// Node 12 output:
'"𝘥𝘦𝘴𝘪𝘨𝘯𝘦\\ud835"'

然后将此响应作为 JSON 发送到 PHP 服务器并进行解码。这是错误发生的地方。 Node10 的输出过去可以与 PHP json_decode 一起正常工作,但它不再与 Node12 的输出一起工作。

我简化了 NODE->PHP 示例,如下所示。

<?php
$string = '{"string": "𝘥𝘦𝘴𝘪𝘨𝘯𝘦\\ud835"}';
var_dump(json_decode($string, false, 512, JSON_THROW_ON_ERROR | JSON_INVALID_UTF8_IGNORE | JSON_INVALID_UTF8_SUBSTITUTE));

// Output:
Fatal error: Uncaught JsonException: Single unpaired UTF-16 surrogate in unicode escape in phptest.php:36
Stack trace:
#0 phptest.php(36): json_decode('{"string": "\xF0\x9D\x98...', false, 512, 7340032)
#1 {main}
  thrown in phptest.php on line 36

我希望以下选项 JSON_INVALID_UTF8_IGNOREJSON_INVALID_UTF8_SUBSTITUTE 与 PHP 7.3+ 中的 json_decode 一起使用,但它根本没有帮助。 JSON_THROW_ON_ERROR 实际上会抛出错误以使其更易于调试。

最佳答案

问题出在 Javascript 中。

您在 a 中的字符串包含多字节字符。使用 a.slice(0, 15) 你得到 15 个字节,而不是 15 个字符,并创建一个无效的 utf-8 字符串。多字节字符可能不会被肢解。

更新:

我认为选项 JSON_INVALID_UTF8_IGNORE 和 JSON_INVALID_UTF8_SUBSTITUTE 用于 json_encode () 而不是为 json_decode () 清除无效的 JSON。 干净的解决方案是在 Javascript 页面上提供有效的 JSON。

肮脏的解决方案是尝试使用 PHP 更正无效的 JSON:

$json = preg_replace_callback(
  '~\\\u[a-d0-9]{4}~iu',
  function($found){
    if(json_decode('"'.$found[0].'"')){
      return $found[0];
    }
    return "";  //or "?"
  },
  $invalidJson
);

关于PHP json_decode 不适用于由 Node 12 格式良好的 JSON.stringify 引起的单个未配对代理项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58674104/

相关文章:

node.js - 在 Windows 上更改 Node JS 命令提示符的字体大小

mysql - Delphi 5,如何从 MySQL 的 tis620 字段中检索数据?

java - 我可以在 String 变量中存储特殊符号吗?

php - 如何使用 JavaScript 访问 PDF 中的图像?

php - 哪一个在资源方面成本更低?

php - 外部登录网络邮件

node.js - 停止服务器后连接socket.io增加

node.js - 快速回复 Node 编码 - 使用示例messenger.js

java - 字符串类内部 - 如果使用 UTF-8,缓存字符偏移到字节关系

php - 如何从数据库循环中获取值并将它们相加以备后用