PHP PDO: Zeichensatz, Namen setzen?


188

Ich hatte dies zuvor in meiner normalen mysql_ * -Verbindung:

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

Benötige ich es für die gU? Und wo soll ich es haben?

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

10
"SET NAMES utf8" sollte wegen SQL-Injection vermieden werden. Weitere Informationen finden Sie unter php.net/manual/en/mysqlinfo.concepts.charset.php .
masakielastic

Wenn Sie Probleme mit dem Zeichensatz haben, haben Sie möglicherweise keine andere Wahl, als auf utf8 zu setzen. Ich denke, das Mitnehmen sollte die Verbindungszeichenfolge verwenden, wie von Cobra_Fast unten gezeigt. Verwenden Sie PDO :: prepare, um Ihre SQL-Anweisungen mit gebundenen Parametern vorzubereiten.
user12345

1
@masakielastic, wie sollen wir dann die Kollatierung als "SET NAMES utf8 COLLATE utf8_unicode_ci"
angeben

Antworten:


457

Sie haben es in Ihrer Verbindungszeichenfolge wie:

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

Vor PHP 5.3.6 wurde die Zeichensatzoption jedoch ignoriert. Wenn Sie eine ältere Version von PHP verwenden, müssen Sie dies folgendermaßen tun:

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

15
Es ist erwähnenswert, dass sich dieses Verhalten in 5.3.6 geändert hat und jetzt ordnungsgemäß funktioniert.
igorw

15
sollte utf8 anstelle von UTF-8 "mysql: host = $ host; dbname = $ db; charset = utf8" sein
od3n

3
Ignorieren Sie die folgenden Antworten, wenn Sie eine aktuelle Version von PHP verwenden: In PHP 5.3.8 funktioniert dies einwandfrei.
Kasimir

4
Muss ich in diesem Fall auch die Sortierung angeben? Wie zum Beispiel 'SET NAMES utf8 COLLATE utf8_unicode_ci'?
Datasn.io

2
Vielen Dank! Rettete meinen Tag!
Aleksandr

64

Vor PHP 5.3.6 wurde die Zeichensatzoption ignoriert. Wenn Sie eine ältere Version von PHP verwenden, müssen Sie dies folgendermaßen tun:

<?php

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

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

?>

1
Hinweis für Mods: Dies ist die richtige Antwort. Sie wurde ein Jahr vor der Bearbeitung dieser Informationen in der akzeptierten Antwort veröffentlicht.
Dotancohen

42

Dies ist wahrscheinlich der eleganteste Weg, dies zu tun.
Direkt im PDO-Konstruktoraufruf, aber unter Vermeidung der fehlerhaften Zeichensatzoption (wie oben erwähnt):

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

Funktioniert super für mich.


1
Mein Verständnis ist, dass dies auch für PHP 5.3.0 fehlerhaft ist. In diesem Fall müssen Sie die Option in das Array eingeben, indem Sie auf die Nummer und nicht auf den Namen wie folgt verweisen : array(1002 => 'SET NAMES utf8',...).
JDelage

Danke für den Tipp! Ich verwende den obigen Code erfolgreich auf mehreren Produktionssystemen, auf denen verschiedene 5.3.X-Versionen von PHP ausgeführt werden, aber tatsächlich ist keine von ihnen 5.3.0.
Jpsy

4
Ich
denke,

Richtig, MYSQL_ATTR_INIT_COMMAND ist nur für MySQL-Datenbanken verfügbar (verfügbare Befehle für jeden DB-Typ finden Sie auf den Unterseiten von php.net/manual/de/pdo.drivers.php ). Aber genau darum hat das OP gebeten.
Jpsy

Das Übergeben charset=utf8des dsn-Strings funktioniert! Ich habe versucht, das Problem unter groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
Hari KT

16

Der Vollständigkeit halber gibt es drei Möglichkeiten, die Codierung festzulegen, wenn eine Verbindung zu MySQL über PDO hergestellt wird. Welche verfügbar sind, hängt von Ihrer PHP-Version ab. Die Reihenfolge der Präferenzen wäre:

  1. charset Parameter in der DSN-Zeichenfolge
  2. Führen Sie SET NAMES utf8mit PDO::MYSQL_ATTR_INIT_COMMANDAnschlussmöglichkeit
  3. Führen Sie SET NAMES utf8manuell

Dieser Beispielcode implementiert alle drei:

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

Alle drei Aufgaben zu erledigen ist wahrscheinlich übertrieben (es sei denn, Sie schreiben eine Klasse, die Sie verteilen oder wiederverwenden möchten).


1
Gibt es ein ODBC / Access-Äquivalent? Ich habe jetzt eine funktionierende Oracle- und MySQL PHP PDO UTF8-Verbindung, aber ich kann sie nicht für ODBC / Access zum Laufen bringen.
Jan

2
Oh und DEFINIEREN Sie niemals Ihr Datenbankkennwort. Sie sind so global wie Superglobale, und das ist keine gute Sache, wenn Sie mit Passwörtern arbeiten.
Xesau

2

Ich möchte nur hinzufügen, dass Sie sicherstellen müssen, dass Ihre Datenbank mit COLLATE utf8_general_ci oder einer beliebigen Kollatierung erstellt wird. Andernfalls erhalten Sie möglicherweise eine andere als beabsichtigt.

In phpmyadmin können Sie die Sortierung anzeigen, indem Sie auf Ihre Datenbank klicken und Operationen auswählen. Wenn Sie versuchen, Tabellen mit einer anderen Sortierung als Ihrer Datenbank zu erstellen, erhalten Ihre Tabellen ohnehin die Datenbanksortierung.

Stellen Sie daher sicher, dass die Sortierung für Ihre Datenbank korrekt ist, bevor Sie Tabellen erstellen. Hoffe das spart jemandem ein paar Stunden lol


1
"Wenn Sie versuchen, Tabellen mit einer anderen Sortierung als Ihrer Datenbank zu erstellen, erhalten Ihre Tabellen sowieso die Datenbanksortierung" - ich denke nicht, dass dies korrekt ist. Die Tabellensortierung hat Vorrang vor der Sortierung der Datenbank. dev.mysql.com/doc/refman/5.5/en/charset-table.html
bescheidene_wolf

2

Ich denke, Sie benötigen eine zusätzliche Abfrage, da die Zeichensatzoption im DSN tatsächlich ignoriert wird. Siehe Link im Kommentar der anderen Antwort.

Schauen Sie sich an, wie Drupal 7 es macht 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
Obwohl diese Antwort wahrscheinlich richtig und nützlich ist, wird sie bevorzugt, wenn Sie eine Erklärung hinzufügen, um zu erklären, wie sie zur Lösung des Problems beiträgt. Dies ist besonders in Zukunft nützlich, wenn eine Änderung (möglicherweise ohne Bezug) dazu führt, dass sie nicht mehr funktioniert und die Benutzer verstehen müssen, wie sie einmal funktioniert hat.
Erty Seidohl

0

Ich teste diesen Code und

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

Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Rollstuhlfahrer

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

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.