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.