web-dev-qa-db-fra.com

Comment traiter les backslashes dans les chaînes JSON php

Il semble y avoir une bizarrerie avec json_encode et/ou json_decode lors d’une tentative de décodage d’une chaîne produite par json_encode:

    $object = new stdClass;
    $object->namespace = 'myCompany\package\subpackage';

    $jsonEncodedString = json_encode($object);
    echo $jsonEncodedString;
    // Result of echo being:
    // {"namespace":"myCompany\\package\\subpackage"}

    $anotherObject = json_decode($jsonEncodedString);
    echo $anotherObject->namespace;
    // Result of echo being:
    // myCompany\package\subpackage


    $yetAnotherObject = json_decode('{"namespace":"myCompany\\package\\subpackage"}');
    // Result should be:
    // myCompany\package\subpackage
    // But returns an invalid string sequence error instead...
    echo json_last_error_msg();

Je n'avais jamais rencontré de problème auparavant, car je n'avais jamais eu à capturer de chaîne contenant des barres obliques inverses jusqu'à aujourd'hui. En examinant le code ci-dessus, je peux encoder/décoder en utilisant les composants intégrés de PHP. Cependant, si je tente de décoder une chaîne produite par cet encodeur, un message d'erreur apparaît. J'ai lu dans la documentation des éléments tels que " Constantes pré-définies " et d'autres questions sur la pile, telles que " comment supprimer la barre oblique inversée ("\") de la réponse Json à l'aide de php? ". Mais je n'arrive pas à trouver une raison pour laquelle je ne peux pas décoder une chaîne produite par json_encode. La version PHP que j'utilise pour tester ce code est 5.5.9.

Je sais que je pourrais être totalement désemparé en manquant quelque chose, mais devrais-je manipuler ma chaîne qui a été produite par json_encode différemment si je tente de l'utiliser ailleurs?

9
Da Gopherboy

La réponse est dans la question:

$jsonEncodedString = json_encode($object);
echo $jsonEncodedString;
// Result of echo being:
// {"namespace":"myCompany\\package\\subpackage"}

Vous n'avez pas à enlever les barres obliques. Au contraire. Vous devez exprimer le texte écho en tant que code source PHP.

$yetAnotherObject = json_decode('{"namespace":"myCompany\\\\package\\\\subpackage"}');

La barre oblique inverse (\) est un caractère spécial dans PHP et JSON. Les deux langues l'utilisent pour échapper aux caractères spéciaux des chaînes et pour représenter correctement une barre oblique inverse, vous devez ajouter une autre barre oblique inverse, à la fois en PHP et en JSON.

Essayons de faire le travail de l'analyseur PHP sur la chaîne ci-dessus. Après la parenthèse ouverte, il rencontre une chaîne entre guillemets simples . Il y a deux caractères spéciaux qui doivent être protégés par des chaînes de guillemets simples: l'apostrophe (') et la barre oblique inversée (\). Bien que l'apostrophe ait toujours besoin d'être évité, l'interpréteur PHP pardonne et permet des barres obliques inverses non échappées tant qu'elles ne créent pas de confusion. Cependant, la représentation correcte de la barre oblique inverse dans les chaînes entre guillemets simples est \\.

La chaîne transmise à la fonction json_decode() est

{"namespace":"myCompany\\package\\subpackage"}

Veuillez noter qu'il s'agit de la liste exacte des caractères traités au moment de l'exécution et non d'une chaîne représentée dans PHP ou de tout autre langage. Les langues ont des règles spéciales pour représenter les caractères spéciaux. Ceci est juste du texte brut.

Le texte ci-dessus est interprété par la fonction json_decode() qui s'attend à ce qu'il soit un élément de JSON. JSON est un petit langage, il a des règles spéciales pour l'encodage des caractères spéciaux dans les chaînes. La barre oblique inverse est l’un de ces caractères et, lorsqu’elle apparaît dans une chaîne, elle doit être précédée d’une autre barre oblique inversée. JSON ne pardonne pas; quand il rencontre une barre oblique inverse, il le traite toujours comme un caractère d'échappement pour le caractère suivant de la chaîne.

L'objet créé par json_decode() après une analyse réussie de la représentation JSON que vous lui transmettez contient une propriété unique nommée namespace dont la valeur est:

myCompany\package\subpackage

Notez à nouveau qu'il s'agit de la chaîne de caractères réelle et non d'une représentation dans aucune langue.

Qu'est ce qui ne s'est pas bien passé?

Retour à votre code:

$yetAnotherObject = json_decode('{"namespace":"myCompany\\package\\subpackage"}');

L'analyseur PHP interprète le code ci-dessus à l'aide des règles PHP. Il comprend que la fonction json_decode() doit être invoquée avec le texte {"namespace":"myCompany\package\subpackage"} en tant qu'argument.

json_decode() utilise ses règles et tente d'interpréter le texte ci-dessus comme un élément de représentation JSON. La citation (") avant myCompany lui indique que "myCompany\package\subpackage" doit être analysé en tant que chaîne. La barre oblique inverse avant package est interprétée comme un caractère d'échappement pour p mais \p n'est pas une séquence d'échappement valide pour les chaînes en JSON. C'est pourquoi il refuse de continuer et renvoie NULL.

5
axiac

Vous aurez besoin de coder vos doubles barres obliques inversées \\ en quadruple barres obliques inverses \\\\ car php interprète une barre oblique inversée en tant que caractère d'échappement dans des chaînes entre guillemets simples et doubles. Cela signifie que \\ est vu comme \.

Cet exemple illustre ce qui se passe

<?php
$str = '{"namespace":"myCompany\\package\\subpackage"}';
echo $str, PHP_EOL; // \\ seen as \
$yetAnotherObject = json_decode($str);
echo json_last_error_msg(), PHP_EOL;

var_dump(json_decode(str_replace('\\', '\\\\', $str)));
echo json_last_error_msg(), PHP_EOL;

C'est la sortie

$ php test.php
{"namespace":"myCompany\package\subpackage"}
Syntax error
class stdClass#1 (1) {
  public $namespace =>
  string(28) "myCompany\\package\\subpackage"
}
No error
2
Josh J

C’est parce que PHP convertit les doubles barres obliques en une seule barre oblique avant de les transmettre à json_decode. Vous devrez soit échapper aux doubles barres obliques (une douleur que je connais), soit construire l'objet manuellement.

http://php.net/manual/en/language.types.string.php#language.types.string.syntax.single

0
Blake A. Nichols