雑記

2000|01|
2003|05|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|
2007|01|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|09|11|
2009|02|03|05|06|07|08|10|11|12|
2010|01|03|04|05|06|07|08|09|10|
2011|05|06|09|10|
2012|03|07|09|12|
2013|01|02|04|05|07|08|10|11|
2014|04|05|08|10|12|
2015|01|05|
2016|09|

2003-05-13

image.rbをさらに改造して動画ファイルのアップロードも可能に.image.rbは最新のものに上書きしました(昨日のバージョン).


2006-05-13

[Ajax][IE][Firefox] 外部ファイルを取り込む際の文字化け対策

既存のCGI群をAjaxで書き直す作業をやってもらったところ、XMLHttpRequest()で取得したソースが、物によって文字化けしたりしなかったりするという報告が上がってきたので調査。IE6とFirefox(1.5.0.3)で試しました。私の調べた範囲では、Safari(1.3.2)の場合、IEやFirefoxで文字化けするページが、文字化けしませんでした。また、他のブラウザは調査する根性がありませんでした。あと、検証はEUC-JPでしかチェックしてません。本エントリは他で公開されている情報を補足するものであり否定するものではありませんし、JavaScript++かも日記bricklife.weblog.*(敬称略)による網羅的なまとめが無ければここまでたどり着くことは出来なかったでしょう。お二方をはじめ、本件に関する情報を先立って公開して下さった皆様に、まずは感謝の意を表します。

関連するページの記述によると、基本的な対策としては文字コードをUTF-8にすると言うことらしいのですが、静的なファイルはともかくCGIまで含めてUTF-8対応させる余裕はありません。また、手元のデータの中には、CGIであるのに文字化けするものとしないものがあったりして、既存の調査結果と一見矛盾していました。さらに、いくつかのページで書かれていた、CGIだと文字化けしないが静的なファイルだと文字化けする、という結果は、プロトコル、およびクライアントの実装手法的にどうしても納得できませんでした。こうしたことから、既存の実験には、なにがしかの条件が不足していたのではないかと考え、とりあえず手元のCGIの場合の文字化けの有り無しで、出力されるデータを比較しました。

結果、文字化けしないCGIでは

Content-type: text/html; charset=EUC-JP
と出力していたのに対し、文字化けするCGIでは、
Content-type: text/html;
とだけ出力していました。これを見たとたんにapacheの挙動に思い至り、文字化けの原因が「htmlかcgiか」の違いではなく、「HTTPレスポンスのContent-typeに正しいcharsetが記述されているかどうか」の違いであると仮定したところ、これまでの自身の実験結果や他のページでまとめられている、一見不可解な挙動がすっきりと説明できます。つまり、ルールとしては
responsTextの場合
  • HTTPヘッダーフィールドのContent-typeで指定されたcharsetは正しく解釈される。
  • HTMLヘッダーの<META>タグを使ってContent-typeで指定されたcharsetは無視される。
responseXMLの場合
  • HTTPヘッダーフィールドのContent-typeで指定されたcharsetは正しく解釈される。(←というのは検証の結果、IEでは間違いと判明)
  • encoding属性も正しく解釈される。
と言うシンプルなものに落とし込むことができ、実装についても妥当と思えるものが容易に想像できます。

あとは実験。apacheの設定を変更して、EUCで書かれた静的なHTMLファイルの取得時には、charset=EUC-JPを含むContents-typeを返すようにしたところ、IE、FirefoxともにresponseTextでも文字化けしないようになりました。一方、responseXMLの場合、IEでは、Content-typeの方は無視されて文字化けしましたが、FirefoxではContent-typeのcharsetが正しく解釈され、文字化けしなくなるという結果でした。表にまとめると、以下のような感じです。

responsTextresponseXML
Content-typeMETAタグ
IE×
Firefox×
Content-typeencoding属性
IE×
Firefox

というわけで、XMLHttpRequest()の文字化けに対するWorkaroundとしては、responsTextを使用する場合、単純にHTTPレスポンスのContent-typeで正しいcharsetを返すようにサーバを設定/CGIを実装する。responsXMLを使用する場合、encoding属性を指定する。という事で大丈夫なようです。

apacheで正しいcharsetを返すための設定方法

全てのレスポンスでcharset=EUC-JPを返すというのは乱暴なので、正しいcharsetを返すための設定方法について調べてみました。何通りかやり方があるようです。

ファイル名で区別する
mod_mimeが有効になっている(デフォルト)場合、ファイル名の拡張子の複数指定を使った設定ができます。例えば、設定ファイルの適切な場所(後述)に、
AddCharset EUC-JP .euc
という行を追加してapacheを再起動し、EUC-JPを含むファイル foo.html/bar.txt を foo.euc.html/bar.euc.txtのように名前変更すると、foo.euc.html/bar.euc.txtにアクセスがあった場合に、charset=EUC-JPがつくようになります。ファイル名とリンクの変更が必要になるので、既に大量のファイルがある場合、ちょっと嫌かも。
ファイル単位で指定する
取り込まれる静的なファイルが決まっていて、少ない場合は、ファイル単位で指定することもできます。
<Files /path/to/foo.html>
AddType "text/html; charset=EUC-JP" .html
</Files>
<Files /path/to/bar.txt>
AddType "text/plain; charset=EUC-JP" .txt
</Files>
ちょっとトリッキーですね。FilesMatchもありますが、アクセスの度にファイル名と正規表現の比較が入ることになるので、これを使うぐらいなら上か下の方法を使うのが良いと思われます。
ディレクトリ・ロケーション単位で指定する
未検証ですが、上記FilesをDirectory とか Location に置き換えれば、できるはずです。日本語ページと英語ページでディレクトリを分けている場合、一番お手軽な方法かも。
このぐらいのバリエーションがあれば、たいていの場合は正しいcharsetを返せるようになるんじゃないでしょうか。

で、上記設定ですが、apacheの設定ファイルで「AllowOverride FileInfo(だと思う)」が指定してあれば、.htaccessファイル内に記述することによって標準の設定を上書きできます。管理者権限が無い場合は、試してみる価値はあるかもしれません。が、ファイルアクセスのたびに.htaccessが読み込まれ、そこから条件比較という手順を踏むようになるので、パフォーマンスが落ちること間違いなしです。

超余談

で、ふと思ったのですが、これってCSSXSSで'{'や'}'に該当するコードを含む日本語文字の入ったHTMLファイルも脅威にさらされるという問題の、サーバ側でのWorkaroundになったりは…しないかな。