【问题标题】:JSON created with PHP's json_encode results in parse errors使用 PHP 的 json_encode 创建的 JSON 会导致解析错误
【发布时间】:2023-04-09 01:24:01
【问题描述】:

取以下 PHP 数组:

$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,
);

当使用 PHP 的 json_encode 解析为 JSON 时,我得到以下字符串:

[{"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}]

请注意,原始字符串中的双引号会使用反斜杠进行转义。看起来不错,甚至validates

当我尝试在 Chrome 或 Safari 中解析 JSON(使用 JSON.parse())时,我在控制台中收到以下错误:

Uncaught SyntaxError: Unexpected number

Firefox 给了我:

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

从 Firefox 错误中,我收集到字符串中第一个转义的双引号似乎破坏了代码。

如果我在引号之前手动转义 反斜杠,我会得到预期的对象...

如何防止此错误?我是不是做错了什么?


相关代码:

型号:

// 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;
}

控制器:

    // 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);

查看:

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

【问题讨论】:

  • 显示你的 js 代码。如果您上面的 json 字符串有效,那么 ELSE 正在破坏它。
  • 添加了相关代码sn-ps。如果您还需要其他东西,请告诉我。
  • json 已经是有效的 javascript,所以你可以只使用 var foo = &lt;?php echo $json ?&gt;;。无需转储到 ' 字符串然后单独解析。但是,由于您的字符串已损坏,无论如何它仍然会以其他方式损坏-您是否确认您在任何地方都有正确的字符集?例如如果您在(比如说)win-1252 字符集环境中构建 json,然后转储到 utf-8 页面中,您会得到损坏的字符。
  • @MarcB:你是对的。删除单引号有效,但问题仍然存在。是的。我到处都在使用 UTF-8。您可以在控制台中运行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}]'); 吗?如果您遇到同样的错误,我们可以排除编码问题。
  • 那是因为您的 json 已损坏。 json IS 有效的 javascript。如果您的 json 字符串有效,那么 var foo = [{....}]; 将是完全可以接受/有效的 javascript。

标签: php json


【解决方案1】:

你没有做任何“错误”的事情。事实上,您自己已经找到了解决方案! PHP 生成的字符串可能会通过echo 转移到 JavaScript 中,使用类似

的方式将其转换为一行 JavaScript 代码
var jsvar='<?= json_encode($arr) ?>';

结果看起来或多或少像您在帖子中显示的那样:

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}]';

当 JavaScript 解析此字符串时," 之前的 \ 将被“吃掉”,JSON.parse 解析的 JSON 字符串将如下所示:

'{"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}'

这个字符串会导致错误消息,这是可以理解的。

解决方案:

所以,你要做的就是用addslashes() 屏蔽你所有的\

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

或者,正如@JAAulde 非常正确地发布的那样:您可以直接跳过变量的“字符串”状态:

var o=<?= json_encode($arr)) ?>;

【讨论】:

    【解决方案2】:

    因为 JSON 使用 JS 文字语法的子集,所以将其直接回显到 JS 的上下文中不需要任何引号换行或解析。

    输出如下:

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

    一旦 JS 执行,变量enterprises 就会成为你想要的数据结构。因此,您还需要删除此行:

    enterprises = JSON.parse(enterprises);
    

    FWIW,您最初的错误是由于需要在 JS 字符串文字中使用双转义斜杠引起的。因为您输出到字符串文字,所以单个 \" 在 JavaScript 执行中被吃掉,不再存在用于 JSON 解析。要输出到 JS 字符串文字,您首先需要转义转义符。因此,您应该坚持我的上述更改(更不用说我建议的更改需要更少的开销)。

    【讨论】:

    • 这是不正确的。 PHP 的json_encode 生成一个字符串。我需要 &lt;?php echo $json; ?&gt; 周围的引号,以便 JS 理解它是一个字符串。不添加引号会产生Uncaught SyntaxError: Unexpected token o 错误。
    • @AlexandreReiffJanini 您对所涉及的机制存在根本性的误解。试试我说的,你就知道了。 (从 PHP 到浏览器的所有输出数据都是传递到各种上下文中的字符串。您不会仅仅因为它们是 PHP 中的字符串而将输出的 HTML 用引号括起来......)。另外,请记下对您接受的答案的修改。
    • 我已经测试了var o=&lt;?=json_encode($arr)?&gt;; - 它确实有效!
    猜你喜欢
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    相关资源
    最近更新 更多