逃避逃脱角色

时间:2010-05-20 03:41:37

标签: php escaping json str-replace

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

$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"

我无法理解为什么我需要用{{1替换单引号('\\\''甚至"\\'" [周围的引号排除])而不只是'\\\u0027'


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

'\\u0027'

6 个答案:

答案 0 :(得分:13)

PHP字符串

'O\'Rei"lly'

只是PHP获取文字值的方式

O'Rei"lly

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

O\'Rei\"lly

即。 strlen(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"

我们希望将'更改为\u0027 我们希望将\"更改为\u0022,因为\中的\"只是为了将"放入字符串中,因为它以double开头和结尾-quotes。

这就是为什么我们得到

"O\\\u0027Rei\\\u0022lly"

答案 1 :(得分:2)

它正在逃避反斜杠以及引用。正如你在这里做的那样很难处理逃脱的逃跑,因为它很快变成了反斜杠计算游戏。 : - /

答案 2 :(得分:2)

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

'\\\u0027'而不只是'\\u0027'

你正在逃避斜线和字符unicode值。有了这个,你告诉json它应该在那里放一个撇号,但它需要反斜杠和你知道下一个unicode十六进制字符代码。

因为您要转义此字符串:

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

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

如果你把这个algorythm给了O'Reilly而不是O \'Rei \ lly,那么后者就足够了。

我希望你觉得这很有用。我只给你这个链接,这样你就可以阅读更多关于如何构造json的内容,因为很明显你已经了解了PHP:

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

答案 3 :(得分: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;
}

答案 4 :(得分:1)

由于您要json_encode字符串\',您必须首先编码\然后编码'。因此,您将拥有\\\u0027。连接这些结果\\\u0027

答案 5 :(得分:0)

\生成的addslashes()json_encode()重新转发。您可能想说Doing json_encode($s, JSON_HEX_APOS | JSON_HEX_QUOT) outputs the following,但您使用的是$str而不是$s,这让所有人感到困惑。

如果您在JavaScript中评估字符串"O\\\u0027Rei\\\u0022lly",您将获得"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>