PHP PDO: jeu de caractères, noms de jeu?


192

J'avais ceci précédemment dans ma connexion mysql_ * normale:

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

En ai-je besoin pour l'AOP? Et où dois-je l'avoir?

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

10
"SET NAMES utf8" doit être évité en raison de l'injection SQL. Voir php.net/manual/en/mysqlinfo.concepts.charset.php pour les détails.
masakielastic

si vous avez des problèmes de jeu de caractères, vous n'aurez peut-être pas d'autre choix que de définir utf8. Je pense que le résultat devrait être d'utiliser la chaîne de connexion comme indiqué par Cobra_Fast ci-dessous. Utilisez PDO :: prepare pour préparer vos instructions SQL avec des paramètres liés.
user12345

1
@masakielastic, alors comment devrions-nous spécifier le classement comme "SET NAMES utf8 COLLATE utf8_unicode_ci"
datasn.io

Réponses:


468

Vous l'aurez dans votre chaîne de connexion comme:

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

CEPENDANT, avant PHP 5.3.6, l'option charset était ignorée. Si vous utilisez une ancienne version de PHP, vous devez le faire comme ceci:

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

15
Il convient de noter que ce comportement a changé dans la version 5.3.6 et qu'il fonctionne désormais correctement.
igorw

15
shoudle be utf8 instaead of UTF-8 "mysql: host = $ host; dbname = $ db; charset = utf8"
od3n

3
Ignorez les réponses ci-dessous si vous utilisez une version à jour de PHP: cela fonctionne très bien en php 5.3.8.
kasimir

4
Dois-je également spécifier le classement dans ce cas? Tels que «SET NAMES utf8 COLLATE utf8_unicode_ci»?
datasn.io

2
Merci! J'ai sauvé ma journée!
Aleksandr

62

Avant PHP 5.3.6, l'option charset était ignorée. Si vous utilisez une ancienne version de PHP, vous devez le faire comme ceci:

<?php

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

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

?>

1
Note aux mods: C'est la bonne réponse, et elle a été publiée un an avant que la réponse acceptée ne contienne cette information.
dotancohen

41

C'est probablement la manière la plus élégante de le faire.
Directement dans l'appel du constructeur PDO, mais en évitant l'option buggy charset (comme mentionné ci-dessus):

$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"
  )
);

Fonctionne très bien pour moi.


1
Ma compréhension est que cela est également bogué pour php 5.3.0. Dans ce cas , vous devez entrer l'option dans le tableau en faisant référence à son numéro plutôt que son nom comme celui - ci: array(1002 => 'SET NAMES utf8',...).
JDelage

Merci pour l'indice! J'utilise le code ci-dessus avec succès sur plusieurs systèmes de production exécutant différentes versions 5.3.X de PHP, mais en réalité aucun d'entre eux n'est 5.3.0.
Jpsy

4
Je pense que cela pourrait être plus élégant sans options spécifiques à la base de données
Aalex Gabi

Certes, le MYSQL_ATTR_INIT_COMMAND n'est disponible que pour les bases de données MySQL (pour les commandes disponibles pour chaque type de base de données, voir les sous-pages de php.net/manual/de/pdo.drivers.php ). Mais c'est exactement ce que le PO a demandé.
Jpsy

passer charset=utf8dans la chaîne DSN fonctionne! J'essayais de résoudre
Hari KT

15

Pour être complet, il existe en fait trois façons de définir l'encodage lors de la connexion à MySQL à partir de PDO et celles qui sont disponibles dépendent de votre version de PHP. L'ordre de préférence serait:

  1. charset paramètre dans la chaîne DSN
  2. Exécuter SET NAMES utf8avec l' PDO::MYSQL_ATTR_INIT_COMMANDoption de connexion
  3. Exécuter SET NAMES utf8manuellement

Cet exemple de code implémente les trois:

<?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);
}

Faire les trois est probablement exagéré (à moins que vous n'écrivez un cours que vous prévoyez de distribuer ou de réutiliser).


1
Existe-t-il un équivalent ODBC / Access? J'ai maintenant une connexion Oracle et MySQL PHP PDO UTF8 fonctionnelle mais je ne peux pas la faire fonctionner pour ODBC / Access.
Jan

2
Oh et ne définissez jamais le mot de passe de votre base de données. Ils sont aussi mondiaux que les super-globaux, et ce n'est pas une bonne chose lorsque vous travaillez avec des mots de passe.
Xesau

1

Je veux juste ajouter que vous devez vous assurer que votre base de données est créée avec COLLATE utf8_general_ci ou selon le classement que vous souhaitez utiliser, sinon vous pourriez vous retrouver avec un autre que prévu.

Dans phpmyadmin, vous pouvez voir le classement en cliquant sur votre base de données et en choisissant les opérations. Si vous essayez de créer des tables avec un autre classement que votre base de données, vos tables se retrouveront de toute façon avec le classement de la base de données.

Assurez-vous donc que le classement de votre base de données est correct avant de créer des tables. J'espère que cela sauve à quelqu'un quelques heures lol


1
"Si vous essayez de créer des tables avec un autre classement que votre base de données, vos tables finiront de toute façon avec le classement de la base de données" - Je ne pense pas que ce soit correct. Le classement des tables est prioritaire sur le classement de la base de données. dev.mysql.com/doc/refman/5.5/en/charset-table.html
humble_wolf

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

1
Bien que cette réponse soit probablement correcte et utile, il est préférable que vous y ajoutiez des explications pour expliquer comment elle aide à résoudre le problème. Cela devient particulièrement utile à l'avenir, s'il y a un changement (peut-être sans rapport) qui l'empêche de fonctionner et que les utilisateurs doivent comprendre comment cela fonctionnait autrefois.
Erty Seidohl

1

Je pense que vous avez besoin d'une requête supplémentaire car l'option charset dans le DSN est en fait ignorée. voir le lien posté dans le commentaire de l'autre réponse.

En regardant comment Drupal 7 le fait dans 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');
}

0
$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 );   

-1

Je teste ce code et

$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'];
}

Bien que ce code puisse répondre à la question, fournir un contexte supplémentaire concernant la raison et / ou la manière dont ce code répond à la question améliore sa valeur à long terme.
rollstuhlfahrer
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.