Проблемы с кодировкой в MySQL версий 4.1+Быстрые рекомендацииПодробные объяснения. Перекодировка Исправление БД, в таблицах которой неверно указана кодировка Если все равно ничего не получается Примечания ОПС Комментарии Быстрые рекомендации Если из базы выводятся вопросики, то после соединения с сервером выполняем волшебный запрос set names кодировкаПараметр "кодировка" должен соответствовать кодировке, в которой выводятся страницы на сайте. например: set names utf8Если это не помогло, и всё равно идут вопросики или крокозябры - значит, криво настроена кодировка таблиц. В этом случае см. Если выводится нормально, но сортировка хромает - см. туда же. Подробные объяснения. До версии 4.1 кодировку данных в MySQL можно было задать только одну на всех. Теоретически, ничто не мешало в одной таблице хранить данные в юникоде, а в другой - в KOI-8. Так все и поступали: в конце концов, для БД любые данные - это всего лишь набор цифр. Что в неё положил - то она тебе и вернёт. Но правильный поиск и сортировка работали только для данных, которые были в кодировке, совпадавшей с настройками MySQL. Начиная с версии 4.1 стало можно хранить данные в любой кодировке, и задавать свой порядок сортировки хоть для каждого поля в таблице. Но для этого понадобилось ввести некоторые правила. Во-первых, для каждого поля в таблице были введены два параметра: кодировка (CHARACTER SET) и правила сравнения (COLLATION). Кодировка - это понятно. Говорим базе, в какой кодировке лежат наши данные. Правила сравнения задают порядок сортировки и сравнения данных при поиске. COLLATION жестко привязан к CHARACTER SET-у и может быть задан только из поддерживаемых кодировкой. Проще говоря, начало названия COLLATION должно совпадать с CHARACTER SET. К примеру, для кодировки utf8 можно задать правила сравнения utf8_bin, но нельзя cp1251_bin. Обычно у каждой кодировки есть, как минимум, два набора правил сравнения - имякодировки_bin и имякодировки_general_ci. Первый сравнивает в лоб по кодам символов, а второй - регистронезависимо, учитывая совпадающие символы. COLLATION имякодировки_general_cs сравнивает регистрозависимо, отличаясь от _bin тем, что учитывает совпадающие символы ("е" и "ё" в русском языке), а также, при сортировке, ставит на место те символы, которые идут в кодировке не по порядку (например "ё" в 1251).Если для поля не указан COLLATION, то он берется по умолчанию. К примеру, для utf8 - utf8_general_ci. В большинстве случаев COLLATION по умолчанию устраивает пользователя, а это значит, что его задавать не нужно. То есть, достаточно указать только кодировку. Кодировка может быть задана для поля, таблицы, database и для всего сервера. Установки имеют характер умолчаний, и могут быть изменены на любом уровне: Кодировку (и сортировку) можно указывать для каждого отдельного поля. Если они не указаны, то при создании таблицы берутся из кодировки, указанной для этой таблицы. Если при создании таблицы кодировка не указывается, то она берется из параметров database. Так же и при создании database - либо задаются явно, либо берутся из параметров сервера. Во-вторых, появилась необходимость говорить базе данных, в какой кодировке мы записываем или хотим получить свои данные. То есть, появилось такое понятие, как кодировка клиента. Здесь и кроется ответ на вопрос - "откуда берутся "вопросики"? Они появляются, если кодировка таблицы не совпадает c кодировкой клиента. Соответственно, в MySQL появились две новые команды set character_set_clientПервая указывает, в какой кодировке приходят данные в базу, а вторая - в какой их выдавать. Поскольку чаще всего эти кодировки совпадают, то можно писать короче - один запрос "SET NAMES кодировка", который и устанавливает оба эти параметра. Из приведенных объяснений должно быть ясно, что для беспроблемной работы нам надо сделать всего две вещи: 1. Указывать правильную кодировку клиента. Это можно сделать либо в настройках сервера в my.ini, либо тем самым запросом SET NAMES. 2. Создавая таблицы, не забывать указывать правильную кодировку для них. Это можно сделать несколькими способами. Самое простое - это указывать кодировку и правила сравнения прямо в коде CREATE TABLE. Пример: CREATE TABLE `chartest` (Но что, если у нас огромный дамп на сотни таблиц, сделанный в прошлой версии MySQL? Дописывать к каждой таблице вручную? Возможно, это и придется делать. Но сначала надо попробовать установить параметры по умолчанию. Как мы помним, при создании таблиц, если для них не указывается collation и charset, эти параметры берутся из настроек database. Следовательно, надо попытаться изменить эти настройки. сначала смотрим, какие они сейчас: заходим в консоль и пишем use `mydb`Этот запрос выведет кодировку базы mydb по умолчанию. Если она нас не устраивает, то пытаемся переопределить настройки самостоятельно alter database `mydb` character set utf8;Если запрос прошел успешно, то проверяем ещё раз, и, если все нормально, то начинаем создавать таблицы или заливать дамп. Если таким образом сделать не удалось (не хватает прав), то варианта только два - или обращаться к провайдеру, чтобы он сам поменял настройки, или дописывать COLLATION И CHARACTER SET ко всем создаваемым таблицам вручную. Перекодировка Как следует предыдущих объяснений, кодировка клиента должна соответствовать реальной кодировке поступающих данных. В этом случае, даже если данные лежат в другой, то всё равно никаких проблем не будет - MySQL автоматом перекодрует туда и обратно. Проведем эксперимент. Для него нам потребуется MySQL, установленная под Windows. Для тех, у кого другая ОС, я думаю, поменять кодировки в терминале проблемы не составит. Для демонстрации возможностей перекодировки воспользуемся тем фактом, что по умолчанию консоль windows настроена на старую кодировку DOS - 866. То есть, сначала мы создадим таблицу в этой кодировке и запишем в неё данные, а потом попробуем общаться с базой в другой кодировке. Сначала запустим командный интерпретатор cmd.exe и установим в свойствах окна шрифт Lucida Console. затем вызываем консоль mysql: C:\MySQL\bin\mysql.exe -uroot testВ консоли пишем: set names cp866;Если мы все сделали правильно, то вывод будет таким: +------+дальше пишем exit, выходим из консоли, и пишем командуchcp 1251которая сменит кодировку окна консоли windows на 1251 затем снова запускаем консоль mysql и пишем: set names cp1251;То же самое можно повторить и для кодировки utf8 (chcp 65001). В результате мы видим, что даже тогда, когда данные поступают не в той кодировке, в которой они хранятся в базе, работа с ними происходит совершенно корректно. При этом они продолжают лежать в базе в той же самой кодировке, в которой они были с самого начала - 866. Возможности перекодировки ограничиваются, разумеется, одним и тем же языком. То есть, из 1251 можно перекодировать в 866, в koi8r, в UTF8. В latin1 из 1251 перекодировать нельзя - появятся вопросики. Исправление БД, в таблицах которой неверно указана кодировка Или что делать, если буквы нормальные, а поиск и сортировка работают странно. Итак, у нас есть проблемы, которые не решаются запросом SET NAMES. Это значит, что в таблицах лежат данные в одной кодировке, а указана для этих таблиц - другая. В принципе, быстрое решение этой проблемы можно вывести из предыдущих объяснений - сделать запрос SET NAMES с кодировкой, которая указана в таблице. Посмотреть её можно запросом show create table `table`.Если там в последней строчке написано DEFAULT CHARSET=latin1, то выполняем запрос SET NAMES latin1 В таблице не будет работать толком сортировка и поиск, но хотя бы сами данные будут отдаваться и записываться нормально (если кодировка html страницы соответствует фактической кодировке лежащих в базе данных). Но это, конечно, ненормальная ситуация, тем более, что исправить её совсем несложно. Что мы сейчас и проделаем. Для исправления существует два способа, которые описаны по ссылкам внизу. Я воспользуюсь вариантом из FAQ сайта linux.by, приведя только его содержательную часть. Но настоятельно рекомендую прочитать подробный вариант, с объяснением опций и исправлением возможных ошибок. Допустим, мы выяснили, что таблицы были созданы по умолчанию в кодировке latin1, а фактически в них содержатся данные в utf8. В этом случае используем команду: mysqldump -uUSERNAME -pPASSWORD DB_NAME --allow-keywords --create-options --complete-insert --default-character-set=latin1 --add-drop-table > dump.sqlРаспространненая ошибка в таких случаях - когда в --default-character-set указывают фактическую кодировку данных, в данном случае - utf8. В дампе будет мусор. Указывать надо ту, которая установлена в таблицах. В результате MySQL не будет пытаться данные перекодировать, и отдаст как есть. mysql -uUSERNAME -pPASSWORD DB_NAME --default-character-set=utf8 < dump.sqlmysql_query("SET NAMES utf8");Если все равно ничего не получается Большое количество вопросов по кодировкам, не имеющих отношения к БД, побудило меня составить небольшое сводное руководство. Итак, кодировка нашего сайта складывается из 4 пунктов: 1. Кодировка базы данных.
N.B.: Обозначения кодировок в mysql могут не совпадать с общепринятыми. Внимательно смотрите примеры Примечания Во-первых, убедитесь, что сервер отдает правильную кодировку в HTTP заголовке и в meta теге. Во-вторых, если в коде присутствуют перекодировки, то убедитесь, что они работают, и работают правильно. А ещё лучше - вообще уберите их, и пользуйтесь средствами БД. И вообще - старайтесь отличать проблемы браузера от проблем с БД. ОПС Если бы я нашел этот текст чуть раньше, то эта статья не была бы написана. Все очень толково и подробно: http://www.linux.by/wiki/index.php/FAQ_PHP_MySQL_charset Еще один неплохой текст по кодировкам: http://mysqlfaq.wikispaces.com/Encoding Официальная документация, разумеется. Я, конечно, знаю, что ни один из читателей этого фака не пойдет читать документацию на английском... Но сам я брал информацию именно оттуда. http://dev.mysql.com/doc/refman/5.0/en/charset.html Другие материалы раздела: \"Кавычки \". Cоставление запросов, слеши, SQL Injection Как разбить вывод из mysql постранично Пример кода, работающего с MySQL Базовые понятия MySQL и отличия от текстовых файлов. |
| Кирилл | 20.07.10 12:24 |
| Спасибо)) а для тех, кто юзает mysqli, используйте $_DB->query("SET NAMES 'utf8'"); где $_DB - имя вашего соединения, utf8 - используемая кодировка. Кстати, очень всем советую (mysqli имеется ввиду). Работает реально быстрее, и код красивей. А ещё, как утверждают разработчики практически неуязвим;) | |
| Дима | 30.06.10 18:39 |
| мудохался мудохался и оказываеться в поле - "сравнение" никакую кодировку мне не ненадо было вставлять. она автоматом выставляется какая надо. и вопросики исчезают. Зато статьи интересные почитал и русифицировал заодно. Спасибо | |
| Samu | 21.05.10 16:53 |
| спасибо тебе большое за подробную информацию.. ковырялся день не мог решить прблему - натолкнулся на твою статью и сразу все исправил Спасибо! | |
| СТАС | 16.05.10 12:13 |
| Спасибо большое за статья mysql_query("SET NAMES utf8"); мне помогло,поставил сразу же после запроса на соединения с базой данных. | |
| Жан | 09.05.10 15:25 |
| Спасибо mysql_query("SET NAMES utf8"); Помогло |
|
| iPlayer | 02.05.10 14:03 |
| Спасибо! Я уж думал, что никогда не найду ответа! Теперь в случае чего сразу на этот сайт заходить буду. |
|
| Макс | 20.04.10 01:08 |
| Разобрался в utf8 после долгих и безнадежных боев с глюком кодировки в БД Спасибо! |
|
| m0uz | 31.03.10 23:57 |
| Пожалуйста помогите мне, вот проблемка с запросом. после обновления странички теста все в ?? чем мне можно помочь! зарания спс CREATE TABLE IF NOT EXISTS `source_stat` ( `src` varchar(8) NOT NULL default '0', `date` timestamp NOT NULL default '0000-00-00 00:00:00' on update CURRENT_TIMESTAMP, `count` int(9) NOT NULL default '1', `type` tinyint(1) NOT NULL default '0' COMMENT 'Код страницы продажника', `test` tinyint(1) NOT NULL default '0' COMMENT '', PRIMARY KEY (`src`), KEY `count` (`count`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 |
|
| Jean | 18.02.10 21:22 |
| Статья очень помогла, два дня лазил по форумам и только тут узнал толком про сравнение. В PHP, MySQL5 и на страницах - cp1251 однако всеравно браузер выдовал вопросы. После того как изменил COLLATION cp1251_general_ci на cp1251_bin проблема была решина. Огромное спасибо автору, =) респект и уважуха =). |
|
| Иналь | 10.02.10 14:40 |
| Спасибо за интересную статью | |