Составлено с бесценной помощью Алексея 'huNTer' Колосова
В ближайшее время перекочует куда-нибудь в более подходящее для совместного редактирования место.
Если что-либо из указанного здесь не работает -- обязательно оставьте об этом сообщение в комментариях. Любые замечания и исправления приветствуются (не забудьте сообщить платформу и версию PHP). Все нижеописанное действует для PHP 4.
Строковые функции
Новость плохая - стандартные “строковые” функции PHP как следует с UTF не работают. Новость получше - в PHP есть сделанный (конечно же японцами) модуль, который не является обязательным, но при этом реализует все необходимые функции сам (дублируя строковые функции своими с префиксом mb_). Новость совсем хорошая - все строковые функции PHP можно заменить их эквивалентами из mbstring, причем ваши скрипты, использующие строковые функции PHP, даже догадываться об этом не будут.
Для этого есть конфигурационная директива
mbstring.func\_overload
причем применять ее можно не только в корневом php.ini, но и (сюрприз) в вашем .htaccess. Следовательно -- сначала проверяем по php_info, есть ли в комплекте сборки вашей версии PHP расширение mbstring. Возможно три варианта
- Ваш хостер не дает вам посмотреть php_info. Купить монтировку (она же, если пользоваться ЖЖ-терминологией, Титановый ЛомЪ) и умело ее применить. Бейте аккуратно, но сильно.
- Оного модуля в комплекте нет -- пишите письмо админу и слезно просите собрать. Ссылку на этот текст можете приложить в комплекте.
- Модуль есть, все в порядке.
Если результат - пункт 3, в наш магический .htaccess нужно прописать перегрузку стандартных строковых функций их версиями из расширения mb (эта перегрузка будет действовать не только на ваши скрипты, а вообще на все, исполняемое PHP-модулем внутри вашей веб-директории).
Однако - поддержка этой перегрузки различается от версии к версии PHP. Например в следующей конфигурации:
Apache v1.3.33-4, PHP v4.3.10-7, Debian GNU/Linux Sid.
не срабатывает mb_substr и перегрузка функций происходит неверно.
У меня на сервере
Apache/1.3.33, PHP v4.3.9, GNU/Linux i686
и на лаптопе
Apache 2, PHP v4.3.9, RELEASE_PPC Power Macintosh
работает вполне. Говоря кратко - надо проверять.
На случай, если mbstring не установлен (или вы не уверены, что в место него не придется использовать iconv), можно иметь (если ваша PHP-система большая) свои функции-обертки или пользоваться простым substr в расчете на то, что на системе, где скрипты будут развертываться, mb_string установлен (и поставлять рекомендации в пакете с системой, что дескать “If you need multibyte support you will need mbstring extension for PHP installed”).
На большинстве западных хостингов данное расширение присутствует, оно является включенным по умолчанию в сегодняшних дистрибутивах PHP 4.
Как настраивать mbstring
Опытным путем выявлена конфигурация Apache+PHP для адекватной реакции на UTF-8:
# unicode support
AddDefaultCharset utf-8
<IfModule mod_charset.c>
CharsetDIsable on
CharsetRecodeMultipartForms Off
</IfModule>
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
Добавить в .htaccess.
Имейте в виду, что если вы делаете раскодирование поступающих по POST или GET данных самостоятельно (это включает получение данных с помощью веб-сервисов вроде SOAP и XML-RPC) - encoding translation включать не надо.
Все скрипты, содержащие юникодные символы (то есть любые русские строковые литералы) следует отконвертировать в UTF-8, иначе у парсера PHP случится мягкий психоз. Нужная кодировка для скриптов - UTF-8, без BOM (byte order marker). Оный маркер превратится в браузерах в очень странный символ “неизвестный глиф” (похожий на вопросительный знак в ромбе), который мало того что будет появляться в браузере, но и будет выводиться перед вашими заголовками (поскольку оный маркер превратится в символ, попадающий в вывод ДО того как выполнится что-бы то ни было внутри PHP-блока.
Содержать скрипты в старой восьмибайтовой кодировке, выводя их в UTF-8 - абсурд.
Регулярные выражения
Еще одна плохая новость. Есть одна область PHP, которая к юникоду крайне чувствительна - это Perl-compatible regular expressions. Если, например, удобный formatter для написан без расчета на совместимость UTF, скорее всего такой форматтер с вашими текстами не заработает.
Если вы переводите на UTF уже написанный движок, первый источник ошибок следует искать там, где применяются регулярные выражения. Чаще всего в результате, например, неудачного preg_replace, результатом его работы становится нуль-строка. Когда эта нуль-строка попадает в базу в SQL-команде база наверняка выдаст вам ошибку ввода. Если все будет удачно, в небольшом скрипте вам придется произвести 5-10 хирургических замен, после чего все станет нормально.
preg_ при использовании с UTF-8 становится регистрозависимым. Причем только с кириллицей. Ключ /i игнорируется. Против этого помогает дополнительный ключ /u. Имейте в виду, что расширение mbstring на движок PCRE не повлияет (только на POSIX regular expressions, то есть на ereg_).
Другие функции
Все функции, рассчитанные на XML (DOM и SAX-парсер) настраиваются на UTF-8 согласно документации и дальнейших телодвижений не требуют, большинство общепринятых библиотек для PHP (типа PEAR и ADODB) чаще всего работают с UTF “из коробки”. То же относится к чтению/записи файлов и выводу в SDTOUT - если ваша консоль/терминал настроена на UTF-8 локаль проблем быть не должно.
Как проверить
Отконвертируйте все скрипты со строковыми литералами в UTF-8. Точно так же поступите с дампом базы. Перезалейте дамп, сотрите все кеш-файлы (если ваша система кеширует что-бы то ни было).
И посмотрите что получится. Если система сопрягается с другими (через web-сервисы, XML, отправку HTTP-запросов и т.д.) испытайте эту функциональность (желательно набором unit-тестов, если они у вас есть).
Введите во все текстовые поля слово Iñtërnâtiônàlizætiøn, поищите его встроенным механизмом поиска. Обязательно проверьте, как ведет себя Javascript (особенно если он должен кодировать строки для отправки серверу или делать поиск-замену в текстовых полях).
Старайтесь, чтобы был способ хранить в системе данные о том, в какой кодировке она в данный момент работает. Если вы пишете CMS - установите “контракт”, что кодировка прописывается в файле настроек или выбирается пользователем, храните эту кодировку в переменной или константе. Отправляйте ее в HTTP-заголовках и в meta-теге документов. Когда требуется сгенерировать что-либо для обмена с внешним миром (отправить из скрипта e-mail, trackback ping, использовать чужой веб-сервис) считывайте эту настройку и конвертируйте все строки в UTF-8 автоматически, опираясь на нее. Перед отправкой данных по HTTP всегда приписывайте charset в конце заголовка Content-type (чтобы сделать это для отправляемых форм пропишите им accept-charset).
И наконец
Требуйте Unicode-совместимость у ближайшего к вам PHP-разработчика. Стучите ему в таз, батарею и тумбочку, пишите внятные багрепорты, помогайте и ассистируйте. И дайте ему ссылку сюда - вдруг пригодится.
Более подробное объяснение как заставить PHP работать с Юникодом можно найти на соответствующей странице WACT.
What others said
huNTer
эээ... huNTer!!! это принципиально :)
kukutz
К сожалению, ни слова о mysql и печальной совместной жизни mysql < 4.1, FTS и Unicode.
Julik
Во-первых, про MySQL должен быть отдельный рассказ.
Во-вторых, все мои проекты (кроме этого блога) уже года два сидят на Postgres, где ситуация несколько более прозрачна, поэтому с MySQL я уже довольно давно не имел опыта.
Если есть желание - помогите с написанием ;-)
huNTer
Написал облегченный вариант typografic'и. Раземеется не полный, но все лучше чем ничего.
Julik
Так опубликовал бы!
Slach
мы тут тоже пробовали мигрировать с MySQL4.0.x на MySQL4.1.x и utf8
сначала девелоперские тестовые серваки под win32 потом тестинг сервер под Debian и скоро вот думает подымать продакшен сервер на mysql4.1
нахватались всякого под win32 я попробовал накопленный опыт выразить вот тут http://phpclub.ru/talk/showthread.php?s=&threadid=67767
Julik
На Win32 я принципиально не работаю :-) а с MySQL 4.1 у меня все обстоит вполне шоколадно (на линуксах/макосях) - просто вызываю SET NAMES UTF8 при установке соединения с базой. Естественно для хостера такой вариант не подойдет, но мне - более чем.
Ну и плюс - да, настроить дефолтные чарсеты и collation нужно (чтобы таблицы создавались с правильным чарсетом.
Slach
Уважаемый Julik, не подскажете случайно чего нибудь полезного вот по этому поводу http://www.livejournal.com/users/slach/187305.html ?
Slach
Уважаемый Julik, не подскажете случайно чего нибудь полезного вот по этому поводу http://www.livejournal.com/users/slach/187305.html ?
Julik
Увы, нет - а времени сейчас разбираться нету. Анимировать надо - экзамены идут :-)
Nigadiay
Julk, я какзаз разбирался сейчас с юникодом плюс пхп. Очень полезная статья, спасибо. Но вот у меня такая проблема: при созранении файлов в кодировке utf-8 все равно какая-то гадость сохраняется в начале файла. Хотя сохраняю без БОМ. И конечно же случается та страшная проблема с заголовками. Может я плохо сохраняю? В чем может быть проблема, не подскажешь?
Julik
smenite tekstovii redaktor kotorim vi polzuetes
shamanStillSir
Спасибо большое. Неимоверно помогло.
rin-nas
Набор PHP функций для разработчиков веб-сайтов, использующих кодировку UTF-8 http://forum.dklab.ru/viewtopic.php?t=17146