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文を確認したら、原因が判明しました。

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文に以下のように記述するとありました。

あれ?
照合順序設定方法と同じです。

この設定をして、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の指定の組み合わせで文字化けすることはあります。
ただ正しく使えば存在する文字ならば文字化けしません。

使いやすい文字コードの選択で十分対応できます。

今回のレポートは以上です。
読んでいただいてありがとうございました。


ホームページに関するお悩み事やご相談事がございましたら私どもまでご連絡ください。 鋭意ご対応申し上げます。
ホームページのご提案もさせていただいております