質問箱/236

カテゴリ
サマリ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を使用していたときは問題なくダウンロードできていたのですが...。

環境
  • Windows 2000 SP3
  • Apache/1.3.28 (Win32) PHP/4.3.2
  • PukiWIki 1.4rc3 EUCコードで運用
 

よろしくお願いします。

アップロードしたファイル
fileSample.sjis.txt
ダウンロード後のファイル
fileSample.sjis.txt.download

回答

  • sha 2003-08-09 (SAT) 16:13:03

    状況が再現できません。ちなみに、上の「アップロードしたファイル」をクリックすると、IE6でもnetscape7.1でも、正常な漢字コードでファイルの内容が表示されます。とりあえず、報告まで。

  • ny? 2003-08-11 (MON) 12:59:15

    こちらのサーバでからは正常にダウンロードできますね。うちの環境ではNetscape7.1でも試してみましたが、同様に文字化けしたファイルをダウンロードしてしまいます。

  • merlin 2003-08-11 (MON) 13:38:16

    linux系のサーバでは再現しませんねぇ。ダウンロード後のファイルは、バイナリエディタで見てみると文字化けどころではなく00 がほとんどになっていました。

  • sha 2003-08-11 (MON) 16:08:39

    行き詰まったら現場へ戻れとも言いますので⌣、「PukiWiki/Install/Windows」や、特に「mbstring」の設定をもう一度確認してみてはいかがですか?

  • ny? 2003-08-27 (WED) 10:54:51

    Windows向けのものやmbstringの設定も見直してみたのですが、変化ありませんでした。他にも画面左の最新20件が、各ページを編集するまで更新されないといった現象もあり、きれいな状態から入れなおした方がいいのかも知れません…。

    • sha 2003-08-27 (WED) 11:30:24

      うーむ。なぞですね。そもそもダウンロードで、ファイルの中身が変換されるのがおかしいかと思います。一方、ブラウザでの閲覧なら何か変換してそうですが。apacheの問題でしょうか???

      同じサーバ上に、その問題のファイルへのリンクを張った単なるHTMLファイルを置いて、ダウンロードでどのような現象が起こるか確認してみてはいかがでしょうか?また、その「問題のファイル(PukiWikiでアップロードしたもの)」でないSJISファイルの場合はどうなるのか、とかも。

      また、後半の「更新されない」現象はおそらく別の症状でして、ここ→「dev:BugTrack/413」をご参照下さい。

  • ny? 2003-09-01 (MON) 18:03:49

    ご丁寧にありがとうございます。直接attach/[ファイル名]のURLをブラウザでたたいたら、正常にダウンロードできました。また、漢字が入っていないファイルであれば問題なくダウンロードできます。改めてmbstringのパラメータを見直してみます。後半の「更新されない」は参照先でうまくいきました :) ありがとうございます。

  • ny? 2003-09-01 (MON) 18:21:11

    不思議な現象が・・・ テストで添付していたファイルを削除しようとして「添付ファイル一覧」でバックアップを見て気づいたのですが、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という状況です。ファイル内容は同一です。
  • sha 2003-09-01 (MON) 21:07:52

    それは重要なヒントですね。この現象の違いはおそらく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. 問題の起こったSJISファイルの拡張子をでたらめなものに置き換えて同じこと(添付してダウンロード)をして見て下さい。おそらくoctet-streamとして送信され大丈夫。(つまり大丈夫なら仮説が確からしい)
    2. 上で大丈夫だったと言っていた直接attach/[ファイル名]のSJISファイルに拡張子.txtを追加して、直接URLでアクセスして見てください。おそらくtext/plainと判定されて異常動作を引き起こします。(つまり失敗なら仮説が確からしい)
    • sha 2003-09-01 (MON) 21:38:36

      そういえば、1.3.5のときは問題なかったんですよね。じゃ、これはやはり違うかな???いや、1.3.5の場合にはmime-typeを設定する機能がなかったんですよね。1.3.5では添付ファイルは常にapplication/octet-streamとして扱っていたから大丈夫だったのかもしれません。そうすると、1.4になって初めてSJISファイルをtext/plainとして扱う状況が出て来たのではないでしょうか?つまり、これは以前から、nyさんのところのapacheが抱えていたバグだったとか?(おお、推理の絆!点と点が線で結ばれて来たかも)

  • sha 2003-09-01 (MON) 21:25:39

    もひとつ疑わしいのは、607行目のmb_convert_encodingでSJISに変換しているところ。もしかして、これをEUC-JPに変更するだけで直るかもしれません。もし、これで直ったら、「EUC-JPモードで運用」とは言っても、apacheはSJISで運用しなければならなかったのかもしれません(かな?)。

    • sha 2003-09-01 (MON) 21:35:29

      これ↑はあんまり関係なさそう。。。

  • sha 2003-09-01 (MON) 22:31:39

    ちなみに、294行目の正規表現はたぶん以下のような感じならよかったのかもしれません(動作未確認)。今回の場合は、こうするとバックアップファイルでも異常動作が生じるはずです(^_^;)。

    if (!preg_match('/_([0-9A-Z]+)(?:\.\d+)?$/',$filename,$matches))
  • sha 2003-09-02 (TUE) 10:58:16

    ちなみに、私はWindows XP Pro上ではApache2.0.46を使用しています。現在、2.0.47が出ているようですので試しにそれを使ってみるとか?「Apacheのサイト」をご参照。

  • ny? 2003-09-02 (TUE) 13:33:52

    仮説の検証を行ってみました。

    1. 拡張子を.txtから何かに変えての添付->ダウンロードは、うまくいきました(仮説どおり)。
    2. 拡張子を何かから.txtへ変えてURLダウンロードは、うまくいってしまいました(仮説と違う)。
    3. 607行目のソース変更は、うまくいきませんでした。日本語ファイル名のファイルを落とそうとした時に、ファイル名が化けてしまいました。

      どこかでPukiWikiはApache 2.0.xには正式に対応していない、というような表記を見かけた気がしたので、1.3.xを使用していました。もう少しApache, PHPの方も見直してみます。

    • reimy 2003-09-02 (TUE) 15:34:30

      Apache 2.0.xが正式に対応していないのはPukiWikiではなくってPHPだったと思いますが…。今はもう正式に対応になったのかな。

    • sha 2003-09-02 (TUE) 19:34:01

      私が最初にWindows XP Proにインストールしたときには、Apache/2.0.46, PHP/4.3.3RC1, PukiWiki/1.4RC3でちゃんと動作しておりました。というかアップデートしてないので今でもそのままですが(^_^;)。そういえば、PHPの正式対応かどうかは確認してなかったです。

  • sha 2003-09-02 (TUE) 19:38:50

    整理すると、i.の結果で、SJISファイルは、text/plainならダメでapplication/octet-streamならOKだと確認された。ii.では、ブラウザから直接apacheへアクセスすれば拡張子が.txtでもSJISファイルを読み取れることが確認された、ということですね。うーむ。一体誰がSJISファイルの第7ビットが立ってるバイトを0にしてしまうんだろう…。まさかPHP!?それとも、Apacheの動作が拡張子.txtで読む場合と、text/plainで読む場合とで動作が違うのか?この間にミッシングリンクがあるようだ。謎が謎を呼ぶミステリー。

  • Komugi? 2003-11-06 (THU) 10:18:15

    これ、IIS5.0でも起きます。Shift-JISで書かれた.txt や .htm(html)を添付して開くと、中身が文字化けします。

  • とおが? 2003-12-02 (TUE) 07:57:44

    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;
  • ぱんだ 2003-12-03 (WED) 00:01:56

    再現する環境が作れていないので当てずっぽうですが、単純にreadfileの前にmb_http_output('pass')を挿入してやるとどうなりますか?

  • Komugi? 2003-12-03 (WED) 17:49:29

    わたしの環境(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 は何か別の意図で入れられていたのでしょうか?)。
    とりあえずうまくいったので、手元の環境では当面これで運用してみたいと思います。
  • とおが? 2003-12-03 (WED) 22:12:30

    readfile の行頭の "-" は削除の意だったのですが、勿論 echo $file を抜いても同じ結果になります。1. で EUC が表示されないのはちょっと解せないですが。で、私なりの調査をまとめてみます。結論としてはdefault_charset = "EUC-JP" を止め(指定無し)た上で、

      header('Content-Type: '.$this->type);
    + mb_http_output('pass')
      @readfile($this->filename)
    です。
    • ここでの文字化けは http_output = EUC-JP 指定によるもので、SJIS が EUC の不正コードと解釈され substitute_character = none 指定により '\x00' に置換された結果である(substitute_character = long 指定にすると 'BAD+xxxx' に置換される)。
    • http_output の変換を無効にする為 mb_http_output('pass') を挿入した場合、ファイル自身はそのまま送信されるが、mime ヘッダに異常が見られ、'Content-type: text/plain;charset=EUC-JP\x00\x0d\x0a\x0d\x0a' となった。これは NT4+IIS4, 2000+IIS5 の環境で発生し、XP+IIS5.1 は 'Content-type: text/plain; charset=EUC-JP\x0d\x0a\x0d\x0a' であった(全て PHP4.3.3)。'charset=EUC-JP' の直後の null と直前のスペースの有無がその違いで、前者では受信できない。
    • http_output の変換を無効にしているので、header('Content-type'.$this->type) のみ、即ち 'Content-type: text/plain\x0d\0a\x0d\a' になればよいのだが、default_charset = "EUC-JP" 指定によって 'charset=EUC-JP' が付加され、この部分でプラットホーム依存の不具合があるようだ。
    • pukiwiki の出力に限って云えば、skin で charset を含む mime ヘッダを送出しているので、default_charset を指定しなくても問題はない(ホントに ?)。
    • PHP 全体の設定を変えられない(default_charset = "EUC-JP" が必要な)場合は、前述した都度エンコーディングを与える方法を取るか、あるいは charset と矛盾しても良ければ header 関数でなく default_mimetype を header 送出前に default_charset を書き換える方法がある。
      + //ini_set('default_mimetype', $this->type);
      + ini_set('default_charset', '');
        header('Content-Type: '.$this->type);
      + mb_http_output('pass');
        @readfile($this->filename);
    • まだ環境依存のとこで真の原因が判明してませんので、人柱さんの報告をお待ちしております。
    • とおが? あんまりなボケなので修正 &new([nodate]){date}: Invalid date string;
  • Komugi? 2003-12-04 (THU) 09:10:17

    失礼しました。"-"が削除の事だとわかっていたのですが、ぱんださんのやり方と両方試しているうちに編集ミスをしていました。readfileを削ってecho $fileとすれば正常に動作しました。

  • ぱんだ 2003-12-04 (THU) 13:29:55

    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=を出力したとしても、それが嘘である可能性が高いですから。
  • とおが? 2003-12-06 (SAT) 00:14:28

    何故 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') が必要だと思います。

    • ぱんだ 2003-12-06 (SAT) 14:01:20

      貴重な情報ありがとうございます。mb_http_output('pass')も入れておきます。

      • 1.4.3以降のパッケージに、修正済のファイルが収録

添付ファイル: fileSample.sjis.txt.download 2360件 [詳細] fileSample.sjis.txt 1847件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2010-06-18 (金) 18:37:22
Site admin: PukiWiki Development Team

PukiWiki 1.5.2+ © 2001-2019 PukiWiki Development Team. Powered by PHP 5.6.40-0+deb8u7. HTML convert time: 0.363 sec.

OSDN