0

Take the following PHP array:

$arr = array(
    'about' => 'Ai você fala o seguinte: "- Mas vocês acabaram isso?" Vou te falar: -"Não, está em andamento!" Tem obras que "vai" durar pra depois de 2010. Agora, por isso, nós já não desenhamos, não começamos a fazer projeto do que nós "podêmo fazê"? 11, 12, 13, 14...',
    'construction' => 100,
);

When parsed to JSON with PHP's json_encode, I get the following string:

[{"about": "Ai você fala o seguinte: \"- Mas vocês acabaram isso?\" Vou te falar: -\"Não, está em andamento!\" Tem obras que \"vai\" durar pra depois de 2010. Agora, por isso, nós já não desenhamos, não começamos a fazer projeto do que nós \"podêmo fazê\"? 11, 12, 13, 14...", "construction": 100}]

Note that the double quotes in the original string get escaped with a backslash. It looks good and even validates.

When I try to parse the JSON in Chrome or Safari (using JSON.parse()), I get the following error in the console:

Uncaught SyntaxError: Unexpected number

Firefox gives me:

SyntaxError: JSON.parse: expected ',' or '}' after property value in object at line 1 column 39 of the JSON data

From the Firefox error, I gather the first escaped double quote in the string seems to break the code.

If I manually escape the backslashes before the quotes, I get the expected object...

How can I prevent this error? Am I doing something wrong?


Relevant code:

Model:

// Returns an array with basic enterprise information
public function getBasicInfo($destination = null)
{
    $response = array(
        'id' => $this->id,
        'name' => $this->name,
        'category' => ! empty($this->category_id) ? $this->category->name : '',
        'neighborhood' => ! empty($this->neighborhood) ? $this->neighborhood : '',
        'city' => (! empty($this->city) ? $this->city : '') . (! empty($this->state_id) ? (! empty($this->city) ? ', ' : '') . $this->state->abbreviation : ''),
        'dorms' => $this->dormitories_text,
        'area' => $this->area,
        'status' => ! empty($this->status_id) ? $this->status->name : '',
        'price' => $this->price > 0 ? 'R$ ' . number_format($this->price, 2, ',', '.') : '',
        'installment' => $this->installment > 0 ? 'R$ ' . number_format($this->installment, 2, ',', '.') : '',
        'image' => ! empty($this->card_image_id) && is_object($this->card_image) ? $this->card_image->getUrl() : '',
        'logo' => ! empty($this->logo_image_id) && is_object($this->logo_image) ? $this->logo_image->getUrl() : '',
        'permalink' => $this->getPermalink($destination),
        'about' => ! empty($this->about) ? $this->get_html($this->about) : '',
        'construction' => $this->getLatestConstructionStageProgress(),
    );
    return $response;
}

Controller:

    // Build data array
    $json = array();
    foreach ($enterprises as $enterprise) {
        $json[] = $enterprise->getBasicInfo(REALTOR_URL);
    }
    $json = json_encode($json);

    // Build data array
    $data = array(
        'urlOrigin'     => $this->url_origin(),
        'module'        => 'Portal do Corretor - Empreendimentos',
        'categories'    => \Type::getByType('category'),
        'cities'        => \Enterprise::getUniqueCities(),
        'statuses'      => \Type::getByType('status'),
        'prices'        => \Enterprise::$priceRanges,
        'installments'  => \Enterprise::$installmentRanges,
        'neighborhoods' => $neighborhoods,
        'json'          => $json,
        'filters'       => (object) array(
            'search'        => isset($_POST['search']) && ! empty($_POST['search']) ? $_POST['search'] : null,
            'city'          => isset($_POST['city']) && ! empty($_POST['city']) ? $_POST['city'] : null,
            'neighborhood'  => isset($_POST['neighborhood']) && ! empty($_POST['neighborhood']) ? $_POST['neighborhood'] : null,
            'category'      => isset($_POST['category']) && ! empty($_POST['category']) ? intval($_POST['category']) : null,
            'dormitories'   => isset($_POST['dormitories']) && ! empty($_POST['dormitories']) ? intval($_POST['dormitories']) : null,
            'status'        => isset($_POST['status']) && ! empty($_POST['status']) ? intval($_POST['status']) : null,
        ),
        'sectionId'     => 'empreendimentos',
    );
    // Merge default values with the data array
    $data = array_merge($data, $this->getDefaultValues());

    // Returns the view with the data array
    return $this->view(REALTOR_URL . DS . 'empreendimentos', $data);

View:

<script type="text/javascript">
    var enterprises = '<?php echo $json; ?>';
</script>

JavaScript:

if ($('#enterprises') && $('#enterprise-template').length && 'undefined' !== typeof enterprises) {
    enterprises = JSON.parse(enterprises);
    enterprisesCount = enterprises.length;
}
7
  • 2
    show your js code. if the json string you have above validates, then something ELSE is corrupting it. Commented Jul 28, 2015 at 14:12
  • Added relevant code snippets. Let me know if you need something else. Commented Jul 28, 2015 at 14:23
  • json is already valid javascript, so youc ould just have var foo = <?php echo $json ?>;. no need for dumping into a ' string and then parsing separately. however, since your string is getting corrupted, it'd still get corruped this other way anyways - have you CONFIRMED that you have correct character sets everywhere? e.g. if you're building the json in a (say) win-1252 charset environment, then dumping into a utf-8 page, you'll get mangled characters. Commented Jul 28, 2015 at 14:26
  • 1
    @MarcB: You're correct. Removing the single quotes works, but the problem persists. Yes. I am using UTF-8 everywhere. Could you run JSON.parse('[{"about": "Ai você fala o seguinte: \"- Mas vocês acabaram isso?\" Vou te falar: -\"Não, está em andamento!\" Tem obras que \"vai\" durar pra depois de 2010. Agora, por isso, nós já não desenhamos, não começamos a fazer projeto do que nós \"podêmo fazê\"? 11, 12, 13, 14...", "construction": 100}]'); in your console? If you get the same error, we can rule out encoding issues. Commented Jul 28, 2015 at 14:30
  • 1
    that's because your json is corrupted. json IS valid javascript. if your json string was valid, then var foo = [{....}]; would be perfectly acceptable/valid javascript. Commented Jul 28, 2015 at 14:43

2 Answers 2

6

You are not doing anything "wrong". In fact you have already found the solution yourself! The PHP-generated string is presumably transferred to JavaScript by echo-ing it into a line of JavasScript code using something like

var jsvar='<?= json_encode($arr) ?>';

The result will look more or less like you have shown in your post:

var js_var='[{"about": "Ai você fala o seguinte: \"- Mas vocês acabaram isso?\" Vou te falar: -\"Não, está em andamento!\" Tem obras que \"vai\" durar pra depois de 2010. Agora, por isso, nós já não desenhamos, não começamos a fazer projeto do que nós \"podêmo fazê\"? 11, 12, 13, 14...", "construction": 100}]';

When JavaScript parses this string the \ before the " will be 'eaten up' and the JSON-string to be parsed by JSON.parse will look like:

'{"about":"Ai você fala o seguinte: "- Mas vocês acabaram isso?" Vou te falar: -"Não, está em andamento!" Tem obras que "vai" durar pra depois de 2010. Agora, por isso, nós já não desenhamos, não começamos a fazer projeto do que nós "podêmo fazê"? 11, 12, 13, 14...","construction":100}'

This string will understandably lead to error messages.

Solution:

So, what you will have to do is mask all your \ with addslashes():

var jsvar='<?= addslashes(json_encode($arr)) ?>';
var o=JSON.parse(jsvar);

Or, as @JAAulde quite correctly posted: you can skip the `string'-state of the variable altogether by doing directly:

var o=<?= json_encode($arr)) ?>;
Sign up to request clarification or add additional context in comments.

Comments

2

Because JSON uses a subset of JS literal syntax, echoing it straight into the context of JS does not require any quote wrapping or parsing.

Outputting like this:

var enterprises = <?php echo $json; ?>;

Will cause the variable, enterprises, to be the data structure you desire once JS executes. As such, you also need to remove this line:

enterprises = JSON.parse(enterprises);

FWIW, your original error is caused by the need to double escape slashes in JS string literals. Because you outputted into a string literal, the single \" is eaten up in the JavaScript execution and is no longer there for the JSON parse. To output into a JS string literal you would first need to escape the escapes. Thus, you should stick with my above changes (not to mention that my recommended changes require less overhead).

3 Comments

This is incorrect. PHP's json_encode generates a string. I need the quotes around the <?php echo $json; ?> so that JS will understand it's a string. Not adding quotes generates a Uncaught SyntaxError: Unexpected token o error.
@AlexandreReiffJanini You have a fundamental misunderstanding of the mechanics involved. Try what I said, you'll see. (All outputted data from PHP to the browser is a string being passed into various contexts. You don't wrap your outputted HTML in quotes just because they're a string in PHP...). Also, take note of the edit to your accepted answer.
I have tested var o=<?=json_encode($arr)?>; - it does work!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.