Шукати в цьому блозі

середа, 14 вересня 2011 р.

Latin1 -> KOI8-U -> UTF8

В общем столкнулся давеча с такой ситуацией. Долго и нудно использовалось на работе приложение в котором составлялись заявки на аварии ну и сохранялись в базе MySQL.
Как-то не приходилось обращать внимания в какой кодировке, где, как и что хранится, а тут задумал переписать приложение, при этом захотелось задействовать ExtJS. Ну то, что этот фреймворк для отображения русского текста использует UTF8 нисколько не останавливало, в конце-концов в том-же PHP есть поддержка замечательного функционала iconv (не говоря уже о том, что iconv есть в Linux). И вот в этом месте поджидала необычная засада…
Таблица в базе была создана в кодировке Latin1, но данные в неё сохранялись из KOI8-U. Помимо всего прочего ситуация усугублялась тем, что системная локаль выставлена в UTF8. Простая смена через ALTER TABLE кодировки полей (или для всей таблицы) к успеху не приводила так как при этом выполнялось дополнительное преобразование кодировки, которое в общем-то делать было не к чему - данные и без того в KOI8.
Первое что пришло на ум это слить таблицу через mysqldump, затем конвертануть всё, что понадобится через iconv, через sed поменять описание для CHARSET и слить таблицу обратно. Но тут опять наметился геморой с двойной-тройной перекодировкой… короче чёрт ногу мог сломать быстрее нежели в этом всём разобраться. Данный путь был быстренько признан тупиковым.
Что же оставалось делать? На выручку пришло поле типа BLOB :)
Итак, пошагово. Заходим в mysql и делаем следующее:


  • Устанавливаем текущую кодировку для таблицы:
    SET NAMES LATIN1;
  • Создаём новую таблицу с использованием структуры старой:
    CREATE TABLE new LIKE old;
  • Сохраняем все записи старой таблицы в новую:
    INSERT INTO new SELECT * FROM old;
  • Меняем кодировку на текущую системную:
    SET NAMES UTF8;
  • Затем для каждого текстового поля (char, varchar и т.п.) было проделано подобное преобразование:
    ALTER TABLE new CHANGE field field BLOB;
    ALTER TABLE new CHANGE field field varchar(64) CHARACTER SET koi8u;

Безусловно, что цифровые, перечисляемые и другие типы полей подобной конвертации не подлежат.
Собственно после столь незначительных усилий таблица new стала содержать все данные из таблицы old только в правильной KOI8-U кодировке, вместо Latin1. Осталось подменить старую таблицу на новую:
  • RENAME TABLE old TO bak, new TO old;
В старые php-скрипты была добавлена инструкция mysql_query('SET NAMES KOI8U') и всё стало на свои места: пока ещё не написан полностью новый функционал - вполне корректно продолжили работать старые скрипты, а в новых, перед использованием json_encode текстовые поля из koi8-u приходится просто перекодировать в utf8 при помощи замечательной функции iconv ;)

Есть вероятность, что из BLOB можно было бы "вытащить" данные в UTF8, но пока мне это просто не нужно, так как старый функционал всё-таки заточен под KOI8-U.

Немає коментарів: