2008年1月19日土曜日

 

PHP+MySQL+UTF-8で文字化け対策

自分は遭遇した事無いけど、今後の参考に。
PHPの内部処理の文字コードがEUCベースな為、UTF-8で作っていくとフォーム値が文字化けしてしまう事があるらしい。
結構多いトラブルの模様。
解決策としては、内部処理の文字コードをUTF-8に変更してから受け取る様にすると良い。

自分の経験で悩まされたのは、DBの文字化け
DBを一から構築する場合は最初からUTF-8で作っていけば良いけど、サーバの移転だったり既存のデータを使ったプログラムを組みときは文字化けが大変。EUC-JPが多い。
その時は以下のコードで文字コードを指定したクエリを発行して乗り越えられた。

<?
mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");

$db=mysql_connect("DBサーバ名","接続ID","接続パスワード");
mysql_query("SET NAMES utf8",$db); //クエリの文字コードを設定
mysql_select_db("DB名");
?>
yohgaki's blog
SET NAMESは禁止
MySQLには文字エンコーディングを変更する「SET NAMES」SQL文が用意されています。(PostgreSQLも同様のSQL文、SET CLIENT_ENCODINGがあります)この機能はSQLコンソールからは使ってよい機能ですが、アプリケーションからは使ってはならない機能です。 SQLインジェクションに脆弱になる場合があります。
(略) ストアドプロシージャだけ使っていれば安全ですが、アプリケーションからDBMSの文字エンコーディングを設定する場合、SQL文ではなく必ず文字エンコーディング設定APIを利用するよう紹介しなければならないです。
(略) 脆弱性の説明は面倒ですが注意事項は簡単です。「DBMSをアプリケーションから利用する場合、文字エンコーディング設定は必ずAPIを利用する」つまり「SET NAMES(SET CLIENT_ENCODING等も)は禁止」です。

"SET NAMES"で文字エンコーディングを指定している箇所はすべてmysql_set_charset()関数を利用するように書き換えた方が良いらしい。

<?
mb_language("uni");
mb_internal_encoding("utf-8"); //内部文字コードを変更
mb_http_input("auto");
mb_http_output("utf-8");

$db=mysql_connect("DBサーバ名","接続ID","接続パスワード");
mysqli_set_charset($db, "utf8") //クエリの文字コードを設定
mysql_select_db("DB名");
?>
mysqli::set_charset - PHPマニュアル

ただmysqli_set_charset()関数はPHP 5.2以降、MySQL 5.0.7以降でないと使えないようです。※こちらによるとMySQL 4.x系でも利用可能らしい

さらに悩ませる記事がありました。

SET NAMESは禁止?

日本語以外の記事では、「SET NAMESを使ってはいけない」とまで書いている記事が見つからなかったので、いまだすんなりと納得できていないのですが、今後、MySQL 4.1以上を入れた共有サーバなんかではどうすればいいんでしょうか…。

“SET NAMES sjs”に問題がある、という記事は下記にありました。

t_komuraの日記
addslashes() による SQL 文字列のエスケープ回避問題

hoshikuzu | star_dust の書斎
■PHP 利用時に Shift_JIS で addslashes() によるエスケープ処理に SQL インジェクション可能な穴

“mysql_real_escape_string()でもSET NAMES sjis;等を実行した後に使うと2バイト目の0x5C文字がエスケープされないようです。”

とりあえずmysqli_set_charset()関数が使える場合は良いとして、それ以前のサーバではどうするべきなんでしょうか。

ラベル: , , ,


コメント:
勉強させてもらいました。
ここの例の場合、
mysqli_set_charset($db,"utf8");
ではなくて、
mysql_set_charset("utf8", $db);
が正しいようです。
 
最新のPHP MY ADMINをインストールしたら同じ現象になりこの記事に助かりました。
しかし匿名さんのおっしゃるとおり例文のソースが間違っていて危うく諦める所でした。
こうゆう記事を載せるときは確認して欲しいです。
匿名さんありがとうございました。
 
コメントを投稿

登録 コメントの投稿 [Atom]



この投稿へのリンク:

リンクを作成



<< ホーム

This page is powered by Blogger. Isn't yours?

登録 投稿 [Atom]

Google