PHP PDO: bộ ký tự, đặt tên?


188

Tôi đã có điều này trước đây trong kết nối mysql_ * bình thường của tôi:

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

Tôi có cần nó cho PDO không? Và tôi nên có nó ở đâu?

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

10
Nên tránh "TÊN TÊN utf8" vì SQL tiêm. Xem php.net/manual/en/mysqlinfo.con accept.charset.php để biết chi tiết.
masakielastic

nếu bạn có vấn đề về bộ ký tự thì bạn có thể không có lựa chọn nào khác ngoài đặt thành utf8. Tôi nghĩ rằng nên sử dụng chuỗi kết nối như được hiển thị bởi Cobra_Fast bên dưới. Sử dụng PDO :: chuẩn bị để chuẩn bị các câu lệnh SQL của bạn với các tham số ràng buộc.
user12345

1
@masakielastic, vậy thì chúng ta nên chỉ định đối chiếu như thế nào là "SET NAMES utf8 COLLATE utf8_unicode_ci"
datan.io

Câu trả lời:


457

Bạn sẽ có nó trong chuỗi kết nối của bạn như:

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

TUY NHIÊN, trước PHP 5.3.6, tùy chọn bộ ký tự đã bị bỏ qua. Nếu bạn đang chạy phiên bản PHP cũ hơn, bạn phải làm như thế này:

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

15
Điều đáng chú ý là hành vi này đã thay đổi trong 5.3.6 và hiện đang hoạt động chính xác.
igorw

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

3
Bỏ qua các câu trả lời dưới đây nếu bạn đang sử dụng phiên bản cập nhật của PHP: nó chỉ hoạt động tốt trong php 5.3.8.
kas Elli

4
Tôi có phải chỉ định đối chiếu trong trường hợp này không? Chẳng hạn như 'THIẾT LẬP TÊN utf8 THU THẬP utf8_unicode_ci'?
datan.io

2
Cảm ơn! Cứu ngày của tôi!
Aleksandr

64

Trước PHP 5.3.6, tùy chọn bộ ký tự đã bị bỏ qua. Nếu bạn đang chạy phiên bản PHP cũ hơn, bạn phải làm như thế này:

<?php

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

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

?>

1
Lưu ý với các mod: Đây là câu trả lời đúng và nó đã được đăng một năm trước khi câu trả lời được chấp nhận có thông tin này được chỉnh sửa.
dotancohen

42

Đây có lẽ là cách thanh lịch nhất để làm điều đó.
Ngay trong lệnh gọi hàm tạo PDO, nhưng tránh tùy chọn bảng mã lỗi (như đã đề cập ở trên):

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

Làm việc tuyệt vời cho tôi.


1
Tôi hiểu rằng đây cũng là lỗi cho php 5.3.0. Trong trường hợp đó, bạn cần nhập tùy chọn trong mảng bằng cách tham chiếu số của nó thay vì tên của nó như sau : array(1002 => 'SET NAMES utf8',...).
JDelage

Cảm ơn các gợi ý! Tôi đang sử dụng mã trên thành công trên nhiều hệ thống sản xuất chạy các phiên bản PHP 5.3.X khác nhau, nhưng thực tế không có mã nào trong số đó là 5.3.0.
Jpsy

4
Tôi cho rằng nó có thể thanh lịch hơn nếu không có các tùy chọn cụ thể về cơ sở dữ liệu
Aalex Gabi

Đúng, MYSQL_ATTR_INIT_COMMAND chỉ khả dụng cho cơ sở dữ liệu MySQL (đối với các lệnh có sẵn cho từng loại db, hãy xem các trang phụ của php.net/manual/de/pdo.drivers.php ). Nhưng đây là chính xác những gì OP đã yêu cầu.
Jpsy

truyền charset=utf8trong chuỗi DSN hoạt động! Tôi đã cố gắng tìm ra vấn đề tại nhóm.google.com/d/msg/auraphp/syMS26Rz
Hari KT

16

Để hoàn thiện, thực tế có ba cách để đặt mã hóa khi kết nối với MySQL từ PDO và cách nào khả dụng tùy thuộc vào phiên bản PHP của bạn. Thứ tự ưu tiên sẽ là:

  1. charset tham số trong chuỗi DSN
  2. Chạy SET NAMES utf8với PDO::MYSQL_ATTR_INIT_COMMANDtùy chọn kết nối
  3. Chạy SET NAMES utf8thủ công

Mã mẫu này thực hiện cả ba:

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

Làm cả ba có lẽ là quá mức cần thiết (trừ khi bạn viết một lớp bạn dự định phân phối hoặc sử dụng lại).


1
Có ODBC / Access tương đương không? Bây giờ tôi có kết nối PDF UTF8 của Oracle và MySQL đang hoạt động nhưng tôi không thể làm cho nó hoạt động được với ODBC / Access.
Jan

2
Oh và không bao giờ xác định mật khẩu cơ sở dữ liệu của bạn. Chúng toàn cầu như các siêu sao và đó không phải là một điều tốt khi bạn làm việc với mật khẩu.
Xesau

2

Tôi chỉ muốn thêm rằng bạn phải đảm bảo rằng cơ sở dữ liệu của bạn được tạo bằng COLLATE utf8_general_ci hoặc bất kỳ đối chiếu nào bạn muốn sử dụng, Khác bạn có thể kết thúc với một cơ sở khác ngoài dự định.

Trong phpmyadmin, bạn có thể xem đối chiếu bằng cách nhấp vào cơ sở dữ liệu của mình và chọn thao tác. Nếu bạn thử tạo các bảng với đối chiếu khác ngoài cơ sở dữ liệu của mình, các bảng của bạn sẽ kết thúc với bất kỳ đối chiếu cơ sở dữ liệu nào.

Vì vậy, hãy đảm bảo đối chiếu cho cơ sở dữ liệu của bạn là đúng trước khi tạo bảng. Hy vọng điều này sẽ cứu ai đó vài giờ lol


1
"Nếu bạn thử tạo các bảng với đối chiếu khác ngoài cơ sở dữ liệu của mình, các bảng của bạn sẽ kết thúc với bất kỳ đối chiếu cơ sở dữ liệu nào" - Tôi không nghĩ đó là chính xác. Đối chiếu bảng được ưu tiên hơn đối chiếu cơ sở dữ liệu. dev.mysql.com/doc/refman/5.5/en/charset-table.html
humble_wolf

2

Tôi nghĩ rằng bạn cần một truy vấn bổ sung vì tùy chọn bộ ký tự trong DSN thực sự bị bỏ qua. xem liên kết được đăng trong bình luận của câu trả lời khác.

Nhìn vào cách Drupal 7 đang làm điều đó trong http://api.drupal.org/api/drupal/includes--database--mysql--database.inc/feft/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
Mặc dù câu trả lời này có thể đúng và hữu ích, nhưng nó được ưu tiên nếu bạn bao gồm một số giải thích cùng với nó để giải thích cách nó giúp giải quyết vấn đề. Điều này trở nên đặc biệt hữu ích trong tương lai, nếu có một sự thay đổi (có thể không liên quan) khiến nó ngừng hoạt động và người dùng cần phải hiểu nó đã hoạt động như thế nào.
Erty Seidohl

0

Tôi kiểm tra mã này và

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

Mặc dù mã này có thể trả lời câu hỏi, cung cấp ngữ cảnh bổ sung về lý do và / hoặc cách mã này trả lời câu hỏi cải thiện giá trị lâu dài của nó.
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 = new PDO ("mysql: host = $ dbhost; dbname = $ cơ sở dữ liệu; charset = $ mã hóa ", "$ dbuser", "$ dbpassword");

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.