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));
Karem
la source
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");
Cobra_Fast
la source
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");

?>
9nix00
la source
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.

Jpsy
la source
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).

Álvaro González
la source
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

Medda86
la source
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);
gauravbhai daxini
la source
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');
}
Berdir
la source
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 );   
Jayanit Satani
la source
-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'];
}
élite andot
la source
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