PHP PDO:文字セット、名前の設定?


188

私は以前これを通常の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
SQLインジェクションのため、「SET NAMES utf8」は避けてください。詳細については、php.net / manual / en / mysqlinfo.concepts.charset.phpを参照してください。
masakielastic 2013年

文字セットに問題がある場合は、utf8に設定するしかありません。以下のCobra_Fastで示すように接続文字列を使用する必要があると思います。PDO :: prepareを使用して、バインドされたパラメーターでSQLステートメントを準備します。
user12345 14

1
@masakielastic、次に「SET NAMES utf8 COLLATE utf8_unicode_ci」として照合順序を指定するにはどうすればよいですか
datasn.io

回答:


457

次のように接続文字列に含めます。

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

ただし、PHP 5.3.6より前では、charsetオプションは無視されていました。古いバージョンのPHPを実行している場合は、次のようにする必要があります。

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

15
この動作は5.3.6で変更され、現在は正しく動作していることに注意してください。
igorw

15
UTF-8のutf8 instaeadであるshoudle "mysql:host = $ host; dbname = $ db; charset = utf8"
od3n

3
PHPの最新バージョンを使用している場合は、以下の回答を無視してください。php5.3.8では問題なく動作します。
カシミール

4
この場合、照合も指定する必要がありますか?'SET NAMES utf8 COLLATE utf8_unicode_ci'など?
datasn.io 2014

2
ありがとう!私の日を救った!
Aleksandr

64

PHP 5.3.6より前は、charsetオプションは無視されていました。古いバージョンのPHPを実行している場合は、次のようにする必要があります。

<?php

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

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

?>

1
modsへのメモ:これは正解です。この情報は、承認された回答にこの情報が編集される1年前に投稿されました。
dotancohen 2013

42

これはおそらく、最もエレガントな方法です。
PDOコンストラクター呼び出しで、ただし上記のようにバグのある文字セットオプションを回避します。

$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 2012

ヒントをありがとう!PHPの異なる5.3.Xバージョンを実行している複数の本番システムで上記のコードを正常に使用していますが、実際には5.3.0ではありません。
Jpsy

4
私は、データベース固有のオプションがなければ、よりエレガントになる可能性があると思います
Aalex Gabi

確かに、MYSQL_ATTR_INIT_COMMANDはMySQLデータベースでのみ使用できます(各dbタイプで使用可能なコマンドについては、php.net / manual / de / pdo.drivers.phpのサブページを参照してください)。しかし、これはまさにOPが求めていることです。
Jpsy

charset=utf8dsn文字列を渡すと動作します!groups.google.com/d/msg/auraphp/syMS26Rz-q8/9laQr9tR4EoJ
Hari KT

16

完全を期すために、PDOからMySQLに接続するときに実際にエンコードを設定する方法は3つあり、どの方法を使用できるかは、PHPのバージョンによって異なります。優先順位は次のとおりです。

  1. charset DSN文字列のパラメータ
  2. 実行SET NAMES utf8してPDO::MYSQL_ATTR_INIT_COMMAND接続オプション
  3. SET NAMES utf8手動で実行

このサンプルコードは3つすべてを実装します。

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

3つすべてを実行するのはおそらくやりすぎです(配布または再利用する予定のクラスを作成している場合を除きます)。


1
ODBC / Accessに相当するものはありますか?現在、OracleおよびMySQL PHP PDO UTF8接続が機能していますが、ODBC / Accessで機能させることができません。
1

2
ああ、決してデータベースのパスワードを定義しないでください。それらはスーパーグローバルと同じくらいグローバルであり、あなたがパスワードを扱っているとき、それは良いことではありません。
Xesau

2

COLLATE utf8_general_ciまたは使用したい照合順序でデータベースが作成されていることを確認する必要があることを付け加えておきます。そうしないと、意図したものとは別の照合順序になる可能性があります。

phpmyadminでは、データベースをクリックして操作を選択すると、照合順序を確認できます。データベースとは別の照合順序でテーブルを作成しようとすると、テーブルはとにかくデータベース照合になります。

したがって、テーブルを作成する前に、データベースの照合順序が正しいことを確認してください。これが誰かを数時間救うことを願っています笑


1
「データベースとは別の照合順序でテーブルを作成しようとすると、テーブルはとにかくデータベース照合順序で終了します」-正しいとは思いません。テーブルの照合は、データベースの照合よりも優先されます。dev.mysql.com/doc/refman/5.5/en/charset-table.html
humble_wolf

2

DSNの文字セットオプションは実際には無視されるため、追加のクエリが必要だと思います。他の回答のコメントに投稿されたリンクを参照してください。

http://api.drupal.org/api/drupal/includes--database--mysql--database.inc/function/DatabaseConnection_mysql%3A%3A__construct/7で Drupal 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、2018年

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

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 = $ database; charset = $ encoding "、 "$ dbuser"、 "$ dbpassword");

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.