Переводим сайт на UTF-8
"Лучше день потерять, потом за час долететь" © Крылья, ноги, хвост
Не так давно мне "посчастливилось" перевести веб сайт средних размеров из одной кодировки в другую. Если быть точнее из windows-1251 на UTF-8. Потом еще один - побольше, на третьем я сломался, и следуя верному принципу вышесказанного мне пришлось потерять кучку времени на написание скрипта по автоматизации этого процесса, но зато потом, за час я все-таки долетел.
Прежде чем приступить к самому скрипту, хотелось бы описать мои подходы к данной проблеме и особенности решения. Естественно я использовал любимый командный интерпретатор bash в среде Linux.
Из особенностей работы скрипта можно отметить следующее:
- Сохранение исходных данных
- Копирование файлов и папок с символами пробела (whitespace)
- Сохранение атрибутов файлов и директорий (владельцы, режим доступа)
- Замена meta charset= на необходимую кодовую страницу в требуемых файлах по маске
- Настраиваемые параметры скрипта
Что-бы понять работу, выполняемую скриптом, привожу алгоритм обработки файлов:
- Вычищаем целевую директорию
- Копируем в нее без изменения все содержимое исходной папки
- Удаляем из целевой папки по маске все файлы, которые в дальнейшем будут перекодированы
- Конвертируем требуемые файлы из исходной папки в целевую, восстанавливая при этом их атрибуты
- Меняем в сконвертированных файлах строки содержащие charset=windows-1251 на charset=UTF-8 (как пример для моего случая, но параметры могут быть легко изменены)
Настраиваемые параметры скрипта следующие:
Исходные параметры:
SDIR="/usr/local/apache2/htdocs/site.ru/" - исходная директория сайта с символом слеша / в конце
SCP="CP1251" - исходная (from) кодовая страница для iconv
EXT=".*.(htm[l]*|php[3]*|js|css)$" - расширения файлов для перекодировки (здесь будут задействованы такие как .htm, .html, .php, .php3, .js, .css)
FCS="windows-1251" - название исходной кодовой страницы для замены мета charset= в файлах
Целевые параметры:
DROP_STRUCT=true - принимает значения false, true, регулируя условие: должна ли при старте вычищаться целевая директория
DDIR="/usr/local/apache2/htdocs/new.site.ru/" - целевая директория сайта с символом слеша / в конце (должна существовать)
DCP="UTF-8" - целевая (to) кодовая страница для iconv
TCS="UTF-8" - название целевой кодовой страницы для замены мета charset= в файлах
А вот собственно и сам скрипт:
#!/bin/bash
# --- CONFIG SECTION ---
# Source Dir's params
SDIR="/usr/local/apache2/htdocs/site.ru/" # with slash '/' in the end
SCP="CP1251" # codepage for 'iconv'
EXT=".*\.(htm[l]*|php[3]*|js|css)$" #files extensions for coding
FCS="windows-1251" # charset for replace
# Destination Dir's params
DROP_STRUCT=true # false, true
DDIR="/usr/local/apache2/htdocs/new.site.ru/" # with slash '/' in the end
DCP="UTF-8" # codepage for 'iconv'
TCS="UTF-8" # new charset
# --- END CONFIG SECTION ---
# Drop structure
#
if $DROP_STRUCT
then
rm -dfr $DDIR*
fi
# Make new copy
#
cp -aR $SDIR* $DDIR
# Flush miscoded files
#
find $DDIR -type f | grep -E "$EXT" | xargs -i rm -f {}
# Convert From To
#
find $SDIR -type f | grep -E "$EXT" | sed "s#$SDIR##" | xargs -i echo {} | \
while read f
do
iconv -c -f $SCP -t $DCP -o "$DDIR$f" "$SDIR$f"
# Revert MODE & OWNER
chmod `find "$SDIR$f" -maxdepth 0 -printf "%m"` "$DDIR$f"
chown `find "$SDIR$f" -maxdepth 0 -printf "%u:%g"` "$DDIR$f"
# Replace strings
perl -pi -e "s#content\s*\=\s*[\"'].*?charset\s*=\s*$FCS.*?[\"']#content=\"text/html; charset=$TCS\"#g" "$DDIR$f"
done
А теперь, еще несколько полезных моментов.
1. Возможно даже после перекодировки в UTF-8 и замены meta content на charset=UTF-8 Вы все равно видите абракадабру или не то, что хотелось бы. Здесь все дело в том, что для нового сайта в UTF-8 необходимо заменить параметр default_charset для самого PHP, т.к. в глобальных переменных он явно установлен для другой кодовой страницы (windows-1251). Я делаю это в настройках виртуального хоста (httpd.conf) через:
php_admin_value default_charset UTF-8
2. Как правило, сейчас любой сайт хочет базы данных, которые Вам то-же надо будет перевести в UTF-8. Особого труда это не составляет, если под рукой есть phpMyAdmin или mysqldump, на крайний случай, для гиганских БД, наверняка придется писать скрипт конвертации и временно приостанавливать сервис. Простота идеи должна быть понятна: делаем дамп БД, перекодируем его с помощью того-же iconv и заменяем все, что связано с кодовыми страницами на желаемые данные, заливаем все в новую БД.
Еще более правильный вариант предложенный 4m@t!c сделать это на тестируемой БД с помощью ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
С БД так-же может вылезти небольшая абракадабра, проявляющаяся в некорректном отображении русских 'ш' 'И'. Здесь также сыграет с нами шутку дефолтная кодовая страница для MySQL. Для устранения этой проблемы, после подключения к БД, Вам придется добавить в код Вашего сайта следующие строки:
mysql_query("SET NAMES 'utf8'");
Либо поменять default-character-set и default-collation для MySQL, если такое позволительно.
Помните!!! Подходите к таким переводам серьезно, сперва выполняя их на параллельной версии сайта и тестируйте, тестируйте, тестируйте.
Удачных переводов!
Добавлено:
Умные люди на Хабре и среди моих читателей дали очень дельные советы, за что им огромное спасибо. В связи с этим статья намного улучшилась.
Достаточно одного запроса «SET NAMES utf-8», которая в том числе изменит CHARSET
Не обязательно конвертировать дампы iconv. мжно сделать это с помощью ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
Огромное спасибо, я этого не знал (насчет ALTER CONVERT).
Тогда алгоритм смены БД меняется:
сперва делается копия существующей, а затем на ней делается ALTER CONVERT.
Еще раз спасибо :)
Читал-читал и осознал собственное несовершенство. Хороший ресурс.
а если на сервере не поддерживается функция
#php_value mbstring.func_overload 7
#php_value default_charset UTF-8
#php_value mbstring.language Russian
#php_value mbstring.internal_encoding UTF-8
#php_flag mbstring.encoding_translation on
#php_value mbstring.http_input “UTF-8,KOI8-R,CP1251”
#php_value mbstring.http_output UTF-8
#php_value mbstring.detect_order “UTF-8,KOI8-R,CP1251”
# end
что делать?
Тогда все аккуратно делать ручками в коде, или менять хостинг (сервер)
Хм… Все переходят на UTF-8, а я чуть было не начал переводить некоторые свои сайты с UTF-8 в 1251 :) И все ради экономии на длине текста, ведь UTF-8 занимает больше места. Но в итоге победил здравый смысл)
Есть один очень простой и эффективный способ перевода в кодировку utf-8.
Первое: заменяем во всех файлах charset=windows-1251 на charset=uft-8.
Вотрое: в папке, где хранятся ваши файлы, которые вы будете заливать на сервер, создаём папку с названием «utf-8».
Далее копируем туда из основной папки все файлы.
Теперь каждый скопированный в папку «utf-8» файл открываем в «блокноте» и сохраняем его в кодировке utf-8.
Всё!
Перекодированные файлы готовы к заливке на сервер!
Вот ещё, рекомендую: Здесь описывается текстовый редактор с перекодировкой в UTF-8 и даётся ссылка на загрузку.
Всем удач!
На правах админа немного видоизменил Ваш комментарий
А на хрена?
В какой кодировке нравится в той и пишите.
Преиущества utf-8 весьма спорны (несколько дополнительных символов), а гимор зачастую велик.
Если Вас устраивает то, в чем вы сейчас пишете, в том и пишите.
Не заморачивайтесь.
Даже по коментам здесь — видно charset=windows-1251 рулит везде без проблемм, а с utf-8 вечные глюки и лишняя работа.
на хрена:
— мультиязычный сайт (или: попробуйте показать свой сайт-визитку на windows-1251 зарубежному партнеру)
— активное использование ajax и фреймворков (без костыльков)
— отход от архаизмов и переход на современные стандарты (если только вы не узколобая бабушка с кругозором в рамках местной деревни)
— нахрен не надо, если вы не заморачиваетесь пунктами указанными выше
Все споры о UTF-8 и с1251 не те и не о том.
Самое главное отличие — это отображение одних и тех же шрифтов. То, что красиво в UTF-8 -в 1251 выглядит ужасно!!!
В 1251 большинство шрифтов отображается криво.
И почему-то про это не кто ни где не упоминает.