Как в json декодировать недопустимый JSON с помощью апострофа вместо кавычек


Пример кода:

<?php

$json = "['foo', 'bar']";

var_dump( json_decode($json) );

Он работает с PHP 5.5.3, но не работает для более низких версий PHP

Он работает на моей машине с PHP 5.5.3, но в других местах он терпит неудачу.

Я знаю, что это неверный JSON, но мой веб-сервис выдает мне JSON с символами ' вместе с "

['foo', "bar", {'test': "crazy \"markup\""}]

Песочница

Как анализировать данные JSON с помощью апострофов в PHP 5.3? Очевидно, что оригинальный JSON, который я хочу разобрать, больше сложный.

(Я не могу обновить свой PHP на рабочем сервере и не могу получить правильный JSON из веб-сервиса)

 18
Author: Peter, 2013-12-03

7 answers

Вот альтернативное решение этой проблемы:

function fixJSON($json) {
    $regex = <<<'REGEX'
~
    "[^"\\]*(?:\\.|[^"\\]*)*"
    (*SKIP)(*F)
  | '([^'\\]*(?:\\.|[^'\\]*)*)'
~x
REGEX;

    return preg_replace_callback($regex, function($matches) {
        return '"' . preg_replace('~\\\\.(*SKIP)(*F)|"~', '\\"', $matches[1]) . '"';
    }, $json);
}

Этот подход более надежен, чем функция h2ooooooo в двух отношениях:

  • Он сохраняет двойные кавычки, встречающиеся в одной строке в кавычках, применяя к ним дополнительное экранирование. вариант h2o заменит их вместо этого двойными кавычками, тем самым изменив значение строки.
  • Он будет правильно обрабатывать экранированные двойные кавычки \", для которых версия h2o, похоже, переходит в бесконечную цикл.

Тест:

$brokenJSON = <<<'JSON'
['foo', {"bar": "hel'lo", "foo": 'ba"r ba\"z', "baz": "wor\"ld ' test"}]
JSON;

$fixedJSON = fixJSON($brokenJSON);
$decoded = json_decode($fixedJSON);

var_dump($fixedJSON);
print_r($decoded);

Вывод:

string(74) "["foo", {"bar": "hel'lo", "foo": "ba\"r ba\"z", "baz": "wor\"ld ' test"}]"
Array
(
    [0] => foo
    [1] => stdClass Object
        (
            [bar] => hel'lo
            [foo] => ba"r ba"z
            [baz] => wor"ld ' test
        )
)
 32
Author: NikiC, 2013-12-07 11:20:02

Вот простой синтаксический анализатор, который исправит ваши цитаты за вас. Если он встретит цитату ', которая не находится в двойной кавычке ", он предположит, что это неправильно, и заменит двойные кавычки внутри этой цитаты и превратит заключенную цитату в двойные кавычки:

Пример:

<?php
    function fixJSON($json) {
        $newJSON = '';

        $jsonLength = strlen($json);
        for ($i = 0; $i < $jsonLength; $i++) {
            if ($json[$i] == '"' || $json[$i] == "'") {
                $nextQuote = strpos($json, $json[$i], $i + 1);
                $quoteContent = substr($json, $i + 1, $nextQuote - $i - 1);
                $newJSON .= '"' . str_replace('"', "'", $quoteContent) . '"';
                $i = $nextQuote;
            } else {
                $newJSON .= $json[$i];
            }
        }

        return $newJSON;
    }

    $brokenJSON = "['foo', {\"bar\": \"hel'lo\", \"foo\": 'ba\"r'}]";
    $fixedJSON = fixJSON( $brokenJSON );

    var_dump($fixedJSON);

    print_r( json_decode( $fixedJSON ) );
?>

Выход:

string(41) "["foo", {"bar": "hel'lo", "foo": "ba'r"}]"
Array
(
    [0] => foo
    [1] => stdClass Object
        (
            [bar] => hel'lo
            [foo] => ba'r
        )

)

ДЕМО-ВЕРСИЯ

 6
Author: h2ooooooo, 2013-12-06 11:06:14

Одним из решений было бы создание прокси-сервера с использованием NodeJS. NodeJS отлично обработает неисправный JSON и вернет чистую версию:

johan:~ # node
> JSON.stringify(['foo', 'bar']);
'["foo","bar"]'

Возможно, написать простой сценарий узла, который принимает данные JSON в качестве стандартного ввода и возвращает проверенный JSON в стандартный вывод. Таким образом, вы можете вызвать его из PHP.

Недостатком является то, что вашему серверу понадобятся NodeJS. Не уверен, что это проблема для вас.

 3
Author: Johan, 2013-12-06 11:08:06

Ответ Никича уже на месте. Ваши входные данные, похоже, сгенерированы вручную, поэтому вполне возможно, что в строках ' в одинарных кавычках вы получите двойные значения " без кавычек. Поэтому вместо простого поиска и замены рекомендуется использовать регулярное выражение .

Но есть также несколько пользовательских синтаксических анализаторов JSON, которые поддерживают немного больший синтаксис выражений Javascript. Вероятно, лучше всего говорить о JSOL, объектных литералах JavaScript, в этот момент.

Груши сервис_json

Services_json может декодировать:

  • ключи объектов без кавычек
  • и строки, заключенные в одинарные кавычки.

Никаких дополнительных опций не требуется, просто = (new Services_JSON)->decode($jsol);

Up_json_decode() в upgradephp

На самом деле это было задумано как запасной вариант для ранних версий PHP без расширения JSON. Это переопределяет PHPs json_decode(). Но есть также версия upgrade.php.prefixed, которую вы бы используйте здесь.
Он вводит дополнительный флаг JSON_PARSE_JAVASCRIPT.

up_json_decode($jsol, false, 512, JSON_PARSE_JAVASCRIPT);

И я совершенно забыл об этом, но он также поддерживает строки в одинарных кавычках.
Например:

{ num: 123, "key": "value", 'single': 'with \' and unquoted " dbls' } 

Будет декодироваться в:

stdClass Object
(
    [num] => 123
    [key] => value
    [single] => with ' and unquoted " double quotes
)

Очевидно, что синтаксический анализатор в стране пользователей значительно медленнее, чем просто предварительная обработка искаженного JSON. Если вы не ожидаете дальнейших ошибок от своего веб-сервиса, вместо этого перейдите к преобразованию котировок.

 3
Author: mario, 2017-05-23 11:46:51

Если вы знаете, что PHP 5.5.+ будет корректно анализировать этот JSON, я бы передал ответы веб-службы через прокси-скрипт на веб-сервере PHP5.5+, который очищает ответы для более низких версий - то есть просто echo json_encode(json_decode($response)); Это стабильный и надежный подход.

Если вы настроите URL-адрес веб-службы с помощью значения конфигурации, он будет работать для более низких версий путем доступа к прокси-серверу, в более высоких версиях - путем прямого доступа к веб-службе.

 2
Author: hek2mgl, 2013-12-07 11:39:02

Вы могли бы использовать (и, возможно, изменить/расширить) библиотеку для создания AST из предоставленного JSON и замены одинарных кавычек двойными кавычками.

Https://github.com/Seldaek/jsonlint/blob/master/src/Seld/JsonLint/Lexer.php

Может быть хорошим началом.

 0
Author: Anthony Sterling, 2013-12-03 10:24:44

Быстрым решением может быть str_replace("'","\"",$string). Это зависит от многих вещей, но я думаю, что вы могли бы попробовать.

 0
Author: Adrian Mare, 2013-12-06 11:06:24