Ajax & PHPでの日本語文字化け対応

日本語の文字化けではまる。。。orz

AjaxPHPでシステムを構築する機会が得られました。
JavaScriptのライブラリはprototype.js
PHPフレームワークEthnaを利用してJSONで通信*1
という環境でアプリを作っていたのですが、
フォームから日本語を送信すると文字化けしてします。。。
なぜでしょう。。。
ということで1日半ほどはまっちゃいました。;-)

prototype.jsのForm.serialize

まず、今回のアプリはprototype.jsの「Form.serialize()」をつかってフォームの内容を送信していたのですが、
この「Form.serialize()」は何をしているのか調べてみました。
prototype.js(1.4.0)のソースを読んでいたら「encodeURIComponent」をつかってURIエンコードしていることが判明
1256行目から1272行目あたりに書いてありました。
このencodeURIComponentというのを調べてみたらどうやら
HTMLがどのような文字コードで書かれていてもUTF-8を使ったエンコードになるようでした。
以下のサイトが参考になりました。
http://winofsql.jp/VA003334/ajax060324165015.htm

ふむ、ふむ。
ということはPHPにはUTF-8でわたってくるのか
じゃあEUC-JPで扱う場合は

mb_convert_encoding($_POST['tf'],'EUC-JP','UTF-8')

とかすればいいのかな?
と思ってやってみたのですが「????」とかなって化けてしまいます。
う〜ん、なぜだろう?

原因はPHPの設定?

色々と悩んだのですがどうも解決の糸口が見つからなかったので開発環境がおかしいのでは?
と思い、別のサーバーで試して見たところ
な、な、なんと
文字化けしないじゃありませんかー
なぜ?
と思いphpinfo()を見てみたところmbstringの設定が開発環境と違っていることが判明。
文字化けする環境のphp.iniの[mbstring]セクションは以下のようになっていました。

mbstring.internal_encoding = auto
mbstring.http_input = EUC-JP
mbstring.http_output = SJIS
mbstring.encoding_translation = On

どこがいけないのでしょうか?
マニュアルを調べてみました。
どうやら、

mbstring.http_input = EUC-JP
mbstring.encoding_translation = On

この2つが問題のようです。
マニュアルによると「mbstring.encoding_translation」には以下のような意味があります。

入力される HTTP クエリに関して、 文字エンコーディング検出および内部文字エンコーディングへの変換を行う 透過的な文字エンコーディングフィルタを有効にします。

ぼくの環境では「mbstring.http_input = EUC-JP」となっていたのでUTF-8で送られてきたHTTPクエリをPHPが勝手にEUC-JPに変換してくれていたようです。
この処理が問題になっていたようです。
小さな親切です。。。

問題解決!

原因がなんとなくわかりましたので、以下のようにphp.iniを設定し、

mbstring.http_input = auto
mbstring.encoding_translation = Off

以下のようなスクリプトで試したところ文字化けの問題は解決しました。
文字コードEUC-JPで書きました。

<?php
if(!empty($_GET['flg'])){
    mb_language('ja');
    mb_internal_encoding('UTF-8');
    echo mb_convert_encoding($_POST['tf'],'EUC-JP',"UTF-8");
}else{
?>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=EUC-JP">
    <script type="text/javascript" src="prototype.js"></script>
    <title>Ajax</title>
<script type="text/javascript">
function send(){
            var url = 'http://localhost/project/ajax/ajax.php?flg=1';
            var myAjax = 
                    new Ajax.Request( 
                        url, 
                        { 
                            method: "post", 
                            parameters: Form.serialize('fm'), 
                            onComplete: function (req){ $('debug').innerHTML = req.responseText;}
                        }
                    );
}
</script>
</head>
    <body>
        <form name="form1" method="post" action="" id="fm">
            <input type="text" name="tf" id="tf">
            <br>
            <input type="button" name="btn" value="Ajax!!!" onclick="send()">
        </form>
        <div id="debug">
        </div>
    </body>
</html>
<?php
}
?>

ふー
これで眠れます。
文字化けという問題にぶつかってから解決するまでの過程でした。
どのような問題にぶち当たっても、やはり、問題解決には

を活用してまず自力で解決することを目指すことが大切だと思います。
時間と労力はかかりますが、
人に聞く前にこれを活用して自力で調べればスキルアップにつながるのではないでしょうか?
うん。
そう信じています。

*1:Ethnaを使ってJSONを扱う方法はここの「EthnaJSON」という部分が参考になりました。