web-dev-qa-db-fra.com

PHP json_encode n'échappe pas à tous les caractères de contrôle JSON

Y a-t-il des raisons pour lesquelles la fonction PHP json_encode n'échappe pas à tous les caractères JSON de la chaîne?

Par exemple, prenons une chaîne qui s'étend sur deux lignes et contient des caractères de contrôle (\ 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: \\."
?>

Notez que les caractères de retour chariot et de nouvelle ligne ne sont pas évités. Pourquoi?

J'utilise jQuery comme bibliothèque JS et sa fonction $ .getJSON () fera l'affaire si vous faites entièrement confiance aux données entrantes. Sinon, j'utilise la bibliothèque JSON2.js de JSON.org comme tout le monde . Mais si vous essayez d'analyser cette chaîne encodée, une erreur est générée:

<script type="text/javascript">

JSON.parse(<?php echo $s ?>);  // Will throw SyntaxError 

</script>

Et vous ne pouvez pas obtenir les données! Si vous supprimez ou échappez\r\n "et\dans cette chaîne, JSON.parse () ne générera pas d'erreur.

Existe-t-il une bonne fonction PHP permettant d’échapper les caractères de contrôle? Str_replace simple avec les tableaux de recherche et de remplacement ne fonctionnera pas.

26
Gustav

D'oh - vous devez double-encoder: JSON.parse attend une chaîne de cours:

<script type="text/javascript">

JSON.parse(<?php echo json_encode($s) ?>);

</script>
12
Greg
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;
  }

J'utilise la fonction ci-dessus qui échappe à une barre oblique inversée (doit être la première dans les tableaux) et devrait traiter des sauts de page et des espaces de retour (je ne pense pas que \f et \b soient supportés en PHP).

27
Peter Whitefield

Je n'ai toujours pas trouvé de solution sans str_replace .. 

Essayez ce code. 

$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);

J'espère que cela pourra aider...

4
sp2hari
$search = array("\n", "\r", "\u", "\t", "\f", "\b", "/", '"');
$replace = array("\\n", "\\r", "\\u", "\\t", "\\f", "\\b", "\/", "\"");
$encoded_string = str_replace($search, $replace, $json);

C'est la bonne façon

3
JunioR

La conversion aller-retour à partir de PHP ne devrait pas être un problème. Le code json_encode de PHP utilise un codage correct, mais sa réinterprétation dans un script Java peut entraîner des problèmes. Comme 

1) chaîne d'origine - [chaîne avec nnn nouvelle ligne] (où nnn est le caractère de nouvelle ligne actuel)

2) json_encode convertira cela en [chaîne avec "\\ n" nouvelle ligne] (caractère de contrôle converti en "\\ n" - Littéral "\ n"

3) Cependant, lorsque vous réimprimez ceci dans une chaîne littérale en utilisant php echo, "\\ n" est interprété comme "\ n" et cela provoque un chagrin d'amour. Parce que JSON.parse comprendra un "\ n" imprimé comme une nouvelle ligne - un caractère de contrôle (nnn)

donc pour contourner ce problème: -

A) Commencez par encoder l'objet json dans php en utilisant json_enocde et obtenez une chaîne. Puis exécutez-le à travers un filtre qui le rend sûr à utiliser dans les scripts HTML et Java.

B) Utilisez la chaîne JSON provenant de PHP comme un "littéral" et mettez-la entre guillemets simples au lieu de guillemets doubles.


<?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>

Placez la chaîne entre guillemets simples dans un script Java. Placer une chaîne JSON entre guillemets doubles entraînerait l'échec de l'analyseur au niveau des marqueurs d'attribut (quelque chose comme {"id": "value"}). Aucune autre évasion ne devrait être requise si vous mettez la chaîne comme "littéral" et laissez l’analyseur JSON faire le travail.

2
rjha94

Peut-être que je suis aveugle, mais dans votre exemple, ils sont échappés. Qu'en est-il de 

<script type="text/javascript">

JSON.parse("<?php echo $s ?>");  // Will throw SyntaxError 

</script>

(notez les différentes citations)

1
nothrow

Je ne comprends pas tout à fait le fonctionnement de var_export, je vais donc le mettre à jour si j'ai des problèmes, mais cela semble fonctionner pour moi:

<script>
    window.things = JSON.parse(<?php var_export(json_encode($s)); ?>);
</script>
0
colllin

C'est ce que j'utilise personnellement et ça ne marche jamais. A eu des problèmes similaires à l'origine.

Le script source (ajax) prendra un tableau et le json_encode. Exemple:

$return['value'] = 'test';
$return['value2'] = 'derp';

echo json_encode($return);

Mon javascript passe un appel AJAX et obtient le "json_encode ($ return)" renvoyé en écho, et dans le script, j'utiliserai ce qui suit:

myVar = jQuery.parseJSON(msg.replace(/&quot;/ig,'"'));

avec "msg" étant la valeur renvoyée. Donc, pour vous, quelque chose comme ...

var msg = '<?php echo $s ?>';
myVar = jQuery.parseJSON(msg.replace(/&quot;/ig,'"'));

... pourrait fonctionner pour vous.

0
Anthony Tomasino

Les caractères de contrôle n'ont aucune signification particulière dans HTML, à l'exception de la nouvelle ligne dans textarea.value. JSON_encode sur PHP> 5.2 le fera comme prévu. 

Si vous souhaitez simplement afficher du texte, vous n'avez pas besoin de rechercher JSON. JSON est pour les tableaux et les objets en JavaScript (et tableau indexé et associatif pour PHP).

Si vous avez besoin d’un saut de ligne pour l’étiquette texarea:

$s=preg_replace('/\r */','',$s);
echo preg_replace('/ *\n */','&#13;',$s);
0
B.F.

Juste un ajout à la réponse de Greg : le résultat de json_encode() est déjà contenu entre guillemets ("), il n’est donc pas nécessaire de les entourer de guillemets:

<script type="text/javascript">
    JSON.parse(<?php echo $s ?>);
</script>
0
Stefan Gehrig