文字セット

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

警告

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

文字セットはきちんと理解して設定しておかないといけません。 すべての操作に影響が及び、セキュリティの問題を引き起こす可能性があるからです。 たとえば、文字列のエスケープ (mysqli なら mysqli_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 utf8mb4");

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

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

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

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

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

MySQL の文字セット名はハイフンを含まないので、MySQL で (3バイト以下の UTF-8 Unicode エンコーディング という意味の) UTF-8 を表す文字セットは "utf8" が正解です。"UTF-8" ではありません。そのため、 "UTF-8" と指定しても文字セットは変わらず、エラーが発生します。

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

<?php

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

echo 'Initial character set: ' . $mysqli->character_set_name() . "\n";

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

echo 'Your current character set is: ' . $mysqli->character_set_name() . "\n";
?>

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

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