我正在尝试模仿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'
答案 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:
答案 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>