コンセプト
PHP Manual

文字セット

適切な文字セットをサーバーレベルで設定しておくのが理想だし、MySQL のマニュアルの » Character Set Configuration にもそうするよう書かれています。 しかしそれ以外にも、各 MySQL API には実行時に文字セットを指定する方法が用意されています。

警告

文字セットと文字のエスケープ

文字セットはきちんと理解して設定しておかないといけません。 すべての操作に影響が及ぶし、セキュリティの問題を引き起こす可能性があるからです。 たとえば、文字列のエスケープ (mysqli なら mysqli_real_escape_string()、 mysql なら mysql_real_escape_string()、 そして PDO_MySQL なら PDO::quote()) は文字セットの設定に従った動きをします。 これらの関数は、クエリで設定した文字セットは使わないことを知っておくことが大切です。 たとえば次の例のような設定をしても、エスケープ機能は正しく動きません。

例1 文字セットを SQL で指定することによる問題

<?php

$mysqli 
= new mysqli("localhost""my_user""my_password""world");

// これは $mysqli->real_escape_string(); に影響を及ぼしません
$mysqli->query("SET NAMES utf8");

// これも $mysqli->real_escape_string(); に影響を及ぼしません
$mysqli->query("SET CHARACTER SET utf8");

// しかしこの方法なら $mysqli->real_escape_string(); にもきちんと影響します
$mysqli->set_charset('utf8');

// いっぽう、こちらは影響を及ぼしません (utf-8 と utf8 の違いに注目) -- ここではハイフンを使ってはいけません
$mysqli->set_charset('utf-8');

?>

実行時に文字セットを変更する適切な方法を、各 API について示します。

注意: UTF-8 でありがちなミス

MySQL の文字セット名はハイフンを含まないので、MySQL で UTF-8 を表す文字セットは "utf8" が正解です。"utf-8" ではないので、"utf-8" と指定しても文字セットは変わりません。

例2 文字セットの設定: mysqli

<?php

$mysqli 
= new mysqli("localhost""my_user""my_password""world");

printf("Initial character set: %s\n"$mysqli->character_set_name());

if (!
$mysqli->set_charset('utf8')) {
    
printf("Error loading character set utf8: %s\n"$mysqli->error);
    exit;
}

echo 
"New character set information:\n";
print_r$mysqli->get_charset() );

?>

例3 文字セットの設定: pdo_mysql

注意: これは PHP 5.3.6 以降でしか動作しません。

<?php
$pdo 
= new PDO("mysql:host=localhost;dbname=world;charset=utf8"'my_user''my_pass');
?>

例4 文字セットの設定: mysql

<?php
$conn 
mysql_connect("localhost""my_user""my_pass");
$db   mysql_select_db("world");

echo 
'Initial character set: ' .  mysql_client_encoding($conn) . "\n";

if (!
mysql_set_charset('utf8'$conn)) {
    echo 
"Error: Unable to set the character set.\n";
    exit;
}

echo 
'Your current character set is: ' .  mysql_client_encoding($conn);
?>

コンセプト
PHP Manual