PHP json_encode不会转义所有JSON控制字符

时间:2009-06-26 10:54:18

标签: php json

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不起作用。

13 个答案:

答案 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", "&#039");
            $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 */','&#13;',$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(/&quot;/ig,'"'));

“msg”是返回值。那么,对你而言,就像......

var msg = '<?php echo $s ?>';
myVar = jQuery.parseJSON(msg.replace(/&quot;/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,否则有两种解决方案:

  1. 将数据写入输入,并在JS中读取:

    <input type="hidden" value="<?= htmlencode(json_encode($data)) ?>"/>
    
  2. 使用addslashes

    var json = '<?= addslashes(json_encode($data)) ?>';