В помощь вебмастеру: Linux bash скрипт для перевода сайта на новую кодировку

    «Лучше день потерять, потом за час долететь» © Крылья, ноги, хвост

    Не так давно мне «посчастливилось» перевести веб сайт средних размеров из одной кодировки в другую. Если быть точнее из windows-1251 на 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, если такое позволительно.

    Помните!!! Подходите к таким переводам серьезно, сперва выполняя их на параллельной версии сайта и тестируйте, тестируйте, тестируйте.

    Удачных переводов!

    Источник: Записки под рукой
    Поделиться публикацией

    Похожие публикации

    Комментарии 26

      0
      ух ты, спасибо!
        +1
        Хорошо бы предупредить людей, которые всё это будут творить что
        1. В базе данных могут случиться всякие .gif и .jpg (аватары, скажем), которые после конвертировани из windows-1251 в utf-8 сломаются (впрочем это редкость)
        2. Почти 100% гарантия того, что где-нибудь в PHP-коде есть неявное предположение: 1 символ == 2 байт, так что сайт нужно после конвертации долго тестировать (не забудьте редко используемые части типа регистрации на сайте и высылки письма с паролем!)
          0
          1. Спасибо, пердупредим :)
          2. Насчет тестирования очень верно - неприятные моменты все-равно будут - гарантированно. Тестить обязательно!
            0
            Не стоит забывать что код php нужно будет перепроверять!
            Функции работы с строками должны быть заменены на их multibyte-аналоги.
            Например strlen - покажет неверное кол-во символов строки, содержащей UTF-8,
            а mb_strlen - посчитает верно.
            0
            Мне ненадо, но спасибо за труды все равно, вдруг понадобится.
            • НЛО прилетело и опубликовало эту надпись здесь
                0
                Спасибо за поправки, учел.
                Еще знающие люди посоветовали:

                " 4m@t!c комментирует...

                Достаточно одного запроса "SET NAMES utf-8", которая в том числе изменит CHARSET
                Не обязательно конвертировать дампы iconv. мжно сделать это с помощью ALTER TABLE tbl_name CONVERT TO CHARACTER SET charset_name;
                "
                  0
                  Замечание про ALTER TABLE - правильное и неправильное одновременно. Оно блокирует базу всё равно, а backup'а у вас не остаётся. Хотя всё зависит от конкретной ситуации, конечно...
                    0
                    поэтому в статье есть ремарка: "...сделать это на тестируемой БД"
                    0
                    А что делает ключ -a в команде cp?
                    В cp на FreeBSD такого ключа нет, насколько я нагуглил сейчас - в linux тоже..
                      0
                      -a, --archive
                    0
                    -regextype posix-extended пришлось выкинуть совсем и сделать через grep (для большей совместимости с ранними версиями), в связи с чем сам скрипт существенно изменился.
                    Не могли бы Вы подсказать будет ли он теперь работать в FreeBSD?
                    0
                    А кодировку отдачи можно и в .htaccess задать:
                    AddDefaultCharset UTF-8
                      0
                      Да, то-же вариант, но если есть доступ к конфигурации лучше это сделать там. Т.к. плодить .htaccess, который будет "выдергиваться" при каждом запросе, помоему не очень хорошо.
                        0
                        Просто не всегда есть доступ к конфигу. Особенно на дешевом хостинге. А еще бывают случаи, когда необходиом назначить кодировку «локально», для одной папочки :) Вот буквально вчера родилась такая необходимость. И другого варианта на серваке клиента предусмотреть было невозможно :)
                      +1
                      > iconv: недопустимая входная последовательность в позиции 1663
                      у iconv есть специальная опция "-c" для пропуска подобных символов
                        0
                        man iconv
                        Хм-м, что-то на Fedora 7 я невижу такой опции :(
                          0
                          у меня тоже Fedora 7:
                          $ rpm -qf `which iconv`
                          glibc-common-2.6-3
                          $ iconv -V
                          iconv (GNU libc) 2.6
                          $ iconv --help
                          ...
                          Output control:
                          -c omit invalid characters from output

                          а в мане iconv как раз неполно описан
                            0
                            Спасибо, опция действительно работает
                        0
                        Всё же, насколько я помню, в оригинале «Лучше день потерять, потом за 5 минут долететь». ;-)
                          0
                          Значит я уже забывать стал :(
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            а сайт уже функционирует на мастдае или ето только тестовая его версия?
                            • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            а для ms windows есть какой-нибуть софт для перекодировки между cp-1251 & utf-8? желательно туда и обратно. может кто-то встречалса из таким... просто заказчик настоятельно хочет, чтоб его сайт в cp1251 виводилса... а я начал делать на unicode...
                            • НЛО прилетело и опубликовало эту надпись здесь

                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                              Самое читаемое