初めに
こちらの記事は、私が「寿司ビール問題」を解決した方法です。
サーバーの設定を触っておりますので、お試しの際は開発環境などで正常な動作を確認後に行なってください。
いきなり本番環境でサーバーの設定を変更しないようにお願いします。(そんな人いないと思いますが一応)
似て非なる問題寿司ビール問題
寿司ビール問題は結構有名なので調べていただいたらすぐにたくさん記事が出てくると思います。
簡単に言うと、以下の絵文字が同じモノとして扱われる的なことです。
🍣=🍺
ちなみに僕は、吉野家の「𠮷(つちよし)」をDBに格納したくて試行錯誤しました。
エンジニア初学者の僕は
「文字コードはUTF-8やろ」
ぐらいに思っており、深く考えたことはありません。。。(だめだめです。)
調べてみると、文字コードは符号化文字集合、文字符号化方式の二つの要素があるらしい。
▼符号化文字集合
用いる文字の集合のこと、またその文字の対応する識別子のこと。Unicode,JIS X 0213などのこと。
▼文字符号化方式
上記の文字集合で得た識別子を符号化するときに用いる方式のこと。つまりエンコード。
なるほどつまり、文字符号化方式を利用して符号化文字集合を利用するんだな。←
コメントにていただいたいるように寿司ビール問題はすでにutf8mb4にて4バイト文字が格納できているが、🍣と🍺が同じ文字として検索されてしまう問題ですね。なので「𠮷(つちよし)問題」とは似て非なる問題として取り上げさせて頂きました。
▼charsetは以下によると、つまり文字符号化方式のことらしい
https://web-designer.cman.jp/other/charset/
utf8って、「utfmb3」を参照しているらしくて、4バイト文字に対応してないんですよね。(なんでやねん)
なので、「𠮷」以外にも、旧漢字だと文字として認識されずに「???」みたいに文字化けすることも多々あります。(苗字とかね)
以下を見ると分かり易い。
show CHARACTER SET ;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |//3バイト文字
| utf8mb4 | UTF-8 Unicode | utf8mb4_general_ci | 4 |//4バイト文字
+----------+-----------------------------+---------------------+--------+
なお、回は「𠮷」をDBに格納することをゴールとします。
mysqlの設定を変更しよう
兎にも角にも、charsetを「utf8mb4」にしてあげる必要があります。
まずは、my.confを修正
[mysqld]
character-set-server=utf8mb4
[mysql]
default-character-set=utf8mb4
[client]
loose-default-character-set=utf8mb4
上記にて設定後、mysqlを再起動、確認
# service mysqld restart
もしくは
# systemctl restart mariadb.service
# mysql -u [user] -p
mysql> show variables like "chara%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
DBにutf8mb4_binを設定する
ALTER DATABASE `test_db` DEFAULT CHARACTER SET utf8mb4;
テーブルにutf8mb4を設定する
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `test2` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE `test3` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
カラムにutf8mb4を設定する
ALTER TABLE `test` CHANGE `test_clumun` `test_clumun` VARCHAR( 255 ) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT 'テスト名';
しかし、上記ではうまくいかず、、、
上記では、「𠮷(つちよし)」はDBに格納されませんでした。とほほ
結局DBから作り直しました。
(ダンプファイルを取っておくように!)
mysql> DROP DATABASE test_db ;
mysql> CREATE DATABASE test_db CHARACTER SET = utf8mb4 ;
mysql> use test
mysql> show variables like 'character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
mysql> exit
その後に、全てのDBレコードを復元しました。
次に、laravelの設定を修正。
config.database.phpの照合順序をutfmb4に変更する。
結構時間がかかってしまいました。
DBが一瞬でも使えない状態になるので、対応中はメンテナンス表示としました。
他にもいい方法があれば教えてください!
では、良いPHPライフを!