PHPをShift-JISで構築した際にMYSQL保存時の文字化けを回避する
ホームページでMYSQL等のデータベースを使う場合は、PHP等でサイト構築する必要があります。
通常はHTMLもPHPもMYSQLも文字コードを「UTF-8」で構築すれば特に文字化けは発生しません。
ただ、サイトを「Shift-JIS」で構築しなければならない場合もあります。
Shift-JISでPHPを構築する場合は、文字コード変換などを行えば容易にできます。
ところが、MYSQLに保存した際に、一部の特殊文字が文字化けして保存されました。
今回Shift-JIS構築のPHPでMYSQLに文字化けの原因と対策について調べましたので、忘備録として記録いたします。
今回MYSQL保存で文字化けした文字は「髙」と「﨑」と「Ⅳ」
投稿記事をShift-JISでMYSQLに保存するアプリの作成で、何気に入力したら文字化けが発生しました。
一応phpMyadminでどのように登録されているか確認しました。
やはりというか、Shift-JISには文字化けがつきものです。
通常文字は大丈夫ですが、旧字体漢字などは文字化けします。
ちなみにPHP側でMYSQLへの文字コードセットは「CP932」なのにMYSQLで文字化け
文字コード「Shift-JIS」や「SJIS」ではPHPでも一部の文字化けが発生します。
そこで「SJIS-win」や「CP932」を指定すると、旧字体も文字化けしません。
MYSQLと接続する際には、文字コードを「CP932」にしています。
経路を調査すると、PHPの中では文字化けしていません。
MYSQLに保存した時に文字化けしています。
いったいなぜ、このMYSQLで文字化けするのでしょう?
調べてみました。
原因はMYSQLの「照合順序」指定
原因を調べるために、phpMyadminを見ていたら、気になる部分がありました。
それがこちらです。
照合順序が「SJIS」になっていました。
データベースを新規作成した時には照合順序を「UTF-8」にしていたのですが、なぜかSJISになっていました。
照合順序がSJISになっていた原因
照合順序デフォルトがUTF-8なのになぜ「SJIS」になっていたのか?
DB登録時のSQL文を確認したら、原因が判明しました。
1 2 3 4 |
CREATE TABLE テーブル名 ( テーブルの構造設定 ) DEFAULT CHARSET=sjis |
DEFAULT CHARSET=sjisをSQL文で宣言していました。
なるほどこれでは確かに照合順序がSJISになります。
でもここで疑問がわきました。
照合順序って、文字化けに関係するものなの?
そこで照合順序とは何なのか?
MYSQLの照合順序について調べてみました。
MYSQLの照合順序とは
照合順序というくらいなので、検索やソートなどに関連する指定のように見えます。
調べてみると、全くその通りでした。
- 照合順序はソートするためのルール
- generalとかunicodeはマルチリンガル(多言語対応)
- ci、csは大文字を区別しない/するの違い
Shift-JISのサイトなので、Shift-JISで照合するのは問題ないように思えます。
ただ、PHPでは「CP932」に設定しているので、「SJIS」では問題があるようにも思えます。
まずは試してみようと思い、照合順序を変更してみました。
照合順序をUTF-8に変更してテストしてみました。
なにはともあれ、照合順序が「SJIS」なのは問題なので、UTF-8に設定しました。
Shift-JIS構築なのに、MYSQLをUTF-8にしたのはもともとデフォルト設定にしていたからです。
照合順序が「UTF-8」に変わったのを確認して、先ほど文字化けした「髙」「﨑」「Ⅳ」を入力してみました。
こんどは、文字化けしませんでした。
ちなみに照合順序「CP932」でも試してみました。
Shift-JISなので、照合順序はUTF-8よりCP932のほうが良いと思い、CP932に設定してためしてみました。
再び「髙」「﨑」「Ⅳ」を入力してみました。
同じShift-JISでも、CP932ならば文字化けしませんでした。
照合順序文字コード指定で文字化けが起こるのはなぜ?
「髙」「﨑」「Ⅳ」といった文字は、「SJIS」には無い文字だから、不明文字として登録されます。
だから「?」に変換されます。
無い文字は表示されない。
そこまでは理解できます。
でも照合順序なのだから、文字化けとは関係ないんじゃないの?
と思いました。
あくまでもソートするための文字コードなのだから・・・。!?
とここで、MYSQLテーブルや、カラムの文字コードはどうやって設定するのだろう?
と疑問に思いました。
調べてみました。
MYSQLテーブルに文字コードを設定する方法を調べてみました。
例えばUTF-8にする場合の文字コード設定方法を調べたら、SQL文に以下のように記述するとありました。
1 2 3 4 |
CREATE TABLE テーブル名 ( テーブルの構造設定 )DEFAULT CHARSET=utf8 |
あれ?
照合順序設定方法と同じです。
この設定をして、phpMyadminで照合順序を調べてみたところ、「utf8-general-ci」になっていました。
MYSQLのテーブル文字コード設定と照合順序の設定方法は同じ
試してみて初めて理解できました。
MYSQLでテーブルの文字コード設定と、テーブルの照合順序設定方法は同じでした。
utf8-general-ciとかutf8-unicode-ciとか、同じutf-8でもオプションのような差異がありますが、文字コードがUTF-8を指定していることには違いないということです。
なるほど、最初照合コードが「sjis-japanese-ci」であったということは、MYSQLテーブルの文字コードも「SJIS」だったということです。
だから、「髙」「﨑」「Ⅳ」といった、SJISには無い文字を入力したら「?」に変換されたのです。
なにかつっかえていたモヤモヤが解消されました。
UTF-8で構築するほうが無難なのですが、それでもShift-JISも必要。
webサイト構築でPHPやMYSQLにたずさわるほど、UTF-8が無難ということに気づきます。
実際、Shift-JISの文字化け問題にはよく悩まされます。
ではなぜShift-JISを使うの?
と言われると、答えはマイクロソフトとの相性が良いからです。
メールフォームでも、UTF-8で送信するとoutlookで受信した際に文字化けしています。
wordやexcelなどはShift-JISが採用されています。
word等からのコピーペーストを前提にしていたりすると、Shift-JISのほうが都合がよかったりします。
無論、表示はShift-JIS、保存はUTF-8という方法もあります。
PHPで文字変換すればよいだけです。
しかしながら「CP932」というSJISの拡張文字コードを知ってからは、Shift-JIS文字化け問題は極端に出会わなくなりました。
PHPとMYSQLの指定の組み合わせで文字化けすることはあります。
ただ正しく使えば存在する文字ならば文字化けしません。
使いやすい文字コードの選択で十分対応できます。