PHP的json_encode函数是否有任何原因无法转义字符串中的所有JSON控制字符?
例如,让我们取一个字符串,该字符串跨越两行并且在其中包含控制字符(\ r \ n“/ \”):
<?php
$s = <<<END
First row.
Second row w/ "double quotes" and backslash: \.
END;
$s = json_encode($s);
echo $s;
// Will output: "First row.\r\nSecond row w\/ \"double quotes\" and backslash: \\."
?>
请注意,回车符和换行符未转义。为什么呢?
我正在使用jQuery作为我的JS库,并且它的$ .getJSON()函数在你完全完成时会很好,100%信任传入的数据。否则我像其他人一样使用JSON.org的库json2.js。 但是,如果您尝试解析该编码的字符串,则会引发错误:
<script type="text/javascript">
JSON.parse(<?php echo $s ?>); // Will throw SyntaxError
</script>
你无法获得数据!如果删除或转义该字符串中的\ r \ n“和\”,则JSON.parse()不会抛出错误。
是否存在用于转义控制字符的现有良好PHP函数。带有搜索和替换数组的简单str_replace不起作用。
答案 0 :(得分:28)
function escapeJsonString($value) {
# list from www.json.org: (\b backspace, \f formfeed)
$escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c");
$replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b");
$result = str_replace($escapers, $replacements, $value);
return $result;
}
我正在使用上面的函数来逃避反斜杠(必须是数组中的第一个)并且应该处理formfeeds和backspaces(我认为PHP中不支持\f
和\b
)。
答案 1 :(得分:12)
D'oh - 你需要进行双重编码:JSON.parse期待一个字符串:
<script type="text/javascript">
JSON.parse(<?php echo json_encode($s) ?>);
</script>
答案 2 :(得分:4)
如果没有str_replace
..
试试这段代码。
$json_encoded_string = json_encode(...);
$json_encoded_string = str_replace("\r", '\r', $json_encoded_string);
$json_encoded_string = str_replace("\n", '\n', $json_encoded_string);
希望有帮助...
答案 3 :(得分:3)
$search = array("\n", "\r", "\u", "\t", "\f", "\b", "/", '"');
$replace = array("\\n", "\\r", "\\u", "\\t", "\\f", "\\b", "\/", "\"");
$encoded_string = str_replace($search, $replace, $json);
这是正确的方法
答案 4 :(得分:2)
从PHP转换来回应该不是问题。 PHP的json_encode执行正确的编码,但重新解释java脚本内部可能会导致问题。喜欢
1)原始字符串 - [带有 nnn 换行符的字符串](其中nnn是实际的换行符)
2)json_encode将此转换为 [带有“\\ n”换行符的字符串](控制字符转换为“\\ n” - 文字“\ n”
3)然而,当你使用php echo在文字字符串中再次打印时,“\\ n”被解释为“\ n”,这会引起心痛。因为JSON.parse会将字面值打印为“\ n”作为换行符 - 控制字符(nnn)
所以要解决这个问题: -
A) 首先使用json_enocde在php中编码json对象并获取一个字符串。然后通过一个过滤器运行它,这样就可以安全地在html和java脚本中使用。
B) 使用来自PHP的JSON字符串作为“文字”并将其放在单引号内而不是双引号中。
<?php
function form_safe_json($json) {
$json = empty($json) ? '[]' : $json ;
$search = array('\\',"\n","\r","\f","\t","\b","'") ;
$replace = array('\\\\',"\\n", "\\r","\\f","\\t","\\b", "'");
$json = str_replace($search,$replace,$json);
return $json;
}
$title = "Tiger's /new \\found \/freedom " ;
$description = <<<END
Tiger was caged
in a Zoo
And now he is in jungle
with freedom
END;
$book = new \stdClass ;
$book->title = $title ;
$book->description = $description ;
$strBook = json_encode($book);
$strBook = form_safe_json($strBook);
?>
<!DOCTYPE html>
<html>
<head>
<title> title</title>
<meta charset="utf-8">
<script type="text/javascript" src="/3p/jquery/jquery-1.7.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var strBookObj = '<?php echo $strBook; ?>' ;
try{
bookObj = JSON.parse(strBookObj) ;
console.log(bookObj.title);
console.log(bookObj.description);
$("#title").html(bookObj.title);
$("#description").html(bookObj.description);
} catch(ex) {
console.log("Error parsing book object json");
}
});
</script>
</head>
<body>
<h2> Json parsing test page </h2>
<div id="title"> </div>
<div id="description"> </div>
</body>
</html>
将字符串放在java脚本中的单引号中。将JSON字符串放在双引号内将导致解析器在属性标记处失败(类似于{“id”:“value”})。如果您将字符串设置为“literal”并让JSON解析器完成工作,则不需要其他转义。
答案 5 :(得分:1)
也许我是瞎子,但在你的例子中他们是逃脱的。
怎么样?<script type="text/javascript">
JSON.parse("<?php echo $s ?>"); // Will throw SyntaxError
</script>
(注意不同的引语)
答案 6 :(得分:0)
只是Greg的回复的补充:json_encode()
的输出已包含在双引号("
)中,因此无需再次用引号括起它们:
<script type="text/javascript">
JSON.parse(<?php echo $s ?>);
</script>
答案 7 :(得分:0)
控制字符在HTML中没有特殊含义,除了textarea.value中的新行。 PHP上的JSON_encode&gt; 5.2会像你期望的那样做。
如果您只想显示文字,则无需追踪JSON。 JSON适用于JavaScript中的数组和对象(以及PHP的索引和关联数组)。
如果您需要texarea-tag的换行符:
$s=preg_replace('/\r */','',$s);
echo preg_replace('/ *\n */',' ',$s);
答案 8 :(得分:0)
我不完全理解var_export是如何工作的,所以如果遇到麻烦我会更新,但这似乎对我有用:
<script>
window.things = JSON.parse(<?php var_export(json_encode($s)); ?>);
</script>
答案 9 :(得分:0)
这是我个人使用的,它永远不会起作用。最初有类似的问题。
源脚本(ajax)将获取一个数组并对其进行json_encode。例如:
$return['value'] = 'test';
$return['value2'] = 'derp';
echo json_encode($return);
我的javascript将进行AJAX调用,并将回显的“json_encode($ return)”作为输入,在脚本中我将使用以下内容:
myVar = jQuery.parseJSON(msg.replace(/"/ig,'"'));
“msg”是返回值。那么,对你而言,就像......
var msg = '<?php echo $s ?>';
myVar = jQuery.parseJSON(msg.replace(/"/ig,'"'));
......可能适合你。
答案 10 :(得分:-1)
当使用任何形式的Ajax时,Web上似乎缺少从CGI服务器收到的响应格式的详细文档。这里的一些注释和stackoverflow.com上的条目指出必须转义返回文本或json数据中的换行符以防止JSON转换中的无限循环(挂起)(可能通过抛出未捕获的异常创建),无论是由jQuery自动完成还是手动使用Javascript系统或库JSON解析调用。
在程序员发布此问题的每种情况下,都会提供不充分的解决方案(最常见的是在发送方用\ n中取代\ n)并且问题被删除。当传递意外嵌入控制转义序列的字符串值(如Windows路径名)时,会显示它们的不足之处。一个例子是“C:\ Chris \ Roberts.php”,它包含控制字符^ c和^ r,它们可以导致字符串{“file”:“C:\ Chris \ Roberts.php”}的JSON转换为永远循环。生成此类值的一种方法是故意尝试将PHP警告和错误消息从服务器传递到客户端,这是一个合理的想法。
根据定义,Ajax在后台使用HTTP连接。此类连接使用GET和POST传递数据,这两者都需要对发送的数据进行编码,以避免语法错误,包括控制字符。
这提供了足够的暗示来构建似乎是一个解决方案(它需要更多测试):在PHP(发送)端使用rawurlencode对数据进行编码,并在Javascript(接收)端使用unescape进行解码数据。在某些情况下,您将这些应用于整个文本字符串,在其他情况下,您只将它们应用于JSON内的值。
如果这个想法证明是正确的,可以构建简单的例子来帮助各级程序员一劳永逸地解决这个问题。
答案 11 :(得分:-1)
$val = array("\n","\r");
$string = str_replace($val, "", $string);
它将删除PHP中的所有新行来自json string
答案 12 :(得分:-1)
除非使用AJAX,否则有两种解决方案:
将数据写入输入,并在JS中读取:
<input type="hidden" value="<?= htmlencode(json_encode($data)) ?>"/>
使用addslashes
var json = '<?= addslashes(json_encode($data)) ?>';