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, чтобы узнать подробности.
Масаэластик

если у вас есть проблемы с кодировкой, то у вас может не быть выбора, кроме как установить utf8. Я думаю, что вы должны использовать строку подключения, как показано Cobra_Fast ниже. Используйте PDO :: prepare для подготовки ваших операторов SQL со связанными параметрами.
user12345

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 вместо 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, но избегая ошибочной опции charset (как упомянуто выше):

$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 (доступные команды для каждого типа БД см. На подстраницах php.net/manual/de/pdo.drivers.php ). Но это именно то, о чем просил ОП.
Jpsy

передача charset=utf8в строку DSN работает! Я пытался выяснить проблему по адресу groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
Хари К.Т.,

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.
Jan

2
Да, и никогда не определяйте пароль вашей базы данных. Они глобальны, как суперглобалы, и это плохо, когда вы работаете с паролями.
Xesau

2

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

В phpmyadmin вы можете увидеть параметры сортировки, щелкнув базу данных и выбрав операции. Если вы попытаетесь создать таблицы с другим сопоставлением, чем ваша база данных, ваши таблицы все равно получат сопоставление базы данных.

Поэтому убедитесь, что сопоставление для вашей базы данных прямо перед созданием таблиц. Надеюсь, это сэкономит кому-то несколько часов LOL


1
«Если вы попытаетесь создать таблицы с другим сопоставлением, чем ваша база данных, ваши таблицы все равно получат сопоставление базы данных» - я не думаю, что это правильно. Таблица сортировки имеет приоритет над базой данных. dev.mysql.com/doc/refman/5.5/en/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

-1

$ con = new PDO ("mysql: host = $ dbhost; dbname = $ database; charset = $ encoding ", "$ dbuser", "$ dbpassword");

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.