Решаем проблемы с кодировкой на сайте.

Практический каждый новичок в области веб-разработок, рано или поздно сталкивается с проблемами кодировки в своих проектах. И тогда, как по написанному сценарию, начинается бомбардировка форумов с вопросами о том, как победить ненавистные "кракозябры". Подавляющее большинство проблем уже давно известны и лечатся довольно легко, нужно просто знать "в каком месте болит и какую таблетку принять". Посему, предлагаю разобрать наиболее популярные ошибки, из-за которых эта проблемка появляется и возможно, что мои рекомендации избавят вас от дальнейших с ними столкновений.

Во-первых, настоятельно рекомендую, чтобы все документы были в одной кодировке и база данных, а именно поля со строковыми данными, имели такую же кодировку. Устанавливается она при создании базы или же можно указывать сравнение для каждого отдельного поля. Если создаёте БД с помощью phpMyAdmin, то сложностей возникнуть не должно: закладка "Базы данных" > в поле под "Создать базу данных" вписываете имя вашей будущей БД > рядом выпадающий список "Сравнения". Если же создаёте базу sql-запросом, то пишите примерно следующее:

CREATE DATABASE IF NOT EXISTS `my_db_name` CHARACTER SET utf8 COLLATE utf8_general_ci;

Выбор кодировки остаётся за вами, но я бы посоветовал выбрать для документов "UTF-8 без BOM" и сравнение для базы "utf8_general_ci" (юникод многоязычный, регистронезависимый). Только не забудьте подстраховаться и сделать дамп перед манипуляциями с БД! Не буду здесь расписывать, что такое BOM, но если о-о-очень образно и на пальцах, то это такой невидимый маркер, который планировался для различения кодировок UTF-16LE и UTF-16BE, но по некоторым причинам оказался невостребованным и теперь мешает веб-разработчикам жить спокойно ;) Выглядит BOM, как символ U+FEFF и селится в начале документа. А почему всё-таки UTF-8? Вот, хотя бы пара причин... Вы без проблем сможете выводить на экран как кириллицу, так и цитату из стихов Аль-Мутанабби или китайские иероглифы. Всё потому, что в той же кодировке windows-1251 (cp1251) всего лишь 256 символов, в то время, как в UTF-8 их около ста тысяч, плюс ко всему специальные символы, пиктограммы, значки и т.д. Если вы собираетесь использовать на своём сайте ajax-запросы, то это так же добавляет плюс к кодировке UTF-8, потому что именно с этой кодировкой дружит объект XMLHttpRequest, а с другими придётся извращаться и иногда безуспешно. Та же карта сайта (sitemap.xml), которая служит для индексации поисковыми системами, работает только, если этот файл создан с кодировкой UTF-8. Кроме того, эта кодировка является стандартом для работы многих функций PHP и стандартом, который рекомендован W3C.

При создании нового документа - всё ясно, а как быть с уже существующим, в котором желательно изменить кодировку? Один из самых простых способов - это открыть документ в Notepad++, выбрать в меню "Кодировки" и в списке "Преобразовать в UTF-8 без BOM". Далее изменяем метатег с определением кодировки:

<meta charset="utf-8"><!-- для HTML5 (рекомендуется) -->
<!-- или -->
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"><!-- для более старых версий HTML -->

И для php-файлов можно установить соответствующий заголовок, но только, если файл не подключен в другом документе, где такой заголовок уже будет отправлен раньше. Это касается как заголовка в метатеге, так и отправленного функцией header:

header('Content-Type: text/html; charset=utf-8');

Проверяем результат в браузере. Тут может несколько вариантов:

  1. Всё выводится отлично и вопрос закрыт
  2. Статически прописанные данные отображаются нормально, но данные из БД - всё тами же "кракозябрами"
  3. Ничего не изменилось и кодировка осталась кривой

Начнём с последнего пункта. Счастливые владельцы выделенных серверов или VPS/VDS, могут изменить кодировку для директивы default_charset в конфигурационном файле php.ini. Тем же, кто доступа к php.ini не имеет или имеет, но необходимо изменить кодировку только для одного сайта, можно использовать файл .htaccess, записав в него следующее:

# в принципе, хватает строки ниже:
AddDefaultCharset UTF-8
# но иногда, могут потребоваться дополнительные установки:
DefaultLanguage ru
php_value default_charset "utf-8"

Файл .htaccess распологается в корне вашего сайта. Если вы его там не обнаружили, то создаём сами. В обычном блокноте создаёте документ > "Сохранить как" > Тип файла выбрать "Все файлы" > в поле "Имя файла" записываем только точку и расширение ".htaccess".

Переходим ко второму пункту - если базу перевели на нужную кодировку, но данные из неё отображаются на странице криво. Для начала, нужно убедится, что символы в самой базе отображаются нормально. Если кодировка там "не поплыла", то можно или же опять апеллировать к файлам конфигурации, или сделать запрос сразу после подключения к базе:

SET NAMES utf8;

*я пишу сам текст запроса, но т.к. не знаю какое расширение вы используете для работы с MySQL, покажу несколько вариантов:

// для устаревшего mysql_*
$db = mysql_connect('localhost', 'username', 'password');
mysql_select_db('db_name', $db);
mysql_query('SET NAMES utf8');

// для PDO и версий php ниже 5.3.6
$dbh = new PDO('mysql:host=localhost;dbname=db_name', 'username', 'password');
$dbh->exec('SET NAMES utf8');
// для PDO и версий php 5.3.6 и новее, можно указывать прямо при создании объекта
$dbh = new PDO('mysql:host=localhost;dbname=db_name;charset=utf8', 'username', 'password');
// или 
$db = new PDO('mysql:host=localhost;dbname=db_name', 'username', 'password', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

// для MySQLi
$mysqli = new mysqli('localhost', 'username', 'password', 'db_name');
$mysqli->set_charset("utf8");

Раз уж затронул вопрос "устаревшего mysql_*", то хочу обратить ваше внимание, на текст выделенный красным в документации php. Cто́ит задуматься...
Если у вас была одна из стандартных проблем, то выполнив некоторые или все вышеописанные шаги, с кодировкой вопрос будет решен положительно. Но так же хотелось бы упомянуть о некоторых функциях, которые могут пригодится в нестандартных ситуациях. Подробнее о них вы сможете прочитать в документации, а я лишь приведу пару примеров, не вдаваясь в подробности:

mb_internal_encoding()
C помощью этой функции, мы можем установить или получить текущую кодировку скрипта:
mb_internal_encoding('UTF-8'); // устанавливаем
echo mb_internal_encoding(); // без аргумента - получаем
mb_http_input() и mb_http_output()
Две функции, которые определяют, устанавливают или получают кодировку символов HTTP запроса или вывода:
print_r( mb_http_input('I') ); // определяем кодировку входных данных http-запроса
mb_http_output('UTF-8');  // устанавливаем кодировку для http-вывода
echo mb_http_output();  // получаем текущую кодировку символов http-вывода
iconv()
Функция преобразовывает символы строки в нужную кодировку:
echo iconv('utf-8','cp1251','Привет, РјРёСЂ!'); // Привет, мир!
mb_convert_encoding()
Функция похоже на iconv(), но на мой взгляд лучше, т.к. работает более адекватно.
echo mb_convert_encoding('Привет, РјРёСЂ!','cp1251','utf-8'); // Привет, мир!

Да и вообще, не забываем про аналоги функций для работы с многобайтными строками. Чаще всего, они имеют такое же название, но с приставкой mb_. Разницу ощутить достаточно просто. Возьмём, для примера, функции strlen() и mb_strlen() и проведём эксперимент, измерив длину строки:

// установим внутреннюю кодировку
mb_internal_encoding('utf-8');

// для латинских символов разницы нет
echo strlen('incode'); // 6
echo mb_strlen('incode'); // 6

// А вот с кириллицей выдает - пичалька
echo strlen('инкод'); // 10
echo mb_strlen('инкод'); // 5

Может кому и не нужно объяснять это явление, но для новичков растолкую: кириллица кодируется двумя байтами, а strlen() считает именно количество байт в строке, а не количество букв. Вот и получается, что пять кириллических символов умножить на два - получаем 10. Китайские символы, если я не ошибаюсь, вообще кодируются тремя байтами, поэтому в дальнейшем для таких случаев, чтоб не возникало никаких недорозумений, используйте соответствующие функции.


Повторюсь, что эти решения к часто встречающимся случаям и в подавляющем большинстве, они решают проблему. Но если у вас возникла ситуация, когда всэ эти способы не возымели действия, то пишите сюда, попробуем разобраться вместе и дополним статью новым "рецептом от головной боли" ;) Засим позвольте откланяться.

Incode Pro logo
Ваш комментарий:
X