Как json_decode недействительный JSON с апострофом вместо кавычки
Пример кода:
<?php
$json = "['foo', 'bar']";
var_dump( json_decode($json) );
Он работает с PHP 5.5.3, но он не подходит для более низких версий PHP
Он работает на моей машине с PHP 5.5.3, но он не работает везде.
Я знаю, что это некорректно JSON, но мой webservice дает мне JSON с символами '
вместе с "
['foo', "bar", {'test': "crazy \"markup\""}]
Песочница
Как анализировать данные JSON с апострофами в PHP 5.3? Очевидно, что оригинальный JSON, который я хочу проанализировать, более сложный.
(я не могу обновить свой PHP на производственном сервере, не получив должного JSON от webservice)
Ответы
Ответ 1
Здесь альтернативное решение этой проблемы:
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
)
)
Ответ 2
Вот простой парсер, который исправит ваши кавычки для вас. Если он встречает цитату '
, которая не входит в двойную кавычку "
, она предположит, что она ошибочна и заменит двойные кавычки внутри этой цитаты, и включите цитату в двойные кавычки:
Пример:
<?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
)
)
DEMO
Ответ 3
Одним из решений было бы создание прокси-сервера с использованием NodeJS. NodeJS будет обрабатывать неисправный JSON просто отлично и вернуть чистую версию:
johan:~ # node
> JSON.stringify(['foo', 'bar']);
'["foo","bar"]'
Возможно, напишите простой Node script, который принимает данные JSON как STDIN и возвращает проверенный JSON в STDOUT. Таким образом вы можете вызвать его из PHP.
Недостатком является то, что вашему серверу потребуется NodeJS. Не уверен, что это проблема для вас.
Ответ 4
Ответ NikiCs уже присутствует. Кажется, что ваш ввод создается вручную, поэтому вполне возможно, что в пределах '
одинарных кавычек вы получите недопустимые числа "
. Поэтому регулярное выражение утверждение рекомендуется вместо простого поиска и замены.
Но есть также несколько пользовательских JSON-парсеров, которые поддерживают немного больше синтаксиса выражения Javascript. На данный момент лучше всего говорить об JSOL, объектных литералах JavaScript.
Services_JSON может декодировать:
- ключи без кавычек
- и строки, заключенные в одинарные кавычки.
Дополнительные параметры не требуются, просто = (new Services_JSON)->decode($jsol);
Это на самом деле означало возврат к ранним версиям PHP без расширения JSON. Он повторно использует PHP 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. Если вы не ожидаете дальнейших сбоев от вашего веб-сервиса, перейдите вместо преобразования котировки.
Ответ 5
Если вы знаете, что PHP 5.5. + будет корректно анализировать этот JSON, я бы передал ответы веб-службы через прокси-сервер script на веб-сервере PHP5.5 +, который санирует ответы для более низких версий, что означает просто echo json_encode(json_decode($response))
; Это стабильный и надежный подход.
Если URL-адрес веб-службы настраивается через значение конфигурации, он будет работать для более низких версий, обратившись к прокси-серверу, в более высоких версиях, напрямую обращаясь к веб-службе.
Ответ 6
Вы можете использовать (и, возможно, модифицировать/расширять) библиотеку для сборки AST из поставляемого JSON и заменять одиночные кавычки двойными кавычками.
https://github.com/Seldaek/jsonlint/blob/master/src/Seld/JsonLint/Lexer.php
Может быть, хорошее начало.
Ответ 7
Быстрое решение может быть str_replace("'","\"",$string)
. Это зависит от многих вещей, но я думаю, вы могли бы попробовать.