PHP DOP: set di caratteri, impostare i nomi?


189

Ho avuto questo in precedenza nella mia normale connessione mysql_ *:

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

Ne ho bisogno per il DOP? E dove dovrei averlo?

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

10
"SET NAMES utf8" dovrebbe essere evitato a causa dell'iniezione SQL. Vedi php.net/manual/en/mysqlinfo.concepts.charset.php per i dettagli.
masakielastic,

se hai problemi con i set di caratteri, potresti non avere altra scelta che impostare su utf8. Penso che il take away dovrebbe usare la stringa di connessione come mostrato da Cobra_Fast di seguito. Utilizzare PDO :: preparazione per preparare le istruzioni SQL con parametri associati.
user12345

1
@masakielastic, allora come dovremmo specificare le regole di confronto come "SET NAMES utf8 COLLATE utf8_unicode_ci"
datasn.io

Risposte:


460

Lo avrai nella tua stringa di connessione come:

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

TUTTAVIA, prima di PHP 5.3.6, l'opzione charset era ignorata. Se stai utilizzando una versione precedente di PHP, devi farlo in questo modo:

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

15
Vale la pena notare che questo comportamento è cambiato in 5.3.6 e ora funziona correttamente.
venerdì

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

3
Ignora le risposte di seguito se stai utilizzando una versione aggiornata di PHP: funziona perfettamente in php 5.3.8.
Kasimir,

4
Devo specificare anche le regole di confronto in questo caso? Come 'SET NAMES utf8 COLLATE utf8_unicode_ci'?
datasn.io,

2
Grazie! Mi hai salvato la giornata!
Aleksandr,

64

Prima di PHP 5.3.6, l'opzione charset era ignorata. Se stai utilizzando una versione precedente di PHP, devi farlo in questo modo:

<?php

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

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

?>

1
Nota per le mod: questa è la risposta corretta ed è stata pubblicata un anno prima che alla risposta accettata venissero modificate queste informazioni.
dotancohen,

42

Questo è probabilmente il modo più elegante per farlo.
Proprio nella chiamata del costruttore DOP, evitando l'opzione buggy charset (come menzionato sopra):

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

Funziona benissimo per me.


1
La mia comprensione è che anche questo è un bug per php 5.3.0. In questo caso è necessario inserire l'opzione nella matrice facendo riferimento il suo numero piuttosto che il suo nome come questo: array(1002 => 'SET NAMES utf8',...).
JDelage,

Grazie per il suggerimento! Sto usando il codice sopra riportato con successo su più sistemi di produzione che eseguono diverse versioni 5.3.X di PHP, ma in realtà nessuno di questi è 5.3.0.
Jpsy,

4
Penso che potrebbe essere più elegante senza opzioni specifiche per il database
Aalex Gabi,

È vero, MYSQL_ATTR_INIT_COMMAND è disponibile solo per i database MySQL (per i comandi disponibili per ogni tipo di db consultare le pagine secondarie di php.net/manual/de/pdo.drivers.php ). Ma questo è esattamente ciò che l'OP ha richiesto.
Jpsy,

passando charset=utf8nella stringa dsn funziona! Stavo cercando di capire il problema su groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
Hari KT

16

Per completezza, in realtà ci sono tre modi per impostare la codifica quando ci si collega a MySQL da PDO e quali sono disponibili dipendono dalla versione di PHP. L'ordine di preferenza sarebbe:

  1. charset parametro nella stringa DSN
  2. Esegui SET NAMES utf8con PDO::MYSQL_ATTR_INIT_COMMANDopzione di connessione
  3. Esegui SET NAMES utf8manualmente

Questo codice di esempio implementa tutti e tre:

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

Fare tutte e tre le cose è probabilmente eccessivo (a meno che tu non stia scrivendo una classe che prevedi di distribuire o riutilizzare).


1
Esiste un ODBC / equivalente equivalente? Ora ho una connessione Oracle e MySQL PHP PDO UTF8 funzionante, ma non riesco a farlo funzionare per ODBC / Access.
Jan

2
Oh e mai DEFINIRE la password del database. Sono globali come i superglobali e non è una buona cosa quando lavori con le password.
Xesau,

2

Voglio solo aggiungere che devi assicurarti che il tuo database sia stato creato con COLLATE utf8_general_ci o qualunque altra raccolta tu voglia usare, altrimenti potresti finire con un altro del previsto.

In phpmyadmin puoi vedere le regole di confronto facendo clic sul tuo database e scegli le operazioni. Se provi a creare tabelle con regole di confronto diverse dal tuo database, le tue tabelle finiranno comunque con le regole di confronto del database.

Quindi assicurati che il confronto per il tuo database sia giusto prima di creare le tabelle. Spero che questo salvi qualcuno qualche ora lol


1
"Se provi a creare tabelle con regole di confronto diverse dal tuo database, le tue tabelle finiranno comunque con le regole di confronto del database" - Non penso che sia corretto. Le regole di confronto delle tabelle hanno la precedenza sulle regole di confronto del database. dev.mysql.com/doc/refman/5.5/en/charset-table.html
humble_wolf

2

Penso che tu abbia bisogno di una query aggiuntiva perché l'opzione charset nel DSN è in realtà ignorata. vedi link pubblicato nel commento dell'altra risposta.

Guardando come Drupal 7 lo sta facendo in 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
Sebbene questa risposta sia probabilmente corretta e utile, è preferibile includere una spiegazione insieme per spiegare come aiuta a risolvere il problema. Ciò diventa particolarmente utile in futuro, se c'è un cambiamento (possibilmente non correlato) che lo fa smettere di funzionare e gli utenti devono capire come funzionava una volta.
Erty Seidohl,

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

Ho testato questo codice e

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

Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo al perché e / o al modo in cui questo codice risponde alla domanda migliora il suo valore a lungo termine.
rollstuhlfahrer,

-1

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.