2011-01-11 2 views
31

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

Это может быть боль в попке для отладки в сложной системе. Было бы гораздо более уместно увидеть недопустимый символ или, по крайней мере, его пропустить. Как бы то ни было, 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(). Я ищу способы облегчить диагностику ошибок кодирования. Строка A null не подходит для этого.

+0

Является ли строка '' Düsseldorf '' недействительной только тогда, когда вы 'utf8_decode()' it? –

+0

@Matt нет, это был просто пример создания сломанной строки для ответчиков для тестирования –

+0

Итак, вы получаете некоторые данные JSON, которые могут содержать недопустимые строки UTF-8? – Gumbo

ответ

39

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

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

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 есть, поэтому покупатель остерегается ... так как могут быть крайние случаи, когда он все еще не работает. Я ненавижу проблемы с набором символов.

+0

Интересно и звучит странно! Я займусь этим завтра. Мне было бы достаточно предупреждения –

+0

. Идея iconv() выглядит интригующей и может просто работать. Я постараюсь и завтра. –

+0

Это сработало для меня. Я 'iconv()' данные теперь перед json_encoding его. –

3

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

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

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

+0

Да, правда, и я знаю об этом. Как я уже сказал, просто невероятно сложно отлаживать сломанную входящую кодировку, когда внезапно части вашего JSON просто начинают исчезать (вместо того, чтобы выглядеть разбитым). Это больше, чтобы находить ошибки более легко, чем обходить само разбитое кодирование. –

+0

Оберните или замените json_decode() чем-то, что проверяет кодировку каждой строки, и жалуется где-нибудь, вы действительно увидите ее, когда какая-либо строка недействительна UTF-8 ? – metamatt

5
$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")); 

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

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

+1

Эта одна линия также решила мою проблему. Спасибо –

1

Вместо того, чтобы использовать функцию Iconv, вы можете direclty использовать json_encode с опцией JSON_UNESCAPED_UNICODE (> = PHP5.4.0)

Убедитесь, что вы положили «кодировка = UTF-8» в заголовке файла PHP :

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

+0

Я не вижу, как это поможет - кажется, что все 'JSON_UNESCAPED_UNICODE' не преобразует символы Unicode в сущности' \ uxxxx'? Это не значит, что это не приведет к пустой строке при столкновении с недопустимыми символами. –

+0

Это отлично подойдет для меня! Я видел что-то подобное в другом потоке, но мне не хватало того, что мне нужно было добавить заголовок, спасибо! – Wingman1487

4

Эта функция удалит все недопустимые символы 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 replacement character, поворачивая регулярное выражение выше, но это действительно не обеспечивает лучшего пользовательского интерфейса, чем просто отбрасывание недопустимых символов.

Смежные вопросы