PHP PDO: ชุดอักขระตั้งชื่อ?


189

ฉันมีสิ่งนี้ก่อนหน้านี้ในการเชื่อมต่อ mysql_ * ปกติของฉัน:

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

ฉันต้องการมันสำหรับ PDO หรือไม่? และฉันควรจะได้ที่ไหน

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

10
"SET NAMES utf8" ควรหลีกเลี่ยงเนื่องจากการฉีด SQL ดูphp.net/manual/th/mysqlinfo.concepts.charset.phpเพื่อดูรายละเอียด
masakielastic

หากคุณมีปัญหาชุดอักขระคุณอาจไม่มีทางเลือกนอกจากตั้งค่าเป็น utf8 ฉันคิดว่าสิ่งที่ควรกลับบ้านควรใช้สตริงการเชื่อมต่อตามที่แสดงโดย Cobra_Fastด้านล่าง ใช้ PDO :: เตรียมพร้อมเพื่อเตรียมงบ SQL ของคุณด้วยพารามิเตอร์ที่ผูก
user12345

1
@masakielastic แล้วเราควรระบุ collation เป็น "SET NAMES utf8 COLLATE utf8_unicode_ci" ได้อย่างไร
datasn.io

คำตอบ:


460

คุณจะมีมันในสตริงการเชื่อมต่อของคุณเช่น:

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

อย่างไรก็ตามก่อน PHP 5.3.6 ตัวเลือกชุดอักขระจะถูกละเว้น หากคุณใช้ PHP รุ่นเก่ากว่าคุณต้องทำดังนี้:

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

15
เป็นที่น่าสังเกตว่าพฤติกรรมนี้เปลี่ยนไปใน 5.3.6 และตอนนี้ทำงานได้อย่างถูกต้อง
igorw

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

3
ละเว้นคำตอบด้านล่างหากคุณใช้ PHP รุ่นล่าสุด: ใช้งานได้ดีใน php 5.3.8
kasimir

4
ฉันต้องระบุการเปรียบเทียบในกรณีนี้ด้วยหรือไม่ เช่น 'SET NAMES utf8 COLLATE utf8_unicode_ci' หรือไม่
datasn.io

2
ขอบคุณ! บันทึกวันของฉัน!
Aleksandr

64

ก่อนหน้า PHP 5.3.6 ตัวเลือกชุดอักขระจะถูกละเว้น หากคุณใช้ PHP รุ่นเก่ากว่าคุณต้องทำดังนี้:

<?php

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

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

?>

1
หมายเหตุถึง mods: นี่คือคำตอบที่ถูกต้องและมันถูกโพสต์หนึ่งปีก่อนคำตอบที่ยอมรับได้มีการแก้ไขข้อมูลนี้
dotancohen

42

นี่อาจเป็นวิธีที่หรูหราที่สุดที่จะทำ
ขวาในการเรียกใช้งานตัวสร้าง PDO แต่หลีกเลี่ยงตัวเลือกชุดอักขระ buggy (ดังที่กล่าวข้างต้น):

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

ใช้งานได้ดีสำหรับฉัน


1
ความเข้าใจของฉันคือว่านี้เป็นรถสำหรับ php 5.3.0 array(1002 => 'SET NAMES utf8',...)ในกรณีที่คุณจำเป็นต้องป้อนตัวเลือกในอาร์เรย์โดยอ้างอิงจำนวนมากกว่าชื่อของมันเช่นนี้
JDelage

ขอบคุณสำหรับคำใบ้! ฉันใช้รหัสข้างต้นได้สำเร็จบนระบบการผลิตหลายระบบที่ใช้ PHP เวอร์ชัน 5.3.X ที่แตกต่างกัน แต่จริงๆแล้วไม่มีในนั้นคือ 5.3.0
Jpsy

4
ฉันคิดว่ามันอาจจะดูหรูหรากว่านี้หากไม่มีตัวเลือกฐานข้อมูล
Aalex Gabi

จริง, MYSQL_ATTR_INIT_COMMAND จะใช้ได้เฉพาะกับฐานข้อมูล MySQL เท่านั้น (สำหรับคำสั่งที่มีให้สำหรับแต่ละประเภทฐานข้อมูลดูที่หน้าย่อยของphp.net/manual/de/pdo.drivers.php ) แต่นี่คือสิ่งที่ OP ขอมา
Jpsy

ผ่านcharset=utf8ในสตริง dsn ทำงาน! ฉันพยายามหาปัญหาที่groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
Hari KT

16

เพื่อความสมบูรณ์มีสามวิธีในการตั้งค่าการเข้ารหัสเมื่อเชื่อมต่อกับ MySQL จาก PDO และตัวเลือกใดที่ใช้ได้ขึ้นอยู่กับเวอร์ชัน PHP ของคุณ ลำดับของการตั้งค่าจะเป็น:

  1. charset พารามิเตอร์ในสตริง DSN
  2. เรียกใช้SET NAMES utf8ด้วยPDO::MYSQL_ATTR_INIT_COMMANDตัวเลือกการเชื่อมต่อ
  3. เรียกใช้SET NAMES utf8ด้วยตนเอง

โค้ดตัวอย่างนี้ใช้ทั้งสาม:

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

การทำทั้งสามอย่างนั้นอาจเกินความเป็นจริง (เว้นแต่คุณจะเขียนชั้นเรียนที่คุณวางแผนจะแจกจ่ายหรือนำมาใช้ซ้ำ)


1
มี ODBC / Access ที่เทียบเท่าหรือไม่ ตอนนี้ฉันมีการเชื่อมต่อ Oracle และ MySQL PHP PDO UTF8 แต่ฉันไม่สามารถใช้กับ ODBC / Access ได้
Jan

2
โอ้และไม่เคยกำหนดรหัสผ่านฐานข้อมูลของคุณ พวกเขาอยู่ในระดับโลกในฐานะ superglobals และนั่นไม่ใช่สิ่งที่ดีเมื่อคุณทำงานกับรหัสผ่าน
Xesau

2

ฉันแค่ต้องการเพิ่มว่าคุณต้องทำให้แน่ใจว่าฐานข้อมูลของคุณถูกสร้างขึ้นด้วย COLLATE utf8_general_ci หรือการเปรียบเทียบใดที่คุณต้องการใช้มิฉะนั้นคุณอาจจะจบลงด้วยอีกอย่างที่ตั้งใจไว้

ใน phpmyadmin คุณสามารถดูการเรียงโดยคลิกฐานข้อมูลของคุณและเลือกการดำเนินการ หากคุณลองสร้างตารางที่มีการเปรียบเทียบใหม่กว่าฐานข้อมูลของคุณตารางของคุณจะจบลงด้วยการเปรียบเทียบฐานข้อมูลต่อไป

เพื่อให้แน่ใจว่าการเปรียบเทียบสำหรับฐานข้อมูลของคุณถูกต้องก่อนสร้างตาราง หวังว่านี้ช่วยให้ใครบางคนไม่กี่ชั่วโมงฮ่า ๆ


1
"ถ้าคุณลองสร้างตารางที่มีการเปรียบเทียบใหม่กว่าฐานข้อมูลของคุณตารางของคุณจะจบลงด้วยการเปรียบเทียบฐานข้อมูลต่อไป" - ฉันไม่คิดว่ามันถูกต้อง การเปรียบเทียบตารางจะมีความสำคัญเหนือกว่าการเปรียบเทียบของฐานข้อมูล dev.mysql.com/doc/refman/5.5/en/charset-table.html
humble_wolf

2

ฉันคิดว่าคุณต้องการแบบสอบถามเพิ่มเติมเนื่องจากตัวเลือกชุดอักขระใน DSN ถูกละเว้นจริง เห็นลิงค์โพสต์ในความคิดเห็นของคำตอบอื่น ๆ

ดูวิธีที่ Drupal 7 ใช้ใน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
แม้ว่าคำตอบนี้อาจจะถูกต้องและมีประโยชน์ แต่ก็เป็นที่ต้องการถ้าคุณมีคำอธิบายมาด้วยเพื่ออธิบายว่ามันช่วยแก้ปัญหาได้อย่างไร สิ่งนี้จะเป็นประโยชน์อย่างยิ่งในอนาคตหากมีการเปลี่ยนแปลง (อาจไม่เกี่ยวข้อง) ที่ทำให้หยุดทำงานและผู้ใช้จำเป็นต้องเข้าใจว่ามันทำงานอย่างไร
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

ฉันทดสอบรหัสนี้และ

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

ในขณะที่รหัสนี้อาจตอบคำถาม แต่มีบริบทเพิ่มเติมเกี่ยวกับสาเหตุและ / หรือวิธีการที่รหัสนี้ตอบคำถามช่วยปรับปรุงมูลค่าระยะยาว
rollstuhlfahrer

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.