За последние 24 часа нас посетили 22540 программистов и 1149 роботов. Сейчас ищут 630 программистов ...

JSON и PHP. Проблемы с кириллицей в UTF-8

Тема в разделе "PHP для новичков", создана пользователем FiMka, 27 янв 2010.

  1. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Ребята, привет всем!

    Я узнал, что начиная с версии PHP 5.2 была включена поддержка кодирования/декодирования данных в формате JSON на уровне самого языка. Когда я попробовал кодировать (json_encode) PHP массив в JSON для отправки клиенту, то получил следующее:

    [{"trn":"\u0443\u0440\u043e\u0436\u0430\u0439\u043...}]

    Попробовал искать в сети, информации немного и везде люди пытаются решить проблему либо разработкой собственной версии PHP кодера/декодера в JSON, либо еще какими-либо заплатками и видами конвертирования. Я, однако, от JSON ждал компактности и скорости. Вы используете JSON в PHP? Как-то можно побороть описанную мной проблему не прибегая к методам, добавляющим дополнительные "воркэраунды" на 30 строк?
     
  2. Elkaz

    Elkaz Старожил
    Команда форума Модератор

    С нами с:
    26 июн 2006
    Сообщения:
    3.373
    Симпатии:
    0
    Адрес:
    Баку, Азербайджан
    FiMka
    Вы опечатались или действительно для декодировки использовали json_encode? Для декодирования используется json_decode.
     
  3. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Да, опечатался, даже видел, но поленился исправить :) Сорри. Поправил.
     
  4. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    http://ua2.php.net/manual/en/function.urldecode.php
    6й пример нечто похожее решает. только в обратную сторону.

    Хотя я не пойму в чем проблема?
    JS должен нормально съесть ту строку.
     
  5. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    PHP:
    1.  
    2. function utf8_urldecode($str) {
    3.     $str = preg_replace("/%u([0-9a-f]{3,4})/i","&#x\\1;",urldecode($str));
    4.     return html_entity_decode($str,null,'UTF-8');;
    5. }
    6. echo json_encode(array(utf8_urldecode("собака"))); // ["\u0441\u043e\u0431\u0430\u043a\u0430"]
    7.  
     
  6. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Не, ну ребята...
    во-первых, я же написал решает в обратную сторону (т.е. из %u0441 получает "с")
    во-вторых, я задал вопрос.
    а в-третьих, пошел я спать, смотреть буду завтра. JS должен нормально работать с ["\u0441\u043e\u0431\u0430\u043a\u0430"]
     
  7. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Simpliest, до завтра тогда.

    И в обратную сторону тоже как-то не решает, кажется, проблему:
    PHP:
    1. function utf8_urldecode($str) {
    2.     $str = preg_replace("/%u([0-9a-f]{3,4})/i","&#x\\1;",urldecode($str));
    3.     return html_entity_decode($str,null,'UTF-8');;
    4. }
    5. echo utf8_urldecode(json_encode(array("собака"))); // ["\u0441\u043e\u0431\u0430\u043a\u0430"]

    А до JavaScript у меня даже и дело-то не доходит, просто эхом вывожу из PHP. Ведь JSON - строка, ну и пускай, казалось бы, выводит ее нормально...

    А проблема, собственно, в том, что нечитаемо... Если на стороне клиента JS даже нормально понимает такие строки, то
    1. каждый раз вместо 2-х байт на символ, передаем целых 6.
    2. при отладке сложно разбираться с такими вот строками.

    Ну да ладно, утро вечера мудренее, разберемся общими усилиями. :)

    ---
    А вот, собственно, что я уже успел почитать в сети на эту тему:
    http://blgo.ru/blog/2009/02/28/json-encode-suxx/ (json_encode сосёт)
    http://yozhek10nozhek.livejournal.com/5842.html (PHP4, JSON и русский язык)
    http://forum.vingrad.ru/forum/s/c69...0ac0e/topic-218967/anchor-entry1983700/0.html (Проблема с руской кодировкой в функции json_encode)
    http://alexmuz.ru/php-json_encode/ (Реализация json_encode на PHP – русский язык UTF-8)
     
  8. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Подобрал вот такое вот решение:
    PHP:
    1. <?php
    2. function json_fix_cyr($json_str) {
    3.     $cyr_chars = array (
    4.         '\u0430' => 'а', '\u0410' => 'А',
    5.         '\u0431' => 'б', '\u0411' => 'Б',
    6.         '\u0432' => 'в', '\u0412' => 'В',
    7.         '\u0433' => 'г', '\u0413' => 'Г',
    8.         '\u0434' => 'д', '\u0414' => 'Д',
    9.         '\u0435' => 'е', '\u0415' => 'Е',
    10.         '\u0451' => 'ё', '\u0401' => 'Ё',
    11.         '\u0436' => 'ж', '\u0416' => 'Ж',
    12.         '\u0437' => 'з', '\u0417' => 'З',
    13.         '\u0438' => 'и', '\u0418' => 'И',
    14.         '\u0439' => 'й', '\u0419' => 'Й',
    15.         '\u043a' => 'к', '\u041a' => 'К',
    16.         '\u043b' => 'л', '\u041b' => 'Л',
    17.         '\u043c' => 'м', '\u041c' => 'М',
    18.         '\u043d' => 'н', '\u041d' => 'Н',
    19.         '\u043e' => 'о', '\u041e' => 'О',
    20.         '\u043f' => 'п', '\u041f' => 'П',
    21.         '\u0440' => 'р', '\u0420' => 'Р',
    22.         '\u0441' => 'с', '\u0421' => 'С',
    23.         '\u0442' => 'т', '\u0422' => 'Т',
    24.         '\u0443' => 'у', '\u0423' => 'У',
    25.         '\u0444' => 'ф', '\u0424' => 'Ф',
    26.         '\u0445' => 'х', '\u0425' => 'Х',
    27.         '\u0446' => 'ц', '\u0426' => 'Ц',
    28.         '\u0447' => 'ч', '\u0427' => 'Ч',
    29.         '\u0448' => 'ш', '\u0428' => 'Ш',
    30.         '\u0449' => 'щ', '\u0429' => 'Щ',
    31.         '\u044a' => 'ъ', '\u042a' => 'Ъ',
    32.         '\u044b' => 'ы', '\u042b' => 'Ы',
    33.         '\u044c' => 'ь', '\u042c' => 'Ь',
    34.         '\u044d' => 'э', '\u042d' => 'Э',
    35.         '\u044e' => 'ю', '\u042e' => 'Ю',
    36.         '\u044f' => 'я', '\u042f' => 'Я',
    37.  
    38.         '\r' => '',
    39.         '\n' => '<br />',
    40.         '\t' => ''
    41.     );
    42.  
    43.     foreach ($cyr_chars as $cyr_char_key => $cyr_char) {
    44.         $json_str = str_replace($cyr_char_key, $cyr_char, $json_str);
    45.     }
    46.     return $json_str;
    47. }
    48.  
    49. echo json_fix_cyr(json_encode(array("собака","кошка"))); // ["собака","кошка"]
    50. ?>
    Но, блин, неужели подобные решения единственно возможные... вот тебе и JSON, интересно какие еще он может для различных символов подкинуть сюрпризы. Похоже, что $cyr_chars будет расти. Вот уже подумываю вернуться к старому доброму XML. Что посоветуете?
     
  9. Silicium

    Silicium Активный пользователь

    С нами с:
    1 апр 2008
    Сообщения:
    205
    Симпатии:
    0
    Адрес:
    Киев
    FiMka

    Как-то сталкивался...

    Решил аналогично твоему
     
  10. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.553
    Симпатии:
    631
    А если скрипт сохранен не в юникоде, а только данные из формы получает в юникоде? Тогда "А" из кода сркипта не соответствует "А" полученой из формы.
    Конвертируй с помощью iconv.
     
  11. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
  12. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Где работает, как работает? В JavaScript вижу, работает, но я ж написал, что не хочу гонять тучи байт клиенту (для каждого символа вместо 2-ух байт целых шесть передается), это ж JSON, экономия траффика должна быть, а не наоборот, а иначе нафиг он нужен вообще. Так-то и в XML и в обычном тексте работает.

    ЗЫ: прокся на работе режет, похоже, домены .co.cc, а тут еще и "пупсик", короче порадовало :D
     
  13. Simpliest

    Simpliest Активный пользователь

    С нами с:
    24 сен 2009
    Сообщения:
    4.511
    Симпатии:
    2
    Адрес:
    Донецк
    Так, все спичечники свободны.

    Если у тебя не библиотека Мошкова с 3мб голого текста без разметки, то json отлично уменьшает трафик, минимум вдвое. Но он сделан не для компрессии данных.

    Для сжатия надо использовать gzip/mod_deflate
     
  14. FiMka

    FiMka Активный пользователь

    С нами с:
    12 май 2009
    Сообщения:
    66
    Симпатии:
    0
    Адрес:
    Санкт-Петербург
    Нее, у меня, конечно, не Мошковская либа, я просто очень жадный, всё хочется лучше и лучше, но согласитесь все равно косяк...

    А вообще, если даже просто взглянуть на синтаксис формата JSON, то видно, что его разработчики задумывались и о компактности тоже (эти лаконичные скобочки фигурные и квадратные и прочее), но да, добиться краткости не было основной целью.
    Вот еще интересная статья в которой сравниваются форматы XML и JSON http://www.json.org/xml.html. Кстати, название статьи говорит само за себя "JSON - обезжиренный XML" (JSON: The Fat-Free Alternative to XML).

    Короче ситуация в этом отношении понятна. Итог: либо использовать XML, либо накропать собственную версию JSON decoder/encoder. А в моем случае это как раз вариант, т.к. структура передаваемых данных крайне перманента и тагирована.

    Всем спасибо за участие!

    ---
    JSON - reduces traffic twice for plain text, but pushes three times more odd stuff.
     
  15. CrashBang

    CrashBang Новичок

    С нами с:
    27 сен 2015
    Сообщения:
    2
    Симпатии:
    0
    Код (PHP):
    1. <?php
    2.  
    3. function toJson($mixed) {
    4.        return preg_replace_callback(
    5.                 "/\\\\u([a-f0-9]{4})/",
    6.                 function($matches) {
    7.                     return iconv('UCS-4LE','UTF-8',pack('V', hexdec('U' . $matches[0])));
    8.                 },
    9.                 json_encode($mixed)
    10.                 );
    11.     }
     
  16. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.554
    Симпатии:
    1.754
    А что столько проблем-то? Недавно столкнулся с проблемой, когда API не понимает такие вещи в json, почитал документацию по json_encode, и всего-то надо было последним параметром передать JSON_UNESCAPED_UNICODE. https://php.net/json_encode
     
  17. CrashBang

    CrashBang Новичок

    С нами с:
    27 сен 2015
    Сообщения:
    2
    Симпатии:
    0
    Век живи, век учись. Отлично работает Ваш вариант.
     
  18. eaol

    eaol Новичок

    С нами с:
    16 дек 2020
    Сообщения:
    1
    Симпатии:
    0
    Всё намного проще, нужно в функцию передать нужный параметр: json_encode(array('собака'), JSON_UNESCAPED_UNICODE), вот и вся магия :)