カテゴリ | |
---|---|
サマリ | SJISテキストファイルのダウンロードで文字化け |
バージョン | 1.4 |
投稿者 | ny |
状態 | 完了 |
投稿日 | 2003-08-08 (FRI) 11:30:57 |
SHIFT-JISで記述したテキストファイルを添付して、ダウンロードすると、文字化けしたファイル内容が表示されます。 IEで閲覧してファイル名をクリックすると、やけに時間がかかった後、ファイルのダウンロードダイアログが表示され、開いても保存しても文字化けした内容が表示されます。
attachフォルダ内のファイルを直接覗いてみると正しく表示されるので、アップロードは正常に動作しているのかと思います。
同じファイルをEUCで保存してアップロードしたら、特に問題なく表示できました。 MIMEの設定がまずいのかとも思ったのですが、PukiWikiで添付ファイルの情報を見てみると、どちらも「Content-type:text/plain」となっています。
以前1.3.5を使用していたときは問題なくダウンロードできていたのですが...。
よろしくお願いします。
状況が再現できません。ちなみに、上の「アップロードしたファイル」をクリックすると、IE6でもnetscape7.1でも、正常な漢字コードでファイルの内容が表示されます。とりあえず、報告まで。
こちらのサーバでからは正常にダウンロードできますね。うちの環境ではNetscape7.1でも試してみましたが、同様に文字化けしたファイルをダウンロードしてしまいます。
linux系のサーバでは再現しませんねぇ。ダウンロード後のファイルは、バイナリエディタで見てみると文字化けどころではなく00 がほとんどになっていました。
行き詰まったら現場へ戻れとも言いますので⌣、「PukiWiki/Install/Windows」や、特に「mbstring」の設定をもう一度確認してみてはいかがですか?
Windows向けのものやmbstringの設定も見直してみたのですが、変化ありませんでした。他にも画面左の最新20件が、各ページを編集するまで更新されないといった現象もあり、きれいな状態から入れなおした方がいいのかも知れません…。
うーむ。なぞですね。そもそもダウンロードで、ファイルの中身が変換されるのがおかしいかと思います。一方、ブラウザでの閲覧なら何か変換してそうですが。apacheの問題でしょうか???
同じサーバ上に、その問題のファイルへのリンクを張った単なるHTMLファイルを置いて、ダウンロードでどのような現象が起こるか確認してみてはいかがでしょうか?また、その「問題のファイル(PukiWikiでアップロードしたもの)」でないSJISファイルの場合はどうなるのか、とかも。
また、後半の「更新されない」現象はおそらく別の症状でして、ここ→「dev:BugTrack/413」をご参照下さい。
ご丁寧にありがとうございます。直接attach/[ファイル名]のURLをブラウザでたたいたら、正常にダウンロードできました。また、漢字が入っていないファイルであれば問題なくダウンロードできます。改めてmbstringのパラメータを見直してみます。後半の「更新されない」は参照先でうまくいきました :) ありがとうございます。
不思議な現象が・・・ テストで添付していたファイルを削除しようとして「添付ファイル一覧」でバックアップを見て気づいたのですが、1世代前のファイルは正常に表示できるのに、最新世代のファイルは同様に文字化けします。
http://server/?plugin=attach&pcmd=open&file=file.txt&refer=test&age=1はOKで、
http://server/?plugin=attach&pcmd=open&file=file.txt&refer=testはNGという状況です。ファイル内容は同一です。
それは重要なヒントですね。この現象の違いはおそらくattach.inc.php v1.31のバグ(ただし今回の悩みの原因ではない)によるものでしょう。294行目付近の正規表現↓にピリオド+数字(「\.\d+」)が含まれていないせいで、
if (!preg_match('/_([0-9A-Z]+)$/',$filename,$matches))バックアップファイルは常にapplication/octet-streamと判定されてしまいます。だから大丈夫だったようですが(つまりそのバグのおかげで大丈夫だった!)、最新のファイルは拡張子が.txtだとtext/plainと(おそらく正しく)判定されて送信されます。すると、なぜかSJISデータが0に置き換わってしまうのではないかと想像します。これはapacheが異常動作していることを意味します(attach.inc.phpでファイルの中身を変換しているところは無いので)。
この仮説を間接的に確かめるために下記のことをして見てください。両方で仮説が確からしければ、おそらくapache(あるいはPHPの?)のtext/plainの異常動作(設定不備か何か?)だと思われます。
そういえば、1.3.5のときは問題なかったんですよね。じゃ、これはやはり違うかな???いや、1.3.5の場合にはmime-typeを設定する機能がなかったんですよね。1.3.5では添付ファイルは常にapplication/octet-streamとして扱っていたから大丈夫だったのかもしれません。そうすると、1.4になって初めてSJISファイルをtext/plainとして扱う状況が出て来たのではないでしょうか?つまり、これは以前から、nyさんのところのapacheが抱えていたバグだったとか?(おお、推理の絆!点と点が線で結ばれて来たかも)
もひとつ疑わしいのは、607行目のmb_convert_encodingでSJISに変換しているところ。もしかして、これをEUC-JPに変更するだけで直るかもしれません。もし、これで直ったら、「EUC-JPモードで運用」とは言っても、apacheはSJISで運用しなければならなかったのかもしれません(かな?)。
これ↑はあんまり関係なさそう。。。
ちなみに、294行目の正規表現はたぶん以下のような感じならよかったのかもしれません(動作未確認)。今回の場合は、こうするとバックアップファイルでも異常動作が生じるはずです(^_^;)。
if (!preg_match('/_([0-9A-Z]+)(?:\.\d+)?$/',$filename,$matches))
ちなみに、私はWindows XP Pro上ではApache2.0.46を使用しています。現在、2.0.47が出ているようですので試しにそれを使ってみるとか?「Apacheのサイト」をご参照。
仮説の検証を行ってみました。
どこかでPukiWikiはApache 2.0.xには正式に対応していない、というような表記を見かけた気がしたので、1.3.xを使用していました。もう少しApache, PHPの方も見直してみます。
整理すると、i.の結果で、SJISファイルは、text/plainならダメでapplication/octet-streamならOKだと確認された。ii.では、ブラウザから直接apacheへアクセスすれば拡張子が.txtでもSJISファイルを読み取れることが確認された、ということですね。うーむ。一体誰がSJISファイルの第7ビットが立ってるバイトを0にしてしまうんだろう…。まさかPHP!?それとも、Apacheの動作が拡張子.txtで読む場合と、text/plainで読む場合とで動作が違うのか?この間にミッシングリンクがあるようだ。謎が謎を呼ぶミステリー。
これ、IIS5.0でも起きます。Shift-JISで書かれた.txt や .htm(html)を添付して開くと、中身が文字化けします。
PHP 内部エンコーディング及び HTTP 出力エンコーディングを該当ファイルの内容に合わせてやると正しく出力できるようになりました。ちなみに IIS4.0+PHP4.3.3です。
attach.inc.php:611 - @readfile($this->filename); + $fp = fopen($this->filename, 'rb'); + or die_message('cannot read '.$this->filename); + $file = fread($fp, $this->size); + fclose($fp); + $enc = mb_detect_encoding($file); + mb_internal_encoding($enc); + mb_http_output($enc); + echo $file; exit;
再現する環境が作れていないので当てずっぽうですが、単純にreadfileの前にmb_http_output('pass')を挿入してやるとどうなりますか?
わたしの環境(IIS5.0+PHP4.3.3)で試したところ、
1.mb_http_output('pass')を挿入する(それ以外は変更なし) ⇒Shift-JISのテキストは正しく表示される ⇒EUC-JPのテキストが表示されない(何も出力されない) 2.とおがさんのコメント通りにattach.inc.phpを変更してみる ⇒Shift-JIS、EUC-JPとも、2回出力されてしまう ('あいうえお'というテキストが、'あいうえおあいうえお'と表示される) 3.とおがさんのコードから、最後の echo $file; を削除してみる ⇒Shift-JIS、EUC-JPの両方とも、正常に表示されるようになったという結果になりました(echo $file は何か別の意図で入れられていたのでしょうか?)。
readfile の行頭の "-" は削除の意だったのですが、勿論 echo $file を抜いても同じ結果になります。1. で EUC が表示されないのはちょっと解せないですが。で、私なりの調査をまとめてみます。結論としてはdefault_charset = "EUC-JP" を止め(指定無し)た上で、
header('Content-Type: '.$this->type); + mb_http_output('pass') @readfile($this->filename)です。
+ //ini_set('default_mimetype', $this->type); + ini_set('default_charset', ''); header('Content-Type: '.$this->type); + mb_http_output('pass'); @readfile($this->filename);
失礼しました。"-"が削除の事だとわかっていたのですが、ぱんださんのやり方と両方試しているうちに編集ミスをしていました。readfileを削ってecho $fileとすれば正常に動作しました。
mb_http_output()は関係ない(readfileの出力には関与しない)ような気がするので、今回は
header('Content-Length: '.$this->size); + ini_set('default_charset',''); header('Content-Type: '.$this->type); @readfile($this->filename);として、Content-Typeヘッダに余計な情報が入らないように対策しておくことにします。ブラウザが文字種の判別に失敗するような文書の場合、mb_detect_encoding()で文字種の判別をしてcharset=を出力したとしても、それが嘘である可能性が高いですから。
何故 default_charset を空にする方向に頭が働かなかったんだろう。ということで、先のコメントちょっと修正させてもらいます。
それから mb_http_output の件、PHPマニュアルの注記によると、PHP4.1.0~では header 関数で自前で出力すればコンバータは無効ですが、PHP4.3.0~では出力する mimetype が text/* の場合なら有効、とあります。実際に 4.2.2 で試したところ、attach.inc.php は素のままでも OK でした。この仕様どおりなら unix 系のホストでも 4.3.0~ なら同様と思われるのですが、実証できてません。Windows ホストで 4.3.0~ の場合は mb_http_output('pass') が必要だと思います。
貴重な情報ありがとうございます。mb_http_output('pass')も入れておきます。