/ PHP GET/POSTメソッドでの日本語の文字化け防止 - 三浦克介 - 情報科学研究科 - 大阪大学

豆知識

概要

このページでは、PHP で、GET/POSTメソッドによりブラウザからサーバーに 送信された日本語文字列データの文字化けを防止する対策について述べています。 HTML文書 でエンコーディング方法を指定する方法、ブラウザの対応状況、PHPの 文字エンコーディング検出関数である mb_detect_encoding() 関数 による誤検出の問題、mb_detect_encoding() 関数 の特性、について述べ、それらを踏まえて、文字化けを防止する方法を 示します。

HTML文書 でエンコーディングを指定する方法

ブラウザからWebサーバーへデータを送信する場合、HTML文書FORMタグ を入れ ておき、GETメソッドかPOSTメソッドを使い送信します。この際に使用する文字 エンコーディングは、FORMタグaccept-charset属性 で指定することができます。 以下のように指定します。

<FORM action="..." method="post" accept-charset="euc-jp,us-ascii">
  FORMの中身...
</FORM>

この場合、ブラウザは、EUC-JP が US-ASCII のいずれかの文字エンコーディン グでデータを送信しなければならないことになっています (HTML4.01の仕様にお いて、若干、疑問な点があります。HTML form要素 accept-charset属性の疑問点 のページをご覧下さい)。

ブラウザの対応状況

しかし、世の中には、accept-charset属性 を無視して、常に同じ文字エンコーディ ングでデータを送信したり、受け取った HTML文書 と同じエンコーディングで送信 したりするブラウザが少からず存在するようです。

  • 携帯電話ブラウザの多くは、常にSHIFT-JISで送信します。
  • 古いブラウザは、accept-charset属性 を無視するものが多いようです。

(詳細には確認していません。少しケースは違いますが、accept-charsetが無い場合についての調査結果が CGIと漢字コード のページに掲載されています。)

結局、ブラウザがどのような文字エンコーディングでデータを送信してくるかは、 サーバーで受け取ったデータから判定しているケースがほとんどのようです。

mb_detect_encoding() 関数 による誤検出

Webサーバーにおいて、PHPを用いて、GET/POSTメソッドでブラウザから送信され たデータの文字エンコーディングを検出するには、mb_detect_encoding() 関数 を利用しますが、この関数は、文字エンコーディングを誤検出する場合がありま す。これは、mb_detect_encoding() 関数 のバグではなく、日本語の文字エンコー ディングの規格の関係上、100%正確なエンコーディング検出が不可能な文字が存 在する為です。例えば、標準的な設定のPHPで「名前」というEUC-JPの文字列の文字エンコーディングを検出すると、UTF-8と誤検出されます。文字エンコーディング検出のテストを、 PHP mb_detect_encoding() 関数のテスト1 のページで行うことができまので、お試し下さい。

mb_detect_encoding() 関数 の特性

mb_detect_encoding() 関数 は、文字エンコーディングを確定できない場合、可 能性のある文字エンコーディングの中から、定められた優先順位で文字エンコー ディングを決定します。この優先順位は、mb_detect_order() 関数 で変更するこ とができます (既定値は php.ini ファイルで指定)。また、 mb_detect-encoding() の第2引数で指定することも可能です。通常は、ASCII

JIS > UTF-8 > EUC-JP > SJIS の順になっています。

誤検出される文字は、この順位に応じて変わります。標準の順位の場合、JIS X0208.1990 の6878文字中、2743文字の文字エンコーディングが正しく検出され ません。誤検出される文字の一覧は、 PHP mb_detect_encoding() 関数のテスト2 のページでご覧頂けます。

文字エンコーディング検出優先順位を変えて、誤検出文字数を調査したところ、 以下のことが分かりました。

  • US-ASCIIの順位を変えても、誤検出文字数は変化しない (ASCIIは他の文字エンコーディングに内包されるので無意味)。
  • JISの順位を下げると、全文字が誤検出されるようになる。
  • SHIFT-JISの順位を上げると、誤検出文字数がかなり増加する。
  • ASCII > JIS > UTF-8 > EUC-JP > SJIS の順位が最も良く、誤検出文字数:2743文字。
  • ASCII > JIS > EUC-JP > UTF-8 > SJIS の順位が次に良く、誤検出文字数:2775文字。

文字化けを防止する方法

以上のように、

  • ブラウザから送られてくるデータの文字エンコーディングを、事前にかつ確実に、知ることはできない。
  • 確実に文字エンコーディングを検出可能な文字が含まれていなければ、送られて来たデータの文字エンコーディングを正しく検出できない。

というのが、実状です。

以上のような理由から、確実に文字エンコーディングを検出する為には、確実に 文字エンコーディングを検出可能な文字を、ブラウザからの送信データに強制的 に含めておく必要があります。従って、以下のように、hidden属性の入力フィールドをフォームの中に入れておき、確 実に文字コードエンコーディングを検出可能な文字 (列) を、value属性に指定 する、という方法が有効です。

<FORM action="..." method="post">
  <INPUT type="hidden" name="encode_hint" value="あ">
  FORMの中身...
</FORM>

謝辞

このページの情報は、PukiWikiのデバッグ過程 (PukiWikiDev:BugTrack/296) において得られました。フォームにhidden属 性データを含めておくアイデアは PukiWikiDev:ぱんだ 様から、FORMタグaccept-charset属性 に関する情報は PukiWikiDev:reimy 様から、それぞれ、頂戴しました。

意見・コメント

  • hiddenには文字列を記述するのがベターです。一文字のみの記述、特に『あ』の一文字だと検出において不安定(不完全)だった気がします。<昔のうろ覚え -- ななしん? 2007-10-18 (木) 14:34:21
    • 1文字でも、文字を選べば大丈夫ですよ。JIS, SJIS, EUC, UTF-8で確認しています。 -- 三浦克介 2007-11-22 (木) 12:49:23

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2008-04-14 (月) 18:57:14 (3059d)