Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with backslashes in json strings php

Tags:

json

php

There appears to be an oddity with json_encode and/or json_decode when attempting decode a string that was produced by 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();

I've never experienced a problem previous to this, as I've never had to capture a string with backslashes in it until today. In reviewing the code above, I can encode/decode utilizing PHP's built in components. However if I attempt to decode a string that was produced by this encoder I get an error message. I've read in documentation items like "Predefined Constants" and other stack questions like "how remove the backslash (“\”) in the json response using php?". But I can't seem to find a reason WHY I can't decode a string that was produced by json_encode. The PHP version I'm using to test this code is 5.5.9.

I know I could be totally clueless by missing something, but should I be handling my string that was produced by json_encode differently if I attempt to use it elsewhere?

like image 607
J. Gavin Ray Avatar asked Aug 17 '15 18:08

J. Gavin Ray


People also ask

Are backslashes valid in JSON?

The backslash ( \ ) is a special character in both PHP and JSON. Both languages use it to escape special characters in strings and in order to represent a backslash correctly in strings you have to prepend another backslash to it, both in PHP and JSON.

Why does JSON string have backslash?

Those backslashes are escape characters. They are escaping the special characters inside of the string associated with JSON response. You have to use JSON. parse to parse that JSON string into a JSON object.

How remove slashes from JSON in PHP?

The stripslashes() function removes backslashes added by the addslashes() function. Tip: This function can be used to clean up data retrieved from a database or from an HTML form.


2 Answers

The answer is in the question:

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

You don't have to strip any slashes. On the contrary. You have to express the echo-ed text as PHP source code.

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

The backslash (\) is a special character in both PHP and JSON. Both languages use it to escape special characters in strings and in order to represent a backslash correctly in strings you have to prepend another backslash to it, both in PHP and JSON.

Let's try to do the job of the PHP parser on the string above. After the open parenthesis it encounters a string enclosed in single quotes. There are two special characters that needs escaping in single quote strings: the apostrophe (') and the backslash (\). While the apostrophe always needs escaping, the PHP interpreter is forgiving and allows unescaped backslashes as long as they do not create confusion. However, the correct representation of the backslash inside single quoted strings is \\.

The string passed to function json_decode() is

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

Please note that this is the exact list of characters processed on runtime and not a string represented in PHP or any other language. The languages have special rules for representing special characters. This is just plain text.

The text above is interpreted by function json_decode() that expects it to be a piece of JSON. JSON is a small language, it has special rules for encoding of special characters in strings. The backslash is one of these characters and when it appears in a string it must be prepended by another backslash. JSON is not forgiving; when it encounters a backslash it always treats it as an escape character for the next character in the string.

The object created by json_decode() after successful parsing of the JSON representation you pass them contains a single property named namespace whose value is:

myCompany\package\subpackage

Note again that this is the actual string of characters and not a representation in any language.

What went wrong?

Back to your code:

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

The PHP parser interprets the code above using the PHP rules. It understands that the json_decode() function must be invoked with the text {"namespace":"myCompany\package\subpackage"} as argument.

json_decode() uses its rules and tries to interpret the text above as a piece of JSON representation. The quote (") before myCompany tells it that "myCompany\package\subpackage" must be parsed as string. The backslash before package is interpreted as an escape character for p but \p is not a valid escape sequence for strings in JSON. This is why it refuses to continue and returns NULL.

like image 131
axiac Avatar answered Nov 15 '22 13:11

axiac


You will need to encode your double backslashes \\ into quadruple backslashes \\\\ because php interprets a backslash as an escape character in single and double quoted strings. This means that \\ is seen as \.

This example illustrates what is happening

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

This is the output

$ php test.php
{"namespace":"myCompany\package\subpackage"}
Syntax error
class stdClass#1 (1) {
  public $namespace =>
  string(28) "myCompany\\package\\subpackage"
}
No error
like image 24
Josh J Avatar answered Nov 15 '22 13:11

Josh J