注意
新卒未経験1年目ぐらいの人向けの記事です。特にテクニカルなことは書いてない表面的な記事です。直近業務で文字化け対応したのでとりあえずまとめます。
文字化けってなぜ起こる?
あまり意識しませんが、今これを書いているだけでも
キーボードで文字を入力 -> データがどこかに保存される -> 読み出し -> 対応フォント検索 -> ディスプレイに表示
というようにInputとOutputを行っています。
普通なら1つのソフト上で瞬時に↑をやるため、INとOUTは「形式」は揃い、"普通に文字が打てる"はずです。
が、例えばDBに文字列を保存・取り出しするとINとOUTの「形式」が合わなくなって
縺翫▽縺九l縺輔∪縺ァ縺励◆
とかなる時があります。
このIN/OUTされる文字をどうするか決める「形式」が文字コードです。
UTF8とかSJISとか色々あるやつです。
文字コードには
- どうやって0と1のデータを並べるか(ビッグエンディアン、リトルエンディアンとか言う)
- 連続した0と1のデータのどこを区切って1文字分のデータとするか
- 区切ったデータをどの文字に当てはめるか
といったルールが決められています(が、そこまで仕様知らなくてもおk)。
なので、文字コードを間違えると変な文字が出てきてしまうというわけです。
また、データのIN/OUTは問題ないけど、対応するフォントが無いと「�」とかトーフが出きたりもします。
なので、もし文字化けが発生した場合、I/Oに着目すると問題がわかりやすいです。
エンコード・デコード
で、文字コードの話と一緒によく出てくるのがエンコード・デコードの話で、base64とかURLエンコードとかがあります。
これらはなにかというと、UTF8やSJISなどでは日本語がかけますが、ASCIIは英語ぐらいしかかけません。
(UTF8は2バイト以上にすれば日本語が使えますが、ASCIIは1バイトしか使えない)
そのため、ASCIIとしてデータをやり取りする時などに、データを変換・元に戻すために使われます。
データ圧縮では無いので、基本データ量は増えます。
「じゃあ全部UTF8とかにすればいいじゃん」って思うかもしれません。
はい、その通りです。
なんか色々あってまだそういうのが必要なんだなって思っててください。
そろそろもうUTF8前提で開発してもいいんじゃないかなーって思ってます。
メールではMIMEっていうルールがあって、その中でbase64とかquated-printableというエンコードをしろよってなってます。
URLも世界のすごい人達が「%使っていい感じにエンコードしようよ」ってルールを決めてます。
「え、俺のブラウザだと日本語がURLバーに表示されてるんだけど」と思う人がいるかも知れませんが、
それはブラウザがわかりやすいように表示だけ変換して見せてくれてるだけで、コピペすると%%してると思います。
暗号化との違い
といったように、エンコード・デコードは「〇〇をXXで使えるようにするための変換」なので問題ないと思いますが、
自分は「データを変換してるのだし、暗号化とどう違うんだ?」と思ってた時期がありました。
結果的にデータを可逆的に変換していることに変わりはないのですが、目的が違います。あと堅牢性とか変換効率とかも。
base64でできた文字列はbase64で出来てるとわかればすぐに解読できてしまいますが、暗号化はそう簡単に行きません。
更に共通鍵や秘密鍵のように「データ本体とは別に認証に必要なもの」があるのも暗号化の特徴です。
アプリケーションが変換をするかどうか
と、わかっていても実際に文字化けが発生した時に何故か原因がよくわからんって場合がほとんどです。(ほんとに)
そういう場合はI/Oに着目するだけでなく「ソフトウェアが余計なことしてくれちゃってないか」も見ると良いと思います。
例えばmySQLでは
SHOW VARIABLES LIKE '%character%';
とすると、接続する時、実際にデータを送る時、内部で扱う時、出力する時、などタイミングごとにどう文字コードを扱うか決められて、
character-set-client-handshake
を設定してると勝手に変換したり、
逆にskip-character-set-client-handshake
だと100%送られてくる文字コードを信じたりします。
メールの送受信をするsendmailでは、オプションによって勝手にメールヘッダやボディを変換したりします。
ほとんどの文字化けの原因がこれだと思います。
が、稀にPHP5.3.6未満のPDOはcharsetしても意味ないですよーとか言われるので辛いです。
このあたりに興味ある人はぜひ文字コードマスターになって僕を助けてください。