Как в 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 из веб-сервиса)
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
)
)
Вот простой синтаксический анализатор, который исправит ваши цитаты за вас. Если он встретит цитату '
, которая не находится в двойной кавычке "
, он предположит, что это неправильно, и заменит двойные кавычки внутри этой цитаты и превратит заключенную цитату в двойные кавычки:
Пример:
<?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
)
)
ДЕМО-ВЕРСИЯ
Одним из решений было бы создание прокси-сервера с использованием NodeJS. NodeJS отлично обработает неисправный JSON и вернет чистую версию:
johan:~ # node
> JSON.stringify(['foo', 'bar']);
'["foo","bar"]'
Возможно, написать простой сценарий узла, который принимает данные JSON в качестве стандартного ввода и возвращает проверенный JSON в стандартный вывод. Таким образом, вы можете вызвать его из PHP.
Недостатком является то, что вашему серверу понадобятся NodeJS. Не уверен, что это проблема для вас.
Ответ Никича уже на месте. Ваши входные данные, похоже, сгенерированы вручную, поэтому вполне возможно, что в строках '
в одинарных кавычках вы получите двойные значения "
без кавычек. Поэтому вместо простого поиска и замены рекомендуется использовать регулярное выражение .
Но есть также несколько пользовательских синтаксических анализаторов 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. Если вы не ожидаете дальнейших ошибок от своего веб-сервиса, вместо этого перейдите к преобразованию котировок.
Если вы знаете, что PHP 5.5.+ будет корректно анализировать этот JSON, я бы передал ответы веб-службы через прокси-скрипт на веб-сервере PHP5.5+, который очищает ответы для более низких версий - то есть просто echo json_encode(json_decode($response))
; Это стабильный и надежный подход.
Если вы настроите URL-адрес веб-службы с помощью значения конфигурации, он будет работать для более низких версий путем доступа к прокси-серверу, в более высоких версиях - путем прямого доступа к веб-службе.
Вы могли бы использовать (и, возможно, изменить/расширить) библиотеку для создания AST из предоставленного JSON и замены одинарных кавычек двойными кавычками.
Https://github.com/Seldaek/jsonlint/blob/master/src/Seld/JsonLint/Lexer.php
Может быть хорошим началом.
Быстрым решением может быть str_replace("'","\"",$string)
. Это зависит от многих вещей, но я думаю, что вы могли бы попробовать.