От автора: вопрос кодировок является, без сомнения, одним из актуальных вопросов рано или поздно встающим перед любым веб-мастером. Практически каждый из нас сталкивался с такой, порой довольно неприятной, проблемой, как проблема корректного отображения информации на сайте, т.е. вывод ее на экран в нужной нам кодировке. Несмотря на то, что этот вопрос почти всегда решается очень легко, и ничего сложного в нем нет. Сейчас в сети можно часто увидеть вопросы о всевозможных «кракозябрах, вопросах и ромбиках» на сайте.
1. Кодировка при работе без использования баз данных
Забегая вперед, давайте сразу сформулируем основной тезис, придерживаясь которого мы значительно облегчим себе работу:
Кодировка в Вашем проекте должна быть универсальной.
Какое значение вкладывается в этот термин — "универсальная"? Это значит, что все составляющие создаваемого проекта, которые так или иначе касаются кодировок, должны иметь единую кодировку. Чтобы понять эту мысль разобьем сформулированный тезис на пункты, которые затем поэтапно разберем:
1. Содержимое всех файлов должно иметь единую кодировку.
2. Заголовки должны передавать единую кодировку.
3. В качестве кодировки сервера необходимо установить единую кодировку.
4. Кодировка соединения с БД также не должна отличаться от кодировки создаваемого проекта.
Это 4 основных правила, которые и являются составляющими сформулированного тезиса. Давайте теперь разберем каждый из этих пунктов.
Итак, на сервере создадим файл index.php, содержимое которого сохраним в кириллической кодировке. Сделать это можно, например, в редакторе Notepad++ через пункт меню Кодировки.
Узнать текущую кодировку файла можно взглянув в строку состояния редактора (в нижней панели).
Здесь уместно дать небольшой совет. При создании сайтов лучше пользоваться одной из двух кодировок: кириллической (windows-1251) или юникод без сигнатуры BOM (utf-8 without BOM). При этом следует знать, что юникод более универсален. Эта кодировка содержит большее количество символов, а потому идеально подойдет для мультиязычных сайтов, в то время как с кириллической кодировкой здесь могут возникнуть проблемы. Есть еще ряд нюансов при использовании юникода. В общем, лучше использовать ту кодировку, которая более универсальна, но если Ваш сайт содержит только кириллические символы, то никто не запрещает использовать Вам windows-1251, тем более, что она также имеет свои плюсы (детальнее об этом, возможно, в одном из следующих уроков).
Отлично, кодировка нашего файла кириллическая (windows-1251). У всех остальных файлов проекта, согласно первому пункту, кодировка должна быть аналогичной. В мета-тегах (между тегами head) также укажем эту кодировку:
1 |
<meta http-equiv="content-type" content="text/html; charset=windows-1251" /> |
Выведем какой-нибудь текст кириллицей на страницу:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1251" /> <meta name="keywords" content="" /> <meta name="description" content="" /> <title>Кодировки</title> <link href="" rel="stylesheet" type="text/css" /> </head> <body> <p>Тестовая строка</p> </body> </html> |
Сохраним файл и попробуем открыть его в браузере… На экран выводится нечитабельная строка — набор вопросительных знаков вместо букв.
Почему так? Ведь мы сохранили файл в кириллической кодировке, в мета-теге также прописали нужную кодировку, но это не помогло. Если мы взглянем, в какой именно кодировке браузер отобразил нам текст, то увидим UTF-8.
При этом если мы выставим в браузере вручную нужную нам кодировку, то текст станет читабельным, но… до следующего обновления страницы в браузере. Еще раз зададимся вопросом, почему так произошло? Почему браузер никак не отреагировал на кодировку указанную в мета-теге?
«Виноват» здесь не браузер, а сервер. Дело в том, что сервер отсылает в браузер так называемые заголовки, где указывается кодировка, в которой браузер должен отобразить содержимое файла. В качестве кодировки сервер берет кодировку по умолчанию, т.е. так называемую дефолтную кодировку сервера. Посмотреть дефолтную кодировку сервера можно в конфигурационном файле httpd.conf, расположенном на сервере в каталоге usr\local\apache\conf\. Здесь кодировка задается в строке AddDefaultCharset. Здесь же мы можем изменить кодировку на нужную нам, при этом не забывая после внесения изменений перезапускать сервер.
Но изменить кодировку получится только на локальном сервере. На сервере в сети хостер нам просто не даст доступ к конфигурационному файлу сервера… и правильно сделает 🙂 Что же нам делать в таком случае? Неужели придется подстраиваться под настройки сервера? Конечно же нет. Для решения этой задачи существует 2 варианта, отвечающих за второй и третий сформулированные нами выше пункты.
Согласно второму пункту мы можем самостоятельно передать в заголовках необходимую кодировку. Делается это при помощи функции header(), в параметрах которой мы укажем тип документа и, собственно, кодировку. В самом верху файла (перед объявлением доктайпа (типа документа)) добавим строку кода:
1 |
<?php header("Content-type: text/html; Charset=windows-1251"); ?> |
Если теперь обновить страницу в браузере, то увидим читабельный текст в кириллической кодировке. Замечательно — мы решили задачу! Путем передачи заголовков мы указали нужную нам кодировку. Но этот вариант не совсем универсален. Дело в том, что заголовки передаются посредством функции header(), т.е. для этого мы используем средства PHP. Но что же тогда делать, если файлы нашего проекта имеют расширение html? В файлах с таким расширением по умолчанию код PHP не выполняется, соответственно — заголовки не будут отправлены. Результат — вновь нечитабельный текст в браузере.
Альтернативой является второе решение (пункт 3), которое гораздо более универсальнее первого. Итак, согласно пункта 3 мы должны установить дефолтной кодировкой сервера нужную нам. Но как это можно сделать, если к конфигурационному файлу сервера мы доступа не имеем? Очень просто. Предусмотрен специальный файл, в котором можно изменять некоторые настройки сервера, в частности — дефолтную кодировку. Файл этот не имеет расширения и называется .htaccess (с точкой в начале имени файла). В самом файле достаточно прописать ту же строку, что и в конфигурационном файле сервера, но с указанием необходимой кодировки:
1 |
AddDefaultCharset windows-1251 |
Сервер при этом перезапускать не нужно, поскольку фактически мы ничего не изменяем в его настройках, а просто «говорим» серверу, что в качестве дефолтной кодировки следует использовать ту, которую мы только что указали.
Теперь файлы открываются в «правильной» (нужной нам) кодировке (функцию header() теперь нет надобности использовать) и кодировка нашего проекта не будет зависеть от настроек сервера того или иного хостера.
Но помните, если мы нарушим сформулированный нами тезис об универсальности кодировки и, к примеру, при установленной в качестве дефолтной кодировки кириллице перекодируем содержимое файлов в юникод, то получим знаменитые «кракозябры».
2. Проблема кодировки при работе с базой данных
Теперь взглянем на ту же проблему, но с использованием в работе БД. Дело в том, что в таблицах БД лежит текст, и эти таблицы также могут иметь свою кодировку. Поскольку я использую в качестве сервера Денвер, который настроен под кириллическую кодировку, то логично, что для хранения информации в БД по умолчанию используется также кириллическая кодировка.
Не будем ничего изменять в настройках и при создании БД и таблицы оставим все как есть, т.е. будет использована кириллическая кодировка. Хотя, забегая вперед, можно сказать, что если бы мы создали таблицы в нужной нам кодировке, то это совсем не означает, что данные будут выведены в этой же кодировке… вся хитрость в том, что здесь существует такой параметр, как кодировка соединения с БД. Вот ее то мы и будем использовать для достижения нужного результата.
Итак, создадим файл с кодировкой юникод (поскольку мы заранее знаем, что данные из БД будут выведены в кириллической кодировке), т.е. мы таким образом поставили перед собой в учебных целях проблему, которую и попытаемся решить… как говорится, тяжело в учении… 🙂
При создании файла не забудем передать в заголовках нужную нам кодировку, поскольку в файле .htaccess указана сейчас кириллическая кодировка, но мы хотим, чтобы новый файл работал корректно в юникоде:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php header("Content-type: text/html; Charset=utf-8"); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "//www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="//www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="keywords" content="" /> <meta name="description" content="" /> <title>Кодировка при работе с БД</title> <link href="" rel="stylesheet" type="text/css" /> </head> <body> </body> </html> |
Теперь создадим БД charset и в ней таблицу test с двумя полями:
id, тип INT, первичный ключ, автоинкремент;
text, тип VARCHAR, длина 255.
В таблицу поместим единственную запись в поле text:
1 |
<p>Тестовая строка</p> |
Эту запись мы и будем выводить на экран. Для этого пропишем соединение с сервером MySQL, выберем БД для работы и запросом выберем необходимые данные (все это мы уже проделывали в ряде предыдущих уроков, а потому подробно останавливаться на объяснении всего этого — нет оснований):
1 2 3 4 5 6 7 8 9 10 11 |
<?php header("Content-type: text/html; Charset=utf-8"); mysql_connect("localhost", "root", "") or die("Can't connect to server"); mysql_query("SET NAMES 'utf8'") or die("Can't set charset"); mysql_select_db("charset") or die("Can't select DB"); $res = mysql_query("SELECT `text` FROM `test` WHERE `id`=". 1) or die(mysql_error()); $row = mysql_fetch_assoc($res); ?> |
Теперь в массиве $row мы имеем искомую строку. Давайте выведем ее в теле страницы (между тегами body):
1 2 3 4 5 |
<?php echo $row['text']; ?> |
Если сейчас открыть страницу в браузере, то увидим опять-таки вместо читабельного текста вопросительные знаки. Так произошло оттого, что браузер (согласно отосланных заголовков) открыл страницу в юникоде, но информация из БД достается в кириллической кодировке. Как это исправить? Очень просто — достаточно после соединения с сервером БД указать в запросе кодировку соединения, тогда данные из БД будут отдаваться в искомой кодировке.
Пропишем необходимый запрос после соединения:
1 2 |
mysql_connect("localhost", "root", "") or die("Can't connect to server"); mysql_query("SET NAMES 'utf8'") or die("Can't set charset"); |
Теперь после обновления страницы информация выводится корректно.
Вот и вся хитрость.
Заключение
Стоит обратить внимание на отличия в именовании кодировок в MySQL от традиционного их именования, т.е. того, к которому мы привыкли. Например, указать юникод правильно так — "utf8", но не так — "utf-8". Второй вариант серверу MySQL будет непонятен. Аналогично с кириллицей: правильно так — "cp1251", но не так — "windows-1251".
На этом наш урок подходит к концу. Теперь, если Вы будете использоваться в своей работе озвученные выше правила, то проблем с кодировками у вас будет гораздо меньше.
Надеюсь, данный урок был полезен для Вас. Если у Вас остались какие-либо вопросы, то я с удовольствием отвечу на них в комментариях.
Автор: Кудлай Андрей
Редакция: Рог Виктор и Андрей Бернацкий. Команда webformyself.
Комментарии (70)