PHP PDO: діаграма, назви наборів?


189

У мене це було раніше в моєму звичайному mysql_ * з'єднанні:

mysql_set_charset("utf8",$link);
mysql_query("SET NAMES 'UTF8'");

Мені це потрібно для PDO? І де мені це мати?

$connect = new PDO("mysql:host=$host;dbname=$db", $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

10
Слід уникати "SET NAMES utf8" через інжекцію SQL. Докладні відомості див. У php.net/manual/en/mysqlinfo.concepts.charset.php .
— masakielastic

якщо у вас є проблеми з діаграмою, вам, можливо, не залишається нічого іншого, як встановити на utf8. Я думаю, що для вивезення слід використовувати рядок підключення, як показано Cobra_Fast нижче. Використовуйте PDO :: підготуйтеся для підготовки своїх операторів SQL із прив’язаними параметрами.
— користувач12345

1
@masakielastic, то як слід вказати зіставлення як "SET NAMES utf8 COLLATE utf8_unicode_ci"
— datasn.io

Відповіді:


460

Ви матимете його у рядку з'єднання, наприклад:

"mysql:host=$host;dbname=$db;charset=utf8"

ТАКОЖ, перед PHP 5.3.6, параметр charset був ігнорований. Якщо ви використовуєте більш стару версію PHP, ви повинні зробити це так:

$dbh = new PDO("mysql:$connstr",  $user, $password);
$dbh->exec("set names utf8");

15
Варто зазначити, що така поведінка змінилася в 5.3.6, і зараз працює коректно.
— igorw

15
будьте utf8 instaead UTF-8 "mysql: host = $ host; dbname = $ db; charset = utf8"
— od3n

3
Проігноруйте відповіді нижче, якщо ви використовуєте оновлену версію PHP: вона працює чудово в php 5.3.8.
— Казимир

4
Чи потрібно також вказувати порівняння в цьому випадку? Такі як "SET NAMES utf8 COLLATE utf8_unicode_ci"?
— datasn.io

2
Дякую! Врятував мій день!
— Олександр

64

До PHP 5.3.6 параметр charset ігнорувався. Якщо ви використовуєте більш стару версію PHP, ви повинні зробити це так:

<?php

    $dbh = new PDO("mysql:$connstr",  $user, $password);

    $dbh -> exec("set names utf8");

?>

1
Примітка модам: Це правильна відповідь, і вона була розміщена за рік до того, як прийнята відповідь змінила цю інформацію.
— dotancohen

42

Це, мабуть, найелегантніший спосіб зробити це.
Прямо під час виклику конструктора PDO, але уникайте помилок набору шаблонів (як зазначено вище):

$connect = new PDO(
  "mysql:host=$host;dbname=$db", 
  $user, 
  $pass, 
  array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
  )
);

Для мене чудово працює.


1
Я розумію, що це також баггі для php 5.3.0. В цьому випадку вам необхідно ввести параметр в масиві з допомогою посилання його номер , а не його ім'я , як це: array(1002 => 'SET NAMES utf8',...).
— JDelage

Дякую за підказку! Я використовую вищезазначений код успішно в декількох виробничих системах, що використовують різні версії PHP 5.3.X, але насправді жодна з них не є 5.3.0.
— Jpsy

4
Я думаю, що це може бути елегантніше без конкретних баз даних
— Aalex Gabi

Правда, MYSQL_ATTR_INIT_COMMAND доступний лише для баз даних MySQL (про доступні команди для кожного типу db див. Підсторінки php.net/manual/de/pdo.drivers.php ). Але це саме те, про що просила ОП.
— Jpsy

проходження charset=utf8в рядку dsn працює! Я намагався розібратися в проблемі на groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
— Hari KT

16

Для повноти фактично є три способи встановити кодування під час підключення до MySQL з PDO, і які з них доступні залежать від вашої версії PHP. Порядок уподобань буде таким:

  1. charset параметр у рядку DSN
  2. Запуск SET NAMES utf8із PDO::MYSQL_ATTR_INIT_COMMANDопцією підключення
  3. Запустити SET NAMES utf8вручну

Цей зразок коду реалізує всі три:

<?php

define('DB_HOST', 'localhost');
define('DB_SCHEMA', 'test');
define('DB_USER', 'test');
define('DB_PASSWORD', 'test');
define('DB_ENCODING', 'utf8');


$dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_SCHEMA;
$options = array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
);

if( version_compare(PHP_VERSION, '5.3.6', '<') ){
    if( defined('PDO::MYSQL_ATTR_INIT_COMMAND') ){
        $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES ' . DB_ENCODING;
    }
}else{
    $dsn .= ';charset=' . DB_ENCODING;
}

$conn = @new PDO($dsn, DB_USER, DB_PASSWORD, $options);

if( version_compare(PHP_VERSION, '5.3.6', '<') && !defined('PDO::MYSQL_ATTR_INIT_COMMAND') ){
    $sql = 'SET NAMES ' . DB_ENCODING;
    $conn->exec($sql);
}

Виконання всіх трьох, ймовірно, зайве (якщо ви не пишете клас, який плануєте розповсюджувати або використовувати повторно).


1
Чи існує еквівалент ODBC / Access? Зараз у мене працює підключення Oracle та MySQL PHP PDO UTF8, але я не можу змусити його працювати для ODBC / Access.
— січня

2
О, і ніколи не визначати пароль своєї бази даних. Вони такі ж глобальні, як суперглобали, і це не дуже добре, коли ви працюєте з паролями.
— Xesau

2

Я просто хочу додати, що ви повинні переконатися, що ваша база даних створена за допомогою COLLATE utf8_general_ci або будь-якого зібрання, яке ви хочете використовувати, в іншому випадку ви можете отримати інший, ніж було призначено.

На phpmyadmin ви можете побачити порівняння, натиснувши вашу базу даних та вибравши операції. Якщо ви спробуєте створити таблиці з іншим порівнянням, ніж ваша база даних, ваші таблиці все-таки закінчуються зіставленням бази даних.

Тому переконайтесь, що зібрання для вашої бази даних є правильним перед створенням таблиць. Сподіваюсь, це заощадить когось кілька годин, хаха


1
"Якщо ви спробуєте створити таблиці з іншим порівнянням, ніж ваша база даних, ваші таблиці все-таки закінчуються зіставленням баз даних" - я не вважаю це правильним. Збір таблиці має перевагу над зіставленням бази даних. dev.mysql.com/doc/refman/5.5/uk/charset-table.html
— humble_wolf

2

Я думаю, що вам потрібен додатковий запит, оскільки параметр charset у DSN насправді ігнорується. дивіться посилання, розміщене в коментарі іншої відповіді.

Дивіться, як Drupal 7 робить це в http://api.drupal.org/api/drupal/includes--database--mysql--database.inc/function/DatabaseConnection_mysql%3A%3A__construct/7 :

// Force MySQL to use the UTF-8 character set. Also set the collation, if a
// certain one has been set; otherwise, MySQL defaults to 'utf8_general_ci'
// for UTF-8.
if (!empty($connection_options['collation'])) {
  $this->exec('SET NAMES utf8 COLLATE ' . $connection_options['collation']);
}
else {
  $this->exec('SET NAMES utf8');
}

1
$conn = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);

1
Хоча ця відповідь, ймовірно, правильна і корисна, бажано, якщо ви додасте разом із нею якесь пояснення, щоб пояснити, як це допомагає вирішити проблему. Це стане особливо корисним у майбутньому, якщо відбудеться якась зміна (можливо непов'язана), яка змусить її перестати працювати, і користувачі повинні зрозуміти, як це колись працювало.
— Ерті Сейдоль

1
$con="";
$MODE="";
$dbhost = "localhost";
$dbuser = "root";
$dbpassword = "";
$database = "name";

$con = new PDO ( "mysql:host=$dbhost;dbname=$database", "$dbuser", "$dbpassword", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$con->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );   

0

Я тестую цей код і

$db=new PDO('mysql:host=localhost;dbname=cwDB','root','',
array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
$sql="select * from products  ";
$stmt=$db->prepare($sql);
$stmt->execute();
while($result=$stmt->fetch(PDO::FETCH_ASSOC)){                  
    $id=$result['id'];
}

Хоча цей код може відповісти на питання, надаючи додатковий контекст стосовно того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
— rollstuhlfahrer

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.