9

我正在尝试模仿json_encodePHP 5.3.0 中实现的位掩码标志,这是我拥有的字符串:

$s = addslashes('O\'Rei"lly'); // O\'Rei\"lly

执行json_encode($s, JSON_HEX_APOS | JSON_HEX_QUOT)输出以下内容:

"O\\\u0027Rei\\\u0022lly"

我目前正在使用 5.3.0 之前的 PHP 版本:

str_replace(array('\\"', "\\'"), array('\\u0022', '\\\u0027'), json_encode($s))
or
str_replace(array('\\"', '\\\''), array('\\u0022', '\\\u0027'), json_encode($s))

正确输出相同的结果:

"O\\\u0027Rei\\\u0022lly"

我无法理解为什么我需要将单引号('\\\''甚至"\\'"[排除周围引号])替换'\\\u0027''\\u0027'.


这是我在移植到 PHP < 5.3 时遇到问题的代码:

if (get_magic_quotes_gpc() && version_compare(PHP_VERSION, '6.0.0', '<'))
{
    /* JSON_HEX_APOS and JSON_HEX_QUOT are availiable */
    if (version_compare(PHP_VERSION, '5.3.0', '>=') === true)
    {
        $_GET = json_encode($_GET, JSON_HEX_APOS | JSON_HEX_QUOT);
        $_POST = json_encode($_POST, JSON_HEX_APOS | JSON_HEX_QUOT);
        $_COOKIE = json_encode($_COOKIE, JSON_HEX_APOS | JSON_HEX_QUOT);
        $_REQUEST = json_encode($_REQUEST, JSON_HEX_APOS | JSON_HEX_QUOT);
    }

    /* mimic the behaviour of JSON_HEX_APOS and JSON_HEX_QUOT */
    else if (extension_loaded('json') === true)
    {
        $_GET = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_GET));
        $_POST = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_POST));
        $_COOKIE = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_COOKIE));
        $_REQUEST = str_replace(array(), array('\\u0022', '\\u0027'), json_encode($_REQUEST));
    }

    $_GET = json_decode(stripslashes($_GET));
    $_POST = json_decode(stripslashes($_POST));
    $_COOKIE = json_decode(stripslashes($_COOKIE));
    $_REQUEST = json_decode(stripslashes($_REQUEST));
}
4

6 回答 6

14

PHP 字符串

'O\'Rei"lly'

只是 PHP 获取文字值的方式

O'Rei"lly

成一个可以使用的字符串。调用addslashes该字符串会将其更改为以下 11 个字符

O\'Rei\"lly

IEstrlen(addslashes('O\'Rei"lly')) == 11

这是发送到的值json_escape

JSON中的反斜杠是转义字符,所以需要转义,即

\ 成为\\

单引号和双引号也会导致问题。因此,以一种方式将它们转换为等效的 unicode 以避免出现问题。所以后来 PHP 的 json_encode 版本发生了变化

' 成为 \u0027

" 成为 \u0022

所以将这三个规则应用于

O\'Rei\"lly

给我们

O\\\u0027Rei\\\u0022lly

然后将该字符串用双引号括起来,使其成为 JSON 字符串。您的替换表达式包括前导正斜杠。无论是偶然还是故意,这意味着返回的前导和尾随双引号json_encode不受转义的影响,这是不应该的。

所以在早期版本的 PHP

$s = addslashes('O\'Rei"lly');
print json_encode($s);

会打印

"O\\'Rei\\\"lly"

并且我们想要更改'为 be\u0027 并且我们想要更改\"为 be\u0022因为\in\"只是为了将 the"放入字符串中,因为它以双引号开头和结尾。

所以这就是为什么我们得到

"O\\\u0027Rei\\\u0022lly"
于 2010-05-26T22:51:07.147 回答
2

如果我理解正确,您只想知道为什么需要使用

'\\\u0027'而不仅仅是'\\u0027'

您正在转义斜杠和字符 unicode 值。有了这个,你告诉 json 它应该在那里放一个撇号,但它需要反斜杠和 u 才能知道接下来是一个 unicode 十六进制字符代码。

由于您要转义此字符串:

$s = addslashes('O\'Rei"lly'); // O\'Rei\"lly

第一个反斜杠实际上是在撇号之前转义反斜杠。然后下一个斜杠用于转义 json 用来将字符标识为 unicode 字符的反斜杠。

如果您将算法应用于 O'Reilly 而不是 O'Rei\"lly,那么后者就足够了。

希望这个对你有帮助。我只给你留下这个链接,这样你就可以阅读更多关于 json 是如何构造的,因为很明显你已经了解了 PHP:

http://www.json.org/fatfree.html

于 2010-05-26T21:08:45.667 回答
2

它正在转义反斜杠和引号。正如您在这里所做的那样,处理逃逸的转义很困难,因为它很快就会变成反斜杠计数游戏。:-/

于 2010-05-20T04:01:19.050 回答
2

当您为 json 编码字符串时,无论选项如何,都必须转义某些内容。正如其他人指出的那样,这包括 '\' 因此通过 json_encode 运行的任何反斜杠都将加倍。由于您首先通过addslashes 运行字符串,这也会在引号中添加反斜杠,因此您添加了很多额外的反斜杠。以下函数将模拟 json_encode 如何对字符串进行编码。如果字符串已经添加了反斜杠,它们将被加倍。

function json_encode_string( $encode , $options ) {
    $escape = '\\\0..\37';
    $needle = array();
    $replace = array();

    if ( $options & JSON_HEX_APOS ) {
        $needle[] = "'";
        $replace[] = '\u0027';
    } else {
        $escape .= "'";
    }

    if ( $options & JSON_HEX_QUOT ) {
        $needle[] = '"';
        $replace[] = '\u0022';
    } else {
        $escape .= '"';
    }

    if ( $options & JSON_HEX_AMP ) {
        $needle[] = '&';
        $replace[] = '\u0026';
    }

    if ( $options & JSON_HEX_TAG ) {
        $needle[] = '<';
        $needle[] = '>';
        $replace[] = '\u003C';
        $replace[] = '\u003E';
    }

    $encode = addcslashes( $encode , $escape );
    $encode = str_replace( $needle , $replace , $encode );

    return $encode;
}
于 2010-05-27T18:11:06.570 回答
1

由于您要访问json_encode字符串,因此\'您必须先编码,\然后再编码'. 所以你会有\\\u0027。连接这些结果\\\u0027

于 2010-05-20T06:45:22.933 回答
0

\生成的由重新addslashes()转义json_encode()。你可能是想说这个Doing json_encode($s, JSON_HEX_APOS | JSON_HEX_QUOT) outputs the following,但你用$str了代替$s,这让每个人都感到困惑。

如果你"O\\\u0027Rei\\\u0022lly"在 JavaScript 中评估字符串,你会得到"O\'rei\"lly",我很确定这不是你想要的。当您评估它时,您可能需要删除所有控制代码。来吧,把它放在一个文件中:alert("O\\\u0027Rei\\\u0022lly").

结论:您两次转义引号,这很可能不是您需要的。json_encode已经转义了所有需要的东西,以便任何 JavaScript 解析器都可以返回原始数据结构。在您的情况下,这是您在调用addslashes.


证明:

<?php $out = json_encode(array(10, "h'ello", addslashes("h'ello re-escaped"))); ?>
<script type="text/javascript">
  var out = <?php echo $out; ?>;
  alert(out[0]);
  alert(out[1]);
  alert(out[2]);
</script>
于 2010-05-23T18:19:23.067 回答