Проблеми з кодуванням в mysql версій 4

Якщо з бази виводяться вопросики, то після з'єднання з сервером виконуємо чарівний запит:

set names кодування

Параметр "кодування" повинен відповідати кодуванні, в якій виводяться сторінки на сайті. наприклад:







Якщо це не допомогло, і все одно йдуть вопросики або "крокозябри" або виводиться нормально, але сортування кульгає, значить криво налаштована кодування таблиць. В цьому випадку дивіться "Виправлення БД, в таблицях якої невірно вказано кодування".

Примітка: замість запиту SET NAMES слід, по можливості, застосовувати функцію mysql_set_charset ().

Детальні пояснення

До версії 4.1 кодування даних в MySQL можна було задати лише одну на всіх. Теоретично ніщо не заважало в одній таблиці зберігати дані в юникоде, а в іншій - в KOI-8. Так все і надходили: врешті-решт, для БД будь-які дані - це всього лише набір цифр. Що в неї поклав, то вона тобі і поверне. Але правильний пошук і сортування працювали тільки для даних, які були в кодуванні, що збігається з настройками MySQL.

Починаючи з версії 4.1 стало можна зберігати дані в будь-якому кодуванні, і задавати свій порядок сортування хоч для кожного поля в таблиці. Але для цього знадобилося ввести деякі правила.
  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 character_set_results. Перша вказує, в якому кодуванні приходять дані в базу, а друга - в якій їх видавати. Оскільки найчастіше ці кодування збігаються, то можна писати коротше - один запит "SET NAMES кодування", який і встановлює обидва ці параметра.
  • З наведених пояснень має бути ясно, що для безпроблемної роботи нам треба зробити всього дві речі:
    1. Вказувати правильний метод кодування клієнта. Це можна зробити або в налаштуваннях сервера в my.ini, або тим самим запитом SET NAMES.
    2. Створюючи таблиці, не забувати вказувати правильний метод кодування для них. Це можна зробити декількома способами. Найпростіше - це вказувати кодування і правила порівняння прямо в коді CREATE TABLE. приклад:

    CREATE TABLE `chartest` # 40;
    `Name` varchar # 40; 10 # 41; default NULL
    # 41; ENGINE = MyISAM CHARACTER SET = utf8

    Але що, якщо у нас величезний дамп на сотні таблиць, зроблений в минулій версії MySQL? Дописувати до кожної таблиці вручну? Можливо, це і доведеться робити. Але спочатку треба спробувати встановити параметри за замовчуванням.

    Як ми пам'ятаємо, при створенні таблиць, якщо для них не вказується collation і charset, ці параметри беруться з налаштувань database. Отже, треба спробувати змінити ці настройки. Спочатку дивимося, які вони зараз: заходимо в консоль і пишемо:

    use `mydb`
    show variables like "character _ set _ database";







    Цей запит виведе кодування бази 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;
    CREATE TABLE ct # 40; `Name` varchar # 40; 10 # 41; default NULL # 41; CHARACTER SET = cp866;
    insert into ct values # 40; 'Вова' # 41; ;
    select * from ct;

    Якщо ми все зробили правильно, то висновок буде таким:

    Далі пишемо exit, виходимо з консолі, і пишемо команду "chcp 1251", яка змінить кодування вікна консолі windows на 1251. Потім знову запускаємо консоль mysql і пишемо:

    set names cp1251;
    select * from ct;
    insert into ct values # 40; 'Вова' # 41; ;
    select * from ct;

    Те ж саме можна повторити і для кодування 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 сторінки відповідає фактичній кодуванні лежать в базі даних). Але це, звичайно, ненормальна ситуація, тим більше, що виправити її зовсім нескладно.

    Для виправлення існує два способи, Скористаємося таким варіантом:
    • Дізнаємося кодування таблиць (show create table `table`).
    • Робимо дамп БД за допомогою mysqldump
    Припустимо, ми з'ясували, що таблиці були створені за замовчуванням в кодуванні 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 не намагатиметься дані перекодувати, і віддасть як є.

    Переглядаємо файл з дампом, щоб переконатися, що в файлі нормальні дані в кодуванні utf8, а не сміття. Цілий і перевірений дамп копіюємо в сторону. Далеко в сторону.

    У файлі дампа виправляємо оператори CREATE DATABASE і / або CREATE TABLE для створення таблиць в правильному кодуванні. Або міняємо настройки database, як це було описано вище. Заливаємо дамп назад:

    mysql -uUSERNAME -pPASSWORD DB_NAME --default-character-set = utf8

    У код сайту, після функцій mysql_connect і mysql_select_db додаємо рядок:

    mysql_query # 40; "SET NAMES utf8" # 41; ;

    Все, можна працювати!

    Якщо все одно нічого не виходить
    Велика кількість питань по кодувань, що не мають відношення до БД, спонукало мене скласти невелике зведене керівництво. Отже, кодування нашого сайту складається з 4 пунктів:
    1. Кодування бази даних. Здається при створенні таблиць. Може бути будь-яка. Повинна відображати реальну кодування даних в таблиці. Наприклад, якщо дані у нас будуть лежати в кодуванні Windows-1251, то створюючи таблицю, пишемо:

    CREATE TABLE chartest # 40; string text # 41; DEFAULT CHARSET = cp1251;

    Перевірити поточну кодування таблиці можна запитом

    SHOW CREATE TABLE tablename

  • Кодування клієнта БД (клієнтом в даному випадку є скрипт, який працює з БД). Здається відразу після з'єднання з БД, запитом

    SET NAMES кодування

    Повинна збігатися з кодуванням виведеної HTML сторінки. Наприклад, якщо сторінка у нас в utf-8, то в PHP пишемо

    mysql_query # 40; "SET NAMES utf8" # 41; ;

    Перевірити можна запитом

    show variables like '% char%'; # 40; змінні character_set_client. character_set_connection і character_set_results повинні мати встановлений нами значення # 41;

  • Кодування сайту. Здається HTTP заголовком Content-type. Повинна відповідати кодуванні даних на сторінці. Наприклад, якщо сторінка у нас в utf-8, то в PHP напишемо:

    header # 40; "Content-Type: text / html; charset = UTF-8" # 41; ;

    Примітки
    • Забавно, але запит SET NAMES не змінює кодування, що використовується функцією mysql_real_escape_string. А тільки заради кодування ця функція і була придумана! Для того, щоб mysql_real_escape_string працювала як задумано, і потрібно змінювати кодування з помщью mysql_set_charset (), а не запиту SET NAMES. Втім, для нас це не так уже й важливо, оскільки для utа8 і всіх однобайтовим кодувань ніяких негативних наслідків від неправильної кодування не буде. Не кажучи вже про те, що давно пора відмовитися від прослешіванія взагалі і використовувати рідні підготовлені вираження.
    • Якщо не хочеться в кожному скрипті задавати кодування, можна встановити кодування для всього сервера за замовчуванням. Для цього в my.ini в секції [mysqld] треба написати:

    init-connect = 'SET NAMES utf8'

    Таким чином дефолтна кодування буде змінена з latin1 на зазначену. Зрозуміло, в скриптах її можна буде міняти на будь-яку іншу.