PHP Conference Japan 2024

文字セット

適切な文字セットをサーバーレベルで設定しておくのが理想であり、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');
?>
add a note

User Contributed Notes 2 notes

up
22
mkroese at eljakim dot nl
7 years ago
Please note that MySQL's utf8 encoding has a maximum of 3 bytes and is unable to encode *all* unicode characters.

If you need to encode characters beyond the BMP (Basic Multilingual Plane), like emoji or other special characters, you will need to use a different encoding like utf8mb4 or any other encoding supporting the higher planes. Mysql will discard any characters encoded in 4 bytes (or more).

See https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb4.html for more information on the matter
up
-1
legrand dot jeremie at gmail dot com
1 year ago
After setting the charset, you should define the 'collation' too, to give information on how sorting results on requests. By default, it is 'utf8mb4_general_ci', which is a simplified set of sorting rules. For the official rules, edicted by Unicode, it should be 'utf8mb4_unicode_ci'.

For example:
\mysqli_set_charset($hdl, 'utf8mb4');
\mysqli_query($hdl, 'SET collation_connection = utf8mb4_unicode_520_ci');
To Top