PHP PDO: charset, tetapkan nama?

189

Saya memiliki ini sebelumnya di koneksi mysql_ * normal saya:

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

Apakah saya membutuhkannya untuk PDO? Dan di mana saya harus memilikinya?

$connect = new PDO("mysql:host=$host;dbname=$db", $user, $pass, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
Karem
sumber
10
"SET NAMES utf8" harus dihindari karena injeksi SQL. Lihat php.net/manual/en/mysqlinfo.concepts.charset.php untuk detailnya.
masakielastic
jika Anda memiliki masalah charset maka Anda mungkin tidak punya pilihan selain mengatur ke utf8. Saya pikir take away harus menggunakan koneksi string seperti yang ditunjukkan oleh Cobra_Fast di bawah ini. Gunakan PDO :: persiapan untuk menyiapkan pernyataan SQL Anda dengan parameter terikat.
user12345
1
@masakielastic, lalu bagaimana kita menentukan collation sebagai "SET NAMES utf8 COLLATE utf8_unicode_ci"
datan.io

Jawaban:

460

Anda akan memilikinya di string koneksi Anda seperti:

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

NAMUN, sebelum PHP 5.3.6, opsi charset diabaikan. Jika Anda menjalankan versi PHP yang lebih lama, Anda harus melakukannya seperti ini:

$dbh = new PDO("mysql:$connstr",  $user, $password);
$dbh->exec("set names utf8");
Cobra_Fast
sumber
15
Perlu dicatat bahwa perilaku ini berubah di 5.3.6, dan sekarang berfungsi dengan benar.
igorw
15
shoudle be utf8 instaead dari UTF-8 "mysql: host = $ host; dbname = $ db; charset = utf8"
od3n
3
Abaikan jawaban di bawah ini jika Anda menggunakan versi PHP terbaru: ini berfungsi dengan baik di php 5.3.8.
kasimir
4
Apakah saya juga harus menentukan susunan dalam kasus ini? Seperti 'SET NAMES utf8 COLLATE utf8_unicode_ci'?
datan.io
2
Terima kasih! Selamatkan hari saya!
Aleksandr
64

Sebelum PHP 5.3.6, opsi charset diabaikan. Jika Anda menjalankan versi PHP yang lebih lama, Anda harus melakukannya seperti ini:

<?php

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

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

?>
9nix00
sumber
1
Catatan untuk mod: Ini adalah jawaban yang benar, dan itu diposting satu tahun sebelum jawaban yang diterima memiliki informasi ini diedit ke dalamnya.
dotancohen
42

Ini mungkin cara paling elegan untuk melakukannya.
Tepat di panggilan konstruktor PDO, tetapi menghindari opsi charset buggy (seperti yang disebutkan di atas):

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

Bekerja bagus untukku.

Jpsy
sumber
1
Pemahaman saya adalah bahwa ini juga buggy untuk php 5.3.0. Dalam hal ini Anda harus memasukkan opsi dalam array dengan referensi nomor dan bukan nama seperti ini: array(1002 => 'SET NAMES utf8',...).
JDelage
Terima kasih atas petunjuknya! Saya menggunakan kode di atas dengan sukses pada beberapa sistem produksi yang menjalankan versi PHP 5.3.X yang berbeda, tetapi sebenarnya tidak satupun dari mereka adalah 5.3.0.
Jpsy
4
Saya berpendapat itu bisa lebih elegan tanpa opsi spesifik database
Aalex Gabi
Benar, MYSQL_ATTR_INIT_COMMAND hanya tersedia untuk database MySQL (untuk perintah yang tersedia untuk setiap jenis db lihat sub-halaman php.net/manual/de/pdo.drivers.php ). Tapi inilah tepatnya yang diminta OP.
Jpsy
lewat charset=utf8di string dsn bekerja! Saya mencoba memecahkan masalah ini di groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
Hari KT
16

Untuk kelengkapan, sebenarnya ada tiga cara untuk mengatur pengkodean saat menghubungkan ke MySQL dari PDO dan mana yang tersedia tergantung pada versi PHP Anda. Urutan preferensi adalah:

  1. charset parameter dalam string DSN
  2. Jalankan SET NAMES utf8dengan PDO::MYSQL_ATTR_INIT_COMMANDopsi koneksi
  3. Jalankan SET NAMES utf8secara manual

Kode contoh ini mengimplementasikan ketiganya:

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

Melakukan ketiganya mungkin berlebihan (kecuali jika Anda menulis kelas Anda berencana untuk mendistribusikan atau menggunakan kembali).

Álvaro González
sumber
1
Apakah ada yang setara dengan ODBC / Akses? Saya sekarang memiliki koneksi Oracle dan MySQL PHP PDO UTF8 yang berfungsi, tetapi saya tidak bisa membuatnya berfungsi untuk ODBC / Access.
Jan
2
Oh dan jangan pernah DEFINE kata sandi database Anda. Mereka sedunia superglobals, dan itu bukan hal yang baik ketika Anda bekerja dengan kata sandi.
Xesau
2

Saya hanya ingin menambahkan bahwa Anda harus memastikan bahwa database Anda dibuat dengan COLLATE utf8_general_ci atau yang mana saja yang ingin Anda gunakan, jika tidak, Anda mungkin berakhir dengan yang lain dari yang dimaksudkan.

Di phpmyadmin Anda dapat melihat susunan dengan mengklik basis data Anda dan memilih operasi. Jika Anda mencoba membuat tabel dengan susunan lain dari basis data Anda, maka meja Anda akan berakhir dengan susunan basis data.

Jadi pastikan pemeriksaan untuk database Anda benar sebelum membuat tabel. Semoga ini bisa menyelamatkan seseorang beberapa jam lagi

Medda86
sumber
1
"Jika Anda mencoba membuat tabel dengan susunan lain selain dari basis data Anda, maka meja Anda akan berakhir dengan susunan basis data" - Saya rasa itu tidak benar. Table collation lebih diutamakan daripada collation database. dev.mysql.com/doc/refman/5.5/en/charset-table.html
humble_wolf
2

Saya pikir Anda memerlukan permintaan tambahan karena opsi charset di DSN sebenarnya diabaikan. lihat tautan yang diposting di komentar dari jawaban lain.

Melihat bagaimana Drupal 7 melakukannya di http://api.drupal.org/api/drupal/includes--database--mysql--database.inc/function/DatabaseConnection_mysql%3A%3A__3truktur/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
sumber
1
$conn = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);
gauravbhai daxini
sumber
1
Meskipun jawaban ini mungkin benar dan bermanfaat, lebih disukai jika Anda menyertakan beberapa penjelasan bersama dengan itu untuk menjelaskan bagaimana itu membantu menyelesaikan masalah. Ini menjadi sangat berguna di masa depan, jika ada perubahan (mungkin tidak terkait) yang menyebabkannya berhenti bekerja dan pengguna perlu memahami bagaimana cara kerjanya.
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 );   
Jayanit Satani
sumber
0

Saya menguji kode ini dan

$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'];
}
andot elit
sumber
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang mengapa dan / atau bagaimana kode ini menjawab pertanyaan meningkatkan nilai jangka panjangnya.
rollstuhlfahrer
-1

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

Dilmurod
sumber