Юникод. Оно вам надо?

Поговорим о кодировке Unicode. Главным ее преимуществом (в общем-то и единственным) является возможность отображать на веб-странице более ста тысяч различных символов не используя при этом html-сущности, наподобие  . Если вы делаете сайт с поддержкой нескольких языков: немецкого, французского, испанского..., это становится особенно актуальным.

В текущей версии php, к сожалению, нет нормальной поддержки Юникода, поэтому он рождает столько споров. Одно дело, когда вы пишете сайт с нуля и выбираете, какую кодировку использовать, другое – если у вас уже есть сайт. И зачем переводить его на какую-то другую кодировку, если и так все работает?

Если все же решились, читайте ниже пошаговую инструкцию, как перейти на Юникод. Предполагается, что исходный сайт написан полностью с поддержкой кодировки windows-1251.

1. В файлах .htaccess редактируем строки, отвечающие за кодировку, или добавляем, если их нет:

код скопирован в буфер
  1. AddType "text/html; charset=utf-8" .html .htm .shtml .php
  2. AddDefaultCharset utf-8

2. Точно так же в html-шаблонах везде, где встречается мета-тег Content-Type меняем его на

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

В текстовом редакторе notepad2 есть такая особенность: если кодировка самого html-файла отличается от кодировки, заданной в мета-теге Content-Type, то содержимое файла при просмотре отображается неправильно, поэтому не пугайтесь, если после сохранения увидите кракозябры.

3. Перекодируем все файлы сайта. Для этого запустим рекуррентную функцию:

код скопирован в буфер
  1. <?
  2. // перекодировка всех файлов директории $path, включая файлы в поддиректориях, из windows-1251 в utf-8
  3. function filesToUnicode($path, $types)
  4. {
  5.     $dir = opendir($path);
  6.     while ($file = readdir($dir))
  7.         // директория - рекуррентно запускаем для нее функцию
  8.         if (is_dir($path.'\\'.$file) && $file != '..' && $file != '.') filesToUnicode($path.'\\'.$file, $types);
  9.         // файл нужного расширения - перекодируем
  10.         elseif (is_file($path.'\\'.$file) && in_array(substr(strrchr($file, '.'), 1), $types))
  11.         {
  12.             $content = iconv('windows-1251', 'utf-8', file_get_contents($path.'\\'.$file));
  13.             if ($content)
  14.             {
  15.                 $f = fopen($path.'\\'.$file, 'w');
  16.                 fwrite($f, $content);
  17.                 fclose($f);
  18.             }
  19.             echo $path.'\\'.$file.' - '.($content?'<b>перекодирован</b>':'<b style="color: red">ошибка или пустое содержимое</b>').'<br>';
  20.         }
  21.     closedir($dir);
  22. }
  23. // это пример запуска, вам нужно указать свой путь и массив типов файлов
  24. filesToUnicode('С:\WebServers\home\mysite.ru', array('php', 'html', 'css', 'js', 'shtml', 'tpl'));
  25. ?>

В функцию передается путь директории без последнего слеша, файлы которой мы хотим перекодировать из windows-1251 в utf-8, и массив расширений файлов, к которым должна применяться перекодировка. Только не запускайте ее два раза, иначе не узнаете содержимое своих файлов.

Предполагается, что этот скрипт будет запускаться на виртуальном сервере под Windows, если вы хотите запускать его под Linux, позаботьтесь о правах записи на файлы.

4. Перекодируем базы данных.

Создаем подключение к БД с помощью функции mysql_connect() пользователем с правами на выполнение запросов ALTER. Запускаем функцию dbToUnicode() из листинга ниже, которая полностью перекодирует указанную базу данных в юникод. Если баз много нужно запустить функцию несколько раз.

код скопирован в буфер
  1. <?
  2. function dbToUnicode($db_name)
  3. {
  4.     // устанавливаем кодировку базы по умолчанию
  5.     mysql_query("ALTER DATABASE `$db_name` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci") or die (mysql_error());
  6.     // устанавливаем кодировку каждой таблицы по умолчанию и кодировку всех ее столбцов
  7.     $result = mysql_query("SHOW TABLES FROM `$db_name`") or die (mysql_error());
  8.     while ($arr = mysql_fetch_assoc($result))
  9.         mysql_query("ALTER TABLE `$db_name`.`".reset($arr)."` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci") or die (mysql_error());
  10. }
  11. dbToUnicode('db_name'); // здесь вместо db_name нужно поставить имя вашей БД
  12. ?>

5.  Добавляем перед запуском всех скриптов сайта строку:

код скопирован в буфер
  1. mysql_query("SET NAMES utf8");

Это позволит правильно распознавать кодировку данных при обращении к БД.

6. Теперь, если вы откроете сайт, то скорее всего узрите его в читаемом виде, но местами он может вести себя не так, как вы ожидаете. Дело в том, что стандартные функции работы со строками в php некорректно понимают юникод. Например, если создать php-скрипт в кодировке utf8 и запустить:

код скопирован в буфер
  1. <?
  2. echo strlen('тест');
  3. ?>

он выведет на экран число 8, хотя длина строки – 4 символа. В юникоде каждый кириллический символ занимает 2 байта. То же самое будет с функциями strtoupper(), preg_match() и другими.

Чтобы научить php корректно работать с юникодовыми строками, нужно заменить все строковые функции в скриптах их аналогами с префиксом mb_, которые понимают юникод. strlen нужно заменить на mb_strlen, strtoupper – на mb_strtoupper и т.д. Чтобы эти функции заработали правильно, придется также в начале каждого скрипта добавить строки:

код скопирован в буфер
  1. mb_internal_encoding('UTF-8'); // для обычных текстовых функций
  2. mb_regex_encoding('UTF-8'); // для регулярных выражений

Они зададут кодировку, в которой будут передаваться строки в mb-функции. Полный список функций, которые подлежат замене, находится здесь (http://ca3.php.net/manual/en/mbstring.overload.php)

Есть возможность не менять сами названия функций, а заставить php автоматически использовать их, вместо стандартных, для этого нужно в .htaccess добавить строку

код скопирован в буфер
  1. php_value mbstring.func_overload "7"

В Windows-системах эта строка в .htaccess для определенных версий php может не срабатывать, поэтому в них нужно указать директиву в файле php.ini

код скопирован в буфер
  1. mbstring.func_overload = 7

Теперь строка кода echo strlen('тест'), как и положено, выведет 4.

Однако, из-за overload-а некоторые сторонние продукты: форумы, доски объявлений, дополнительные библиотеки и т.п., могут повести себя некорректно, это нужно учесть и, возможно, просто переписать все свои функции, добавив префикс mb_, вместо использования mbstring.func_overload

А что же с функциями регулярных выражений preg_match, preg_replace и т.д. – их нет в списке (http://ca3.php.net/manual/en/mbstring.overload.php). К ним прямо в регулярные выражения мы добавим модификатор "u", говорящий, что работа идет с юникодовой строкой.

Было:

код скопирован в буфер
  1. preg_replace('/т/i', '_', 'тесТ'); // должно вывести "_ес_", но не выводит, так как нет модификатора

Изменим на

код скопирован в буфер
  1. preg_replace('/т/iu', '_', 'тесТ'); // теперь с юникодом должно работать правильно

7. Во всех местах, где у вас происходила работа со строками с учетом кодировок (например, после парсинга XML, вы переводили строку в windows-1251 с помощью функции iconv()), нужно учесть изменения, вызванные переходом на юникод. Это уже нельзя сделать централизовано, придется вручную проверять весь сайт.

Теги: PHP, Юникод
Другие готовые решения...
10 декабря 2013

Добавление комментария

Имя:
Преобразовывать в тексте комментария смайлики в графические иконки
Защитный код:
Защитный код
 
 
                                                                                                                                                                                                       
Copyright © 2019 ScriptScript.ru, по всем вопросам пишите нам через форму обратной связи.
364319675