2011-07-08 11 views
21

直接HTTPリクエスト(ファイルを安全に保つ、ダウンロードを追跡するなど)を許可するのではなく、PHPを効率的に使用してファイルをダウンロードする方法について多くの質問がありました。なぜreadfile()はPHPメモリを使い果たしますか?

答えはほとんど常にPHP readfile()です。

しかし、それは巨大なファイル、それはユーザーの何百ものライブサイト上にあるとき、ダウンロードがハングし始め、PHPでのテスト中に素晴らしい作品が、メモリの限界が使い果たされる。

readfile()がトラフィックが高いときにメモリが爆発する原因は何ですか?私はそれが出力バッファに直接書き込むことによってPHPメモリの大量使用をバイパスすることになっていると思った?

EDIT:(明確にするために、私は「なぜ」を探しています、「私は何を行うことができない」私はApacheのmod_xsendfileを回避するための最良の方法だと思います。)

+1

(ob_start()経由で)PHP出力バッファリングをしていますか?もしそうなら、PHPはファイルの内容をキャッチしてメモリの問題を引き起こします。 – ceejayoz

+1

リンクされたPHPドキュメントの例を使って、私はob_clean()を持っていません。流す(); readfile($ file); – tmsimont

答えて

4
Description 
int readfile (string $filename [, bool $use_include_path = false [, resource $context ]]) 
Reads a file and writes it to the output buffer*. 

PHPをしなければなりませんファイルを読み込み、出力バッファに書き込みます。 したがって、300Mbファイルの場合、実装した実装(多くの小さなセグメント、または1つの大きなチャンク)にかかわらず、PHPは最終的に300Mbのファイルを読み取る必要があります。

複数のユーザーがファイルをダウンロードする必要がある場合、問題が発生します。 (1つのサーバーでは、ホスティングプロバイダによって、各ホストユーザーに与えられるメモリが制限されます。このような限られたメモリでは、バッファを使用するのは良い考えではありません)

ファイルをダウンロードするダイレクトリンクを使用すると大きなファイルの方がはるかに優れています。

+0

PHPがUserAのために "出力バッファに書き込む"のであれば、UserBとUserCは利用できないメモリを使用していますか?メモリの最終的な過剰使用につながる? – tmsimont

+0

はい。 PHPは他のユーザがいつ同じファイルをダウンロードするのか分からないので、PHPはバッファにファイルを読み込み、できるだけ早くリクエスタに書き込みます... 100人のユーザが同じ10MBファイルを要求すると、メモリ使用量はおそらく1000MBであろう。 – user482594

+0

は私にとって理にかなっています...だから、readfile()はそのトリックをあまりしていないので、交通量の多い状況では避けるべきです。ありがとう。 – tmsimont

0

まあ、それはメモリ集中的な機能です。 readfile()を使用する代わりに、ダウンロードを制御する特定のルールが設定された静的サーバーにユーザーを配管します。

これはオプションではないため、負荷を満たすためにRAMを追加したり、サーバーの使用状況を適切に制御するキューイングシステムを導入したりしてください。

1

PHP's output_buffering configurationディレクティブを使用して、特定の場所で出力バッファリングを完全にオフにしたい場合があります。

Apacheの例:値として

<Directory "/your/downloadable/files"> 
    ... 
    php_admin_value output_buffering "0" 
    ... 
</Directory> 

「オフ」は、それが本当にエラーをスローする必要がありながら、同様に動作しているようです。少なくともhow other types are converted to booleans in PHPによる。あなたは(のReadFileする右の呼び出しの前にはob_end_flush使うよりも上の出力バッファリングを()している場合* *

2

を肩をすくめる)

header(...); 
ob_end_flush(); 
@readfile($file); 
+0

2GBファイルでreadfileを実行する前にこれを追加しようとしましたが、それでもメモリ制限を超えました – NDM

+0

上記のように、出力バッファリングは問題ではありません。 – reggie

1

は(私のライブラリの一部として)過去にこのアイデアを思い付きました高いメモリ使用量を避けるために:

function suTunnelStream($sUrl, $sMimeType, $sCharType = null) 
{ 
    $f = @fopen($sUrl, 'rb'); 
    if($f === false) 
    { return false; } 

    $b = false; 
    $u = true; 

    while($u !== false && !feof($f)) 
    { 
    $u = @fread($f, 1024); 
    if($u !== false) 
    { 
     if(!$b) 
     { $b = true; 
     suClearOutputBuffers(); 
     suCachedHeader(0, $sMimeType, $sCharType, null, !suIsValidString($sCharType)?('content-disposition: attachment; filename="'.suUniqueId($sUrl).'"'):null); 
     } 
     echo $u; 
    } 
} 

    @fclose($f); 
    return ($b && $u !== false); 
} 

これはあなたにあるインスピレーションを与えるかもしれません。

1

ここに記載されているように:"Allowed memory .. exhausted" when using readfile、PHPファイルの先頭に次のコードブロックがあります。

これはPHPの出力バッファリングがアクティブかどうかをチェックします。もしそうなら、それはそれをオフにする。

if (ob_get_level()) { 
    ob_end_clean(); 
} 
+0

質問が「なぜ」なので、私はあなたが解決策ではなく説明を提供すべきだと思います。結局のところ、あなたは基本的に既存の答えをコピーしています。 –

+0

ああ、そうです。私は先に進み、簡単な説明を加えました。 –

関連する問題