4

私は初心者なので、私が抱えている問題を説明するために最善を尽くします。見落としや不明な点がありましたら、あらかじめお詫び申し上げます。

ルート ディレクトリの外にある 81 MB の zip ファイルを、事前に検証された人に提供しています。ダウンロードが破損している、またはダウンロードを完了できないという報告を受けています。低速接続をシミュレートすると、マシンでこれが発生することを確認しました。

私は Apache-Coyote/1.1 を実行している共有ホスティングを使用しています。

ネットワーク タイムアウト エラーが発生します。ホストがダウンロードに時間がかかりすぎる場合、ダウンロードを強制終了している可能性があると思いますが、どちらの方法でも確認していません。

メモリ制限または時間制限に達している可能性があると思ったので、ホストは apache モジュール XSendFile をインストールしました。検証後にダウンロードを処理するファイルのヘッダーは、次のように設定されています。

<?php
set_time_limit(0);
$file = '/absolute/path/to/myzip/myzip.zip';

header("X-Sendfile: $file");
header("Content-type: application/zip");
header('Content-Disposition: attachment; filename="' . basename($file) . '"');

ヘルプや提案をいただければ幸いです。ありがとう!

4

1 に答える 1

2

このコメントを見ることをお勧めします:

http://www.php.net/manual/en/function.readfile.php#99406

特に、Apache を使用している場合。そうでない場合は、上記のリンクのコードが役立つはずです。

ダウンロード速度が非常に遅いクライアントに非常に大きなファイルが送信されたときに、問題が発生し始めました。そのような場合、スクリプトがタイムアウトし、ダウンロードは不完全なファイルで終了します。私はスクリプトのタイムアウトを無効にすることに固執しています-それがプログラミングの問題の解決策であるときはいつでも、あなたは何か間違ったことをしています-そのため、ファイルのサイズに基づいてタイムアウトをスケーリングしようとしました. しかし、エンド ユーザーがファイルをダウンロードする速度を予測することは不可能であったため、最終的には失敗に終わりました。つまり、これは最良の推測に過ぎず、必然的にスクリプト タイムアウトのレポートが引き続き表示されます。

その後、mod_xsendfile ( https://tn123.org/mod_xsendfile/ (バイナリ) または https://github.com/nmaier/mod_xsendfile (ソース)) と呼ばれる素晴らしい Apache モジュールに出くわしました。このモジュールは基本的に出力バッファを監視して特別なヘッダーが存在するかどうかを確認し、それらが見つかると、ユーザーがファイルを直接要求したかのように、apache をトリガーしてファイルを独自に送信します。PHP の処理はその時点で停止するため、ファイルのサイズやクライアントのダウンロード速度に関係なく、タイムアウト エラーは発生しません。また、エンド クライアントは、正確なファイル サイズ レポートやダウンロード ステータス バーなど、ファイルを送信する Apache の利点を最大限に活用できます。

最終的に完成したコードは長すぎてここに投稿できませんが、一般的に mod_xsendfile モジュールが存在する場合はそれを使用し、存在しない場合、スクリプトは最初に投稿したコードを使用するようにフォールバックします。サンプル コードはhttps://gist.github.com/854168にあります。

編集

元のコードへのリンクを「チャンク」するコードの参照を取得するだけです:

<?php 
function readfile_chunked ($filename,$type='array') { 
  $chunk_array=array(); 
  $chunksize = 1*(1024*1024); // how many bytes per chunk 
  $buffer = ''; 
  $handle = fopen($filename, 'rb'); 
  if ($handle === false) { 
   return false; 
  } 
  while (!feof($handle)) { 
      switch($type) 
      { 
          case'array': 
          // Returns Lines Array like file() 
          $lines[] = fgets($handle, $chunksize); 
          break; 
          case'string': 
          // Returns Lines String like file_get_contents() 
          $lines = fread($handle, $chunksize); 
          break; 
      } 
  } 
   fclose($handle); 
   return $lines; 
} 
?>
于 2012-09-13T17:47:23.453 に答える