0

Here is my php:

$response = array(
    'errors' => $this->errors,
    'orders_fulfilled' => $this->orders_fulfilled,
);
echo '<pre>$response: ' . print_r($response, true) . '</pre>';

$json = json_encode($response, JSON_HEX_APOS);
echo '<pre>$json: ' . print_r($json, true) . '</pre>';

This shows the following output:

$response: Array
(
    [errors] => Array
        (
            [0] => Error text

        )

    [orders_fulfilled] => 0
)

$json: {"errors":["Error text\n"],"orders_fulfilled":0}

QUESTION:

Why does php's json_encode() create unescaped \n characters out of actual newlines in the source php array, when they are not valid in the json string?

I see in this accepted answer the suggestion is to escape the source newlines, i.e. convert from \n to \\n. So why should PHP's json_encode() not be doing so here? As it stands it is directly creating a json string that chokes JSON.Parse() in javascript. For instance, try running this in console:

JSON.parse('{"errors":["Error text\n"],"orders_fulfilled":0}');

VM1628:1 Uncaught SyntaxError: Unexpected token in JSON at position 22 at JSON.parse () at :1:6

If I add a slash to escape the newline or remove it altogether, the error is gone.

Is there a flag for json_encode() that I should be using to handle escaping of special/control characters this that I have not seen in the PHP manual?

Community
  • 1
  • 1
ajmedway
  • 1,492
  • 14
  • 28
  • This is not a Shopify issue, strictly a question about php's `json_encode` and usage in conjunction with `JSON.parse` – ajmedway Dec 15 '16 at 15:39
  • Question do you parse the `$json` in the html (`print $json`)? Because then the linebreak is noticed by the browser! Or how do you test the `JSON.parse('{"errors":["Sh` line ? – JustOnUnderMillions Dec 15 '16 at 15:42
  • If you can't control outputs of error, just add `addslashes` manually in your `$response` – br3t Dec 15 '16 at 16:01

1 Answers1

6

The output of json_encode is fine.

The problem is that when you try to convert it to a JavaScript string literal by wrapping it with ', the \n gets parsed as a new line in the JS string.

When you try to parse that string as JSON, it has a real new line in it.

To convert to a JavaScript string, you also have to escape any special characters in it.

Since JSON is (more-or-less) a subset of JavaScript, json_encode will do that:

var json = <?php json_encode(json_encode($foo)); ?>;
var obj = JSON.parse(json);
console.log(obj);

… but that's a silly approach.

Just skip the bit where you treat it as JSON and just treat it as JavaScript.

var obj = <?php json_encode($foo); ?>;
console.log(obj);
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • ah I see, so this is being seen as an actual line-break appearing in the middle of a json value thus causing an "unterminated string literal" error? – ajmedway Dec 15 '16 at 16:05
  • I have since managed to verify that indeed the `\n` is perfectly valid within the json string literal – ajmedway Dec 15 '16 at 16:06
  • 2
    `\n` is valid in a JavaScript string. `\n` is valid in a JSON string. A `\n` in the expression of a JSON string as a JavaScript string will put a new line in the JSON string. A new line is not valid in a JSON string. To see this run `'{"errors":["Error text\n"],"orders_fulfilled":0}'` directly in your browser's JS console. Then copy the result, including the line break, into JSON Lint. – Quentin Dec 15 '16 at 16:09
  • perfect demo of the problem right there! I am primarily a PHP head and my brain is thus used to only seeing strings in double quotes interpret the `\n`, whereas in single quotes the `\n` is taken literally. I didn't realise that a JavaScript string would interpret the `\n` as a literal new line (like in a PHP double quoted string), hence the flaw in my understanding. – ajmedway Dec 15 '16 at 16:36