Промяна на енкодинга на сайт към UTF-8 (част 1)

Преминаване на сайт към UTF-8 енкодинг

Това е публикация за програмисти, описваща решаването на реален проблем.

Наскоро ми се наложи да прехвърля стар сайт форум, написан на PHP и mySQL база данни към нов хостинг. Старият сайт беше унищожен от ненадежден хостинг доставчик, който освен базите данни беше затрил и архивните копия на множество сайтове. За щастие имах на моя компютър файловете на сайта и старо копие на базата данни. Всички съвременни хостинги по подрабиране ползват кодиране UTF-8, което осигурява безпроблемно показване на кирилицата. Моят архив с таблици на базата данни беше един текстов .sql файл, който поради спецификата на стария хостинг беше в странен енкодинг, който вместо символи на кирилица съдържаше символи като: Ãëàñóâàé

Ползвам два от най-големите хостинг доставчика в България и първо се обърнах към поддръжката на единия, след това към другия, но и двата казаха, че не могат да помогнат, защото още при експорта на данните е допусната грешка. Аз обаче продължих да опитвам и да чета кодирани текстове, които помня по памет. Например форум подписи на потребители и скоро видях, че за всеки български символ отговаря точно един от тези странните с вълнички и точки отгоре. Например:


ãóãúë îïòèìèçèðàíå - ëåñíî îòêðèâàíå íà âàøèÿ ñàéò
гугъл оптимизиране - лесно откриване на вашия сайт

æèâîòúò, âñåëåíàòà è âñè÷êî îñòàíàëî
животът, вселената и всичко останало

Това беше добър знак, защото означава, че при това кодиране няма загуба да данни. Скоро открих, че кодирането е  ASCII extended character sets -  ISO_8859-1 (или ISO Latin 1).

Промяна на енкодинга на файл

Под Linux има команда iconv с която лесно се променя енкодинга на файл. Например:

iconv -f cp1251 -t utf8 db.sql > db-new.sql

От файла db.sql в CP1251 енкодинг създава нов файл db-new.sql в UTF-8 енкодинг.

Това е чудесно, но при мен не сработи и получавах грешки като:

iconv: illegal input sequence at position 114

Тази грешка показва, че iconv стига да символ, който не може да разбере и спира там. Има опция -c  с която може да се укаже на програмата да игнорира непознатите символи и да продължава до края на файла.

Това при мен не сработи и влоши нещата - изчезнаха големи части от файла.

Проверката на енкодинга на файла под Linux става с команда:

file -i db.sql

Започнах да гледам подробно данните. Текстовия .sql файл, който съдържа всичките таблици и данни беше около 270MB, което е предизвикателство за много текстови редактори. Под Linux е препоръчително да се отварят подобни файлове от конзолата с команда less. Например:

less db.sql

Тя се справя с лекота с огромни текстови файлове дори при бързо превъртане или търсене напред. Има забавяне само при бързо връщане назад в текста.

С програмата less разбрах какъв е проблема - имаше смесено кодиране. Някои от таблиците на базата данни са били в cp1251 кодиране, други в latin1. Ето защо не сработваше iconv, както и други подобни програми, с които пробвах.

И тогава ми дойде хитрата идея (и вероятно единствено възможна) да направя съпоставяща таблица на символите. Трябваше за всяка буква на килилица, малка и голяма да намеря съответната буква от .sql файла. Тогава ще заменя всеки странен символ със съответния на кирилица, като по този начин ще сменя само буквите с кодиране Latin1 без да засегна буквите в cp1251. След което остава да премина към UTF8.

Използвах таблицата тук http://cstein.kings.cam.ac.uk/~chris/shtools/xterm/charsets.utf8.txt

В първата табличка последните 4 реда са главните и малките букви на кирилица, които присъстват в моя .sql файл.

Направих съпоставяща таблица и създадох нов файл със заместени символи. И разбира се, не стана от първия път. Потърсих къде греша и тази таблица http://unicode-table.com/en/sections/cyrillic/ ме подсети, че има няколко допълнителни букви на кирилица от руската азбука, които трябва да прескоча в съпоставящата таблица. Накрая стигнах до:

sed 's/À/А/g
s/Á/Б/g
s/Â/В/g
s/Ã/Г/g
s/Ä/Д/g
s/Å/Е/g
s/Æ/Ж/g
s/Ç/З/g
s/È/И/g
s/É/Й/g
s/Ê/К/g
s/Ë/Л/g
s/Ì/М/g
s/Í/Н/g
s/Î/О/g
s/Ï/П/g
s/Ð/Р/g
s/Ñ/С/g
s/Ò/Т/g
s/Ó/У/g
s/Ô/Ф/g
s/Õ/Х/g
s/Ö/Ц/g
s/×/Ч/g
s/Ø/Ш/g
s/Ù/Щ/g
s/Ú/Ъ/g
s/Ü/Ь/g
s/Þ/Ю/g
s/ß/Я/g
s/à/а/g
s/á/б/g
s/â/в/g
s/ã/г/g
s/ä/д/g
s/å/е/g
s/æ/ж/g
s/ç/з/g
s/è/и/g
s/é/й/g
s/ê/к/g
s/ë/л/g
s/ì/м/g
s/í/н/g
s/î/о/g
s/ï/п/g
s/ð/р/g
s/ñ/с/g
s/ò/т/g
s/ó/у/g
s/ô/ф/g
s/õ/х/g
s/ö/ц/g
s/÷/ч/g
s/ø/ш/g
s/ù/щ/g
s/ú/ъ/g
s/ý/ь/g
s/þ/ю/g
s/ÿ/я/g' db.sql > db-new.sql

Тази чудна команда на Linux от команден ред, замества всеки от символите след s/ със съответния символ пред /g във файла db.sql при това с много добра бързина. Резултатът се записва във файла db-new.sql.

Отворих файла db-new.sql и всичко изглеждаше наред - базата беше спасена! Побързах да се похваля във Facebook групата Програмисти 🙂 Не знаех, че ме чака още доста работа 😉

Създаване на UTF8 база данни

За да бъде всичко наред с кирилицата, включително и сортиране по азбучен ред е нужно всичко в mySQL базата да бъде UTF8. Започва се от създаване на нова база с колация utf8_bin и всяка таблица трябва да бъде в колация  utf8_bin. Важно е да се отбележи, че ако базата при създаването не е била в тази колация и я промениш след като вече има в нея таблица, обикновено това няма да помогне. Дефинициите на таблиците трябва да завършват на  ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

За съжаление при мен в .sql файла имаше таблици с различно кодиране и затова трябваше да бъдат променени.

Освен таблиците, всяка колона която съдържа кирилица трябва да има колация utf8_bin или utf8_general_ci.

Разликата между двете е, че utf8_bin сравнява символите като двоични данни и се ползва, когато искаме да различаваме малки и големи букви при сортиране и сравнение.

Ако ползваме utf8_general_ci, то при търсене в таблицата на 'Вада', ще излизат резултати като 'Вада', 'вада', 'ВАДА', 'ВаДа' и т.н. Затова най-често се ползва utf8_bin и за текстовите колони:

`name` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',

Ето защо аз трябваше да направя още редица замествания в .sql файла, за промяна на всички дефиниции на таблиците:


sed 's/CHARSET=latin1/CHARSET=utf8/g
s/CHARSET=cp1251 COLLATE=cp1251_general_cs/CHARSET=utf8 COLLATE=utf8_bin/g
s/CHARSET=cp1251 COLLATE=cp1251_general_ci/CHARSET=utf8 COLLATE=utf8_bin/g
s/CHARSET=cp1251 COLLATE=cp1251_bulgarian_ci/CHARSET=utf8 COLLATE=utf8_bin/g
s/character set latin1/character set utf8/g
s/CHARACTER SET latin1/character set utf8/g
s/collate latin1_bin/collate utf8_bin/g
s/COLLATE latin1_bin/collate utf8_bin/g
s/collate cp1251_bulgarian_ci/collate utf8_bin/g
s/collate cp1251_bulgarian_cs/collate utf8_bin/g
s/collate cp1251_general_cs/collate utf8_bin/g
' db-new.sql > db-utf8.sql

Тук вече във файл db-utf8.sql има описания на таблици и данни, които са в UTF-8. Самият файл db-utf8.sql също е в кодиране UTF-8. И новата база данни е създадена с колация UTF-8. Остава да се импортне файла в базата. Разбира се отново имаше проблем 😉 Той беше с големината на файла от около 270MB. Повечето хостинг доставчици имат ограничение от 50MB файл за импорт.

.

Следва продължение... (абонирай се за публикации от SEO блога)

Продължава в Промяна на енкодинга на сайт към UTF-8 (част 2)

Прочетена:11919
1 - лоша2 - слаба3 - средна4 - добра5 - отлична (4 гласа, оценка: 5,00 от 5. Моля изберете оценка!)
Loading...
Георги Стефанов
Магистър по информатика, който се занимава с компютри от 1988 г., професионално с програмиране от 1998 г., а с уеб технологии от 2002 г. Има богат опит при оптимизиране на бизнес сайтове. Повече от 15 години развива успешно свои уеб проекти и работи с български и международни компании за постоянно подобряване на техните сайтове и увеличаване на онлайн продажбите. 
споделиха
linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram