Подтвердить что ты не робот

Как сохранить json_encode() от удаления строк с недопустимыми символами

Есть ли способ сохранить json_encode() от возврата null для строки, содержащей недопустимый символ (не UTF-8)?

Это может быть болью в заднице для отладки в сложной системе. Было бы гораздо более уместно увидеть недопустимый символ или, по крайней мере, его пропустить. Как бы то ни было, json_encode() будет тихо отбрасывать всю строку.

Пример (в UTF-8):

$string = 
  array(utf8_decode("Düsseldorf"), // Deliberately produce broken string
        "Washington",
        "Nairobi"); 

print_r(json_encode($string));

Результаты в

[null,"Washington","Nairobi"]

Желаемый результат:

["D�sseldorf","Washington","Nairobi"]

Примечание. Я не, желая, чтобы сломанные строки работали в json_encode(). Я ищу способы облегчить диагностику ошибок кодирования. Строка null не подходит для этого.

4b9b3361

Ответ 1

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

Вот некоторый код, который демонстрирует это:

error_reporting(-1);//report all errors
$invalid_utf8_char = chr(193);

ini_set('display_errors', 1);//display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());//nothing

ini_set('display_errors', 0);//do not display errors to standard output
var_dump(json_encode($invalid_utf8_char));
var_dump(error_get_last());// json_encode(): Invalid UTF-8 sequence in argument

Это странное и неудачное поведение связано с этой ошибкой https://bugs.php.net/bug.php?id=47494 и некоторыми другими, и не похоже, что она когда-либо будет исправлена.

обходной путь:

Очистка строки перед ее передачей в json_encode может быть приемлемым решением.

$stripped_of_invalid_utf8_chars_string = iconv('UTF-8', 'UTF-8//IGNORE', $orig_string);
if ($stripped_of_invalid_utf8_chars_string !== $orig_string) {
    // one or more chars were invalid, and so they were stripped out.
    // if you need to know where in the string the first stripped character was, 
    // then see http://stackoverflow.com/questions/7475437/find-first-character-that-is-different-between-two-strings
}
$json = json_encode($stripped_of_invalid_utf8_chars_string);

http://php.net/manual/en/function.iconv.php

Руководство говорит

//IGNORE молча отбрасывает символы, которые являются недопустимыми в целевой кодировке.

Таким образом, сначала удалив проблемные символы, в теории json_encode() не должен получить ничего, что он захлебнется и потерпит неудачу. Я не проверил, что вывод iconv с флагом //IGNORE полностью совместим с понятием json_encodes того, что являются действительными символами utf8, так что покупатель остерегается... поскольку могут быть крайние случаи, когда он все еще терпит неудачу. тьфу, я ненавижу проблемы с набором символов.

редактировать
в php 7. 2+ появились новые флаги для json_encode: JSON_INVALID_UTF8_IGNORE и JSON_INVALID_UTF8_SUBSTITUTE
Документации пока немного, но сейчас этот тест должен помочь вам понять ожидаемое поведение: https://github.com/php/php-src/blob/master/ext/json/tests/json_encode_invalid_utf8.phpt

И в php 7. 3+ появился новый флаг JSON_THROW_ON_ERROR. Смотрите http://php.net/manual/en/class.jsonexception.php

Ответ 2

$s = iconv('UTF-8', 'UTF-8//IGNORE', $s);

Это решило проблему. Я не уверен, почему ребята из php не облегчили жизнь, установив json_encode().

В любом случае использование вышеописанного позволяет json_encode() создавать объект, даже если данные содержат специальные символы (например, шведские буквы).

Затем вы можете использовать результат в javascript без необходимости декодирования данных обратно в исходную кодировку (с escape(), unescape(), encodeURIComponent(), decodeURIComponent());

Я использую его вот так в php (smarty):

$template = iconv('UTF-8', 'UTF-8//IGNORE', $screen->fetch("my_template.tpl"));

Затем я отправляю результат на javascript и просто innerHTML готовый шаблон (html peace) в моем документе.

Просто указанная выше строка должна быть реализована в json_encode() каким-то образом, чтобы позволить ей работать с любой кодировкой.

Ответ 3

Эта функция удалит все недопустимые символы UTF8 из строки:

function removeInvalidChars( $text) {
    $regex = '/( [\x00-\x7F] | [\xC0-\xDF][\x80-\xBF] | [\xE0-\xEF][\x80-\xBF]{2} | [\xF0-\xF7][\x80-\xBF]{3} ) | ./x';
    return preg_replace($regex, '$1', $text);
}

Я использую его после преобразования документа Excel в json, поскольку документы Excel не гарантируются в UTF8.

Я не думаю, что есть особенно разумный способ преобразования недопустимых символов в видимый, но действительный символ. Вы можете заменить недопустимые символы U + FFFD, который является символом unicode , поворачивая регулярное выражение выше, но это действительно не обеспечивает лучшего чем просто сбросить недопустимые символы.

Ответ 4

Вам нужно знать кодировку всех строк, с которыми вы имеете дело, или вы входите в мир боли.

UTF-8 - это простая кодировка для использования. Кроме того, JSON определен для использования UTF-8 (http://www.json.org/JSONRequest.html). Так почему бы не использовать его?

Короткий ответ: способ избежать json_encode() отбрасывания ваших строк - убедиться, что они действительны UTF-8.

Ответ 5

Вместо использования функции iconv вы можете использовать json_encode с параметром JSON_UNESCAPED_UNICODE ( >= PHP5.4.0)

Убедитесь, что в заголовке вашего php файла вставлен "charset = utf-8":

header ('Content-Type: application/json; charset = utf-8');