Лечим убитую в ноль кодировку
Разгребал вчера неудачный апгрейд 2.3.6 до 3.0.1. Для начала вводная - как запороть свой форум в ноль в процессе обновления:
1) конечно же, не делать бекапа БД,
2) внести до запуска скрипта обновления в conf_global.php строку "$INFO['sql_charset']='utf8';", но не сконвертировать в utf-8 саму базу.
Что произойдет в процессе обновления при таком сценарии:
Скрипт обновления будет брать данные из старых win-1251 таблиц и вносить в бинарном виде в новые таблицы utf-8. В результате мы получим всю админку в таких вот строках:
(82, 'Показывать версию IPB?', '', 8, 'yes_no', 'ipb_display_version', '', '1', '', '', 1, 38, '', 0, 1, ''), (83, 'Отключить возможность анонимной авторизации?', 'Если опция включена, то пользователи не увидят опцию "Скрытность" в форме входа.', 8, 'yes_no', 'disable_anonymous', '', '0', '', '', 1, 39, '', 0, 1, ''), (84, 'Отключить возможность администраторам видеть анонимных пользователей на форуме?', '', 8, 'yes_no', 'disable_admin_anon', '', '0', '', '', 1, 40, '', 0, 1, ''),
Это уникальнейший образец клинописи - мы имеем в БД поля типа utf-8, в которых хранятся однобайтовые win-1251 символы. Как это раскодировать? Да почти никак! При любой попытке извлечь данные, MySQL формирует на выходе совершенно покореженные последовательности, обратной трансофрмации почти не поддающиеся. iconv from cp-1251 to utf-8 над дампом оставляет все в таком же виде, а если добавить параметр "игнорировать неверные последовательности" (-c), то обрезает строки до первого включения букв "и", "ш" и проч. Штирлиц из windows, равно как и многочисленные онлайн-конвертеры, также пасуют. Попытка сменить типы полей также ничего не дает, т.к. в процессе смены типа MySQL "декодирует" все в кашу прямо на лету.
Единственный разумный выход в таком случае - откатиться к бекапу, сначала сконвертировать базу, а затем уже запустить скрипт обновления. А если бекапа нет?
Почти 2 часа поисков привели к ответу. Вот запрос, который может извлечь оригинальные данные из этой мешанины:
SELECT CONVERT(CONVERT(CONVERT(field USING cp1251) USING binary) USING utf8) FROM table
Чуть изменив его, можно за один заход выполнить "починку" одного поля:
UPDATE table SET filed = CONVERT(CONVERT(CONVERT(field USING cp1251) USING binary) USING utf8)
А теперь вспомните, сколько у нас полей и в каком количестве таблиц Тщательный проход по всем таблицам с русскими покореженными буквами (их более 10) для каждого поля я оставляю за вами. Иммет смысл хотя бы теперь сделать бекап - т.к. одна ошибка - например, два раза запустить скрипт на одном столбце - и все снова превратится в кашу.
Кстати, что-то можно и не обновлять, а взять в виде дампа из установленного на локали чистого форума (это касается приложений, настроек, групп настроек, репутаций, языковой и некоторых других таблиц).
После этой работы, сброса всех кэшей и перепрочтения данных в шаблоны из xml-lang-файла все засияет красивыми русскими буквами.
4 комментария
Рекомендуемые комментарии