SYONテクニカル

PHP と Shift-JIS 環境での文字化けについて

サイオンコミュニケーションズ株式会社
津嘉山 朝也

1.はじめに

PHPのプログラムで、日本語の文字列をGETやPOSTで受け渡しを行ったときに、文字化けを起こしたことはありませんか?

 単に文字化けと言ってもその原因はさまざまですが、今回はPHPによるShift-JIS文字列のURLエンコード/デコード時における文字化けについて書きます。

検証用のソースコードの動作確認環境

サーバ:

  • Windows 2000 Professional
  • Apache 2.0.49
  • PHP 4.3.5

 

クライアント:

  • Windows XP Home edition
  • FireFox 1.0.4

 

2. 文字化けを起こす文字

 PHPのプログラムで、表1にあるShift-JISの文字列をGETやPOSTを用いて受信すると、その文字の後に「\」がついてくるはずです。検証用ソース1で試してみて下さい。

表1. 文字化け該当文字

Ы

検証用ソース1

<HTML>

<FORM METHOD="POST" ACTION=" testPOST.php ">

<?php

// POSTで送られてきたデータ内に含まれるを削除して変数に格納
$input = stripslashes($_POST["input"]);

// POSTで送られてきたデータを変数に格納
$output = $_POST["input"];

?>

入力
<INPUT TYPE="text" NAME="input"
VALUE=<php print str_replace(""",""",$input); ?>>
<BR>

出力
<INPUT TYPE="text" NAME="output"
VALUE=<php print str_replace(""",""",$output); ?>>

<BR>

<INPUT TYPE="submit" VALUE="変換">

</FORM>
</HTML>

3. 文字化けの原因

 この文字化けは、PHPのMagic Quote GPC(Get Post Cookie)という設定とShift-JISの文字コードの組み合わせが原因になって起こります。

 Magic Quote GPCとは、PHPでGETやPOSTで受信する文字列に「\」や「”」のメタ文字が含まれているときに、自動的に「\」を付加して該当文字をエスケープしてくれる機能です。例えば、 データベースに対してPHPからSQLクエリを実行する場合、 Magic Quote GPCの設定がonであれば問題なく実行できます。それはデータベースにSQLクエリを送る際にMagic Quote GPC機能によって次のSQLクエリのように「”」 がエスケープされているからです。

例:
sql = SELECT * FROM "testable"
			↓
sql = SELECT * FROM "testable"

 次にShift-JISの文字コードについて見てみましょう。表1で紹介した文字化けを起こす文字にはある共通点があります。次の表は、文字化け該当文字のShift-JISの文字コードです。

表2. 文字化け該当文字と文字コード

文字 文字コード 文字 文字コード
%81%5c %9a%5c
%89%5c %9b%5c
Ы %84%5c %9c%5c
%87%5c %9d%5c
%89%5c %9e%5c
%8a%5c %9f%5c
%8b%5c %e0%5c
%8c%5c %e1%5c
%8d%5c %e2%5c
%8e%5c %e3%5c
%8f%5c %e4%5c
%90%5c %e5%5c
%91%5c %e6%5c
%92%5c %e7%5c
%93%5c %e8%5c
%94%5c %e9%5c
%95%5c %ea%5c
%96%5c %eb%5c
%97%5c %ec%5c
%98%5c %fa%5c
%99%5c %fb%5c

 もうおわかりになったと思いますが、文字コードの16進値の下2桁、いわゆる2バイト目が「5C」ですね。実は「5C」はShift-JISでは「\」と認識されるのです。この2バイト目が「5C」 となるような文字列をMagic Quote GPC機能をonに設定してGETやPOSTで受信した場合、 「5C」を「\」と勘違いしてエスケープ文字である「\」を付加してしまうのです。

例:
%90 %5C	=>	%90 %5C %5C
申      =>	申

以下に文字コードが「%**%5C」(2バイト目が5C)のすべての文字を
URLデコードしてみました。

検証用ソース2(URLデコード)

<?php
// 繰り返し処理
for($i = 0;$i < 256;$i++){

	// 基底を16進数に変換
	$Num = str_pad(base_convert($i,10,16),2,0,STR_PAD_LEFT);

	// 文字コード生成
	$str = "%".$Num."%5c";

	// URLデコードして画面に出力
	print $str." : ".urldecode($str)."<BR>";
}
?>

表3. 実行結果(文字化け該当文字とShift-JIS文字コード)

文字コード 文字 文字コード 文字 文字コード 文字 文字コード 文字 文字コード 文字 文字コード 文字 文字コード 文字 文字コード 文字
%00%5c \ %20%5c \ %40%5c @\ %60%5c `\ %80%5c \ %a0%5c  \ %c0%5c タ\ %e0%5c
%01%5c \ %21%5c !\ %41%5c A\ %61%5c a\ %81%5c %a1%5c 。\ %c1%5c チ\ %e1%5c
%02%5c \ %22%5c “\ %42%5c B\ %62%5c b\ %82%5c %a2%5c 「\ %c2%5c ツ\ %e2%5c
%03%5c \ %23%5c #\ %43%5c C\ %63%5c c\ %83%5c %a3%5c 」\ %c3%5c テ\ %e3%5c
%04%5c \ %24%5c $\ %44%5c D\ %64%5c d\ %84%5c Ы %a4%5c 、\ %c4%5c ト\ %e4%5c
%05%5c \ %25%5c %\ %45%5c E\ %65%5c e\ %85%5c %a5%5c ・\ %c5%5c ナ\ %e5%5c
%06%5c \ %26%5c &\ %46%5c F\ %66%5c f\ %86%5c %a6%5c ヲ\ %c6%5c ニ\ %e6%5c
%07%5c \ %27%5c ‘\ %47%5c G\ %67%5c g\ %87%5c %a7%5c ァ\ %c7%5c ヌ\ %e7%5c
%08%5c \ %28%5c (\ %48%5c H\ %68%5c h\ %88%5c %a8%5c ィ\ %c8%5c ネ\ %e8%5c
%09%5c \ %29%5c )\ %49%5c I\ %69%5c i\ %89%5c %a9%5c ゥ\ %c9%5c ノ\ %e9%5c
%0a%5c \ %2a%5c *\ %4a%5c J\ %6a%5c j\ %8a%5c %aa%5c ェ\ %ca%5c ハ\ %ea%5c
%0b%5c \ %2b%5c +\ %4b%5c K\ %6b%5c k\ %8b%5c %ab%5c ォ\ %cb%5c ヒ\ %eb%5c
%0c%5c \ %2c%5c ,\ %4c%5c L\ %6c%5c l\ %8c%5c %ac%5c ャ\ %cc%5c フ\ %ec%5c
%0d%5c \ %2d%5c -\ %4d%5c M\ %6d%5c m\ %8d%5c %ad%5c ュ\ %cd%5c ヘ\ %ed%5c
%0e%5c \ %2e%5c .\ %4e%5c N\ %6e%5c n\ %8e%5c %ae%5c ョ\ %ce%5c ホ\ %ee%5c
%0f%5c \ %2f%5c /\ %4f%5c O\ %6f%5c o\ %8f%5c %af%5c ッ\ %cf%5c マ\ %ef%5c
%10%5c \ %30%5c 0\ %50%5c P\ %70%5c p\ %90%5c %b0%5c ー\ %d0%5c ミ\ %f0%5c
%11%5c \ %31%5c 1\ %51%5c Q\ %71%5c q\ %91%5c %b1%5c ア\ %d1%5c ム\ %f1%5c
%12%5c \ %32%5c 2\ %52%5c R\ %72%5c r\ %92%5c %b2%5c イ\ %d2%5c メ\ %f2%5c
%13%5c \ %33%5c 3\ %53%5c S\ %73%5c s\ %93%5c %b3%5c ウ\ %d3%5c モ\ %f3%5c
%14%5c \ %34%5c 4\ %54%5c T\ %74%5c t\ %94%5c %b4%5c エ\ %d4%5c ヤ\ %f4%5c
%15%5c \ %35%5c 5\ %55%5c U\ %75%5c u\ %95%5c %b5%5c オ\ %d5%5c ユ\ %f5%5c
%16%5c \ %36%5c 6\ %56%5c V\ %76%5c v\ %96%5c %b6%5c カ\ %d6%5c ヨ\ %f6%5c
%17%5c \ %37%5c 7\ %57%5c W\ %77%5c w\ %97%5c %b7%5c キ\ %d7%5c ラ\ %f7%5c
%18%5c \ %38%5c 8\ %58%5c X\ %78%5c x\ %98%5c %b8%5c ク\ %d8%5c リ\ %f8%5c
%19%5c \ %39%5c 9\ %59%5c Y\ %79%5c y\ %99%5c %b9%5c ケ\ %d9%5c ル\ %f9%5c
%1a%5c \ %3a%5c :\ %5a%5c Z\ %7a%5c z\ %9a%5c %ba%5c コ\ %da%5c レ\ %fa%5c
%1b%5c \ %3b%5c ;\ %5b%5c [\ %7b%5c {\ %9b%5c %bb%5c サ\ %db%5c ロ\ %fb%5c
%1c%5c \ %3c%5c <\ %5c%5c \\ %7c%5c |\ %9c%5c %bc%5c シ\ %dc%5c ワ\ %fc%5c
%1d%5c \ %3d%5c =\ %5d%5c ]\ %7d%5c }\ %9d%5c %bd%5c ス\ %dd%5c ン\ %fd%5c \
%1e%5c \ %3e%5c >\ %5e%5c ^\ %7e%5c ~\ %9e%5c %be%5c セ\ %de%5c ゙\ %fe%5c \
%1f%5c \ %3f%5c ?\ %5f%5c _\ %7f%5c \ %9f%5c %bf%5c ソ\ %df%5c ゚\ %ff%5c \

4. 文字化け対策

 このような文字化けの対策として、
以下のような対策が考えられます。

4.1. 日本語文字列の文字コードにShift-JISを使わない

 基本的にはShift-JIS以外の文字コードを用いれば、今回のような文字化けは起こらないので一番確実でしょう。しかし、仕事でプログラムを書いている人たちは諸々の事情からShift-JISを使用しなければならない状況があるかもしれません。

4.2. Magic Quote GPC機能をoffに設定する

設定方法:

php.ini(PHPの設定ファイル)の項目
magic_quotes_gpc = On
をOffに書き直す。

 これで、GETやPOSTで文字列を受信しても勝手に「\」がつかないので、文字化け自体は起こらなくなるのですが、データベース登録時には注意が必要です。なぜならばSQLでよく使用される「’」や「”」などの文字にも自動で 「\」が付加されなくなるので、意図的にaddslashesなどの処理が必要になってきます。
addslashesの使い方:

変数 = addslashes( "文字列" または変数 );

4.3. GETやPOSTで受信した文字列に「\」を取り除く処理を行う

 この場合は、Magic Quote GPC機能をonの状態で、GETやPOSTで受信した文字列に対して、stripslashes などで逐一余分に付加される「\」を取り除く処理を行っていきます。
stripslashesの使い方:

変数 = stripslashes( "文字列" または変数 );

5. 最後に

今回の文字化けは、私がPHPで複数のページに渡って変数をやり取りするプログラムを作っているときに見つけたものです。納品直前で見つけてしまって、 結構あせりました。まだ納品前でよかったー。PHPでプログラムをする方、GETやPOSTで日本語を扱う際は、気をつけましょう。

Copyright 1999-2012 SYON Communications, Co. All rights reserved