3

I have the following PHP code:

    $foo = new stdClass();
    $foo->test='hello world';
    $bar = new stdClass();
    $bar->foo = json_encode($foo);
    $encoded_string = json_encode($bar);

The $encoded_string contains:

{"foo":"{\"test\":\"hello world\"}"}

I want to parse this string from javascript (using jQuery's $.parseJSON for example):

var data = $.parseJSON('{"foo":"{\"test\":\"hello world\"}"}');
console.log(data);

I would expect something like the following to be logged:

Object {foo: '{"test":"hello world"}'}

But I get an Unexpected token t error when running it (using chromium)

How can I parse this json string in Javascript? Here's a fiddle if anyone wants to try.

periklis
  • 10,102
  • 6
  • 60
  • 68

5 Answers5

6

The problem that you're running into is that the output of json_encode is not meant to be used directly as a string in JavaScript.

json_encode outputs a usable JavaScript object:

<?php
$foo = new stdClass();
$foo->test='hello world';
$bar = new stdClass();
$bar->foo = json_encode($foo);
$encoded_string = json_encode($bar);
?>
var a = <?php $encoded_string ?>;
console.log(a.foo); // produces '{"test":"hello world"}'

If you want to needlessly parse the JSON output from a string value, you simply need to double encode $encoded_string:

<?php
$foo = new stdClass();
$foo->test='hello world';
$bar = new stdClass();
$bar->foo = json_encode($foo);
$encoded_string = json_encode(json_encode($bar));
?>
var aStr = <?php $encoded_string ?>;
var a = JSON.parse(aStr);
console.log(a.foo); //same as before

Of course, you should avoid using server side languages to generate JavaScript code, instead set up the data as either a data-* attribute or as a JSON source that can be requested with AJAX.

When the data is requested from the server (or from the attribute) it will be as a properly escaped JavaScript string, which is where JSON.parse will be necessary to parse the object.

Community
  • 1
  • 1
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
2

Your code should be

$foo = new stdClass();
$foo->test='hello world';
$bar = new stdClass();
$bar->foo = $foo;
$encoded_string = json_encode($bar);

Just json encode once at the end, and decode once at the beginning at the other end.


As for the jsfiddle, you are not considering that the string literals go through additional decoding layer before they become "strings in javascript memory".

The correct way to setup the string literal in this case is (JS-JSON-JSON):

data = $.parseJSON('{"foo":"{\\\"test\\\":\\\"hello world\\\"}"}');
console.log($.parseJSON(data.foo));

And simply reversing the encoding steps you did works. http://jsfiddle.net/Jmjjp/2/

Esailija
  • 138,174
  • 23
  • 272
  • 326
1

The problem is double encoding as JSON. The solution you want if you need to retain the data as a string is

$bar->foo = addslashes(json_encode($foo));

scum
  • 3,202
  • 1
  • 29
  • 27
  • Think of encoding and decoding like placing items in nested boxes. `addslashes` is not the appropriate function to encode the string to store it within another box. One could simply call `json_encode(json_encode($foo))` but the real underlying question is why this is necessary in the first place. – zzzzBov Jun 18 '13 at 21:15
  • Agreed. Pinoniq's answer should suffice. The 'arbitrary data coming from a different source, which may or may not be already json encoded' should be processed first to check what data is coming across before encoding it (possibly again). – scum Jun 18 '13 at 21:19
0

The code returns exactly what it should return.

when json_encodein $bar, $bar->foo is a string. this string is escaped to produce a correct output.

$bar->foo = json_encode($foo);

should be $bar->foo = $foo

Pinoniq
  • 1,365
  • 9
  • 13
  • My problem is that $bar contains json_encoded properties. The function is correct; how do I get the object in javascript though? – periklis Jun 18 '13 at 20:56
  • I don't want the inner encoded string unparsed ($foo in this example); I want it to remain as is and only get the "outer" object – periklis Jun 18 '13 at 20:59
  • I don't manage to see what the problem is or why my answer doesnt solver your problem :/ – Pinoniq Jun 18 '13 at 21:03
  • Pinoniq is correct. The problem is double encoding as JSON. The solution you want if you need to retain the data as a string is `$bar->foo = addslashes(json_encode($foo));` – scum Jun 18 '13 at 21:07
  • @Pinoniq because I don't have control over the string $foo. It is arbitrary data coming from a different source, which may or may not be already json encoded. Your solution is based on the assumption that I can bypass encoding foo, but that was merely an example, so you're not answering the question itself: A json_encoded object that contains properties that are already encoded, how will it be decoded? – periklis Jun 18 '13 at 21:08
  • Ah, in that case my answer isnt an answer at all :) – Pinoniq Jun 18 '13 at 21:16
0

you need to escape the slashes protecting the inner quotes:

JSON.parse('{"foo":"{\\"test\\":\\"hello world\\"}"}');
// == Object {foo: '{"test":"hello world"}'}
dandavis
  • 16,370
  • 5
  • 40
  • 36