2016-06-24 2 views
1

私はfile_get_contents()を使用して、7M(7〜30M)を超えるファイルを読み取ります。そして、私はクライアントにそれをダウンロードさせるためにそれをエコーし​​ます。PHP:なぜ16KB(16624バイト)のファイルしかダウンロードできないのですか?

注:これらのファイルをダウンロードするための直接リンクはありません。だから私はそれをPHPに読み込んでダウンロードファイルを作成しなければなりません。大きなファイルをメモリに読み込むことは間違った考えです---ファイルを直接ダウンロードすることが最善の方法です。しかし今はそうではありません...ファイルは他人によって作成され、クラウドファイルサーバーに移動する計画はありません。 ---私はそれをPHPで処理する必要があります。

何か不自由なことがあります。私の個人的なPHP7ドッカーコンテナでうまくいきます(設定ファイルはhttps://github.com/AarioAi/Confです)

私はフルファイル(おそらく7.8M)をダウンロードできます。

しかし、私はこれらのコードをPHPとNginxの設定とほぼ同じ別のサーバ(PHP 5.5)にプッシュします。このファイルは16KB(16624B)しかダウンロードできません。

"HTTP_RANGE": null, 
"Content-Length:": 7490833, 
"md5": "aaefc8249e2a96574fa7b83e7bc168f0", 
"fileSize": 7490833 

16キロバイトのセグメントは、元のファイルの一部であるかどうかを確認するために:

ここで7.8Mバイナリファイルに関するデバッグ情報です。私は繰り返される文字列 "Hello、Aario"で16Mファイルを埋めます。シェルスクリプトによって。次に、ダウンロードした16KBセグメントをPHP 5.5サーバから開きます。それらはすべて "Hello、Aario。Hello、Aario。....."です。

したがって、16KBは間違いなく元のファイルのセグメントです。

"HTTP_RANGE": null, 
"Content-type": "application/force-download", 
"Content-Length:": 16155228, 
"md5": "5c919dd9d1049a59e7c2a8cb55a695a9", 
"fileSize": 16155228 

私はob_xxxに何も送信しないので、私はoutput_buffering設定と間違って何もないと思う:「こんにちは、Aario」

はここ16Mについてのデバッグ情報です。 PHP memory_limitの設定は、両方のサーバで同じです。また、php-fpm.confファイル間には大きな違いはないことに気付きました。

私はタイムアウトしていると思います。私は別のサーバ(PHP 5.5)のNginx keepalive_timeoutをチェックしていますが、それはこのサーバ(PHP 7)よりも長い65です。

あなたは私にいくつかのヒントを教えていただけますか?

//--------------------------------------------------------------------- 
$length = (function_exists('mb_strlen') ? mb_strlen($content, '8bit') : strlen($content)); 
// it's just the sample to calculate Content-Length, actually, 
// it needs be handled in the if (isset($_SERVER['HTTP_RANGE'])) {} 
//---------------------------------------------------------------------- 

if (isset($_SERVER['HTTP_RANGE'])) { 
     header('Accept-Ranges: bytes'); 
     //client sent us a multibyte range, can not hold this one for now 
     if (strpos($_SERVER['HTTP_RANGE'], ',') !== false) { 
      header("Content-Range: bytes $contentStart-$contentEnd/$fileSize"); 
    .... 
    .... 
} 



if ($debug > 0) { 
     return [ 
      'Content-type' => $contentType, 
      'Content-Length:' => $length, 
      'md5' => md5_file($file), 
      'fileSize' => $fileSize, 
     ]; 
    } else { 
     header('Pragma: public'); 
     header('Expires: 0'); 
     header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 
     header("Content-Type: $contentType"); 
     header('Content-Length: ' . $length); 
     header("Content-Disposition: attachment; filename=\"$fileName\""); 
     header('Content-Transfer-Encoding: binary'); 
     $content = function_exists('mb_substr') ? mb_substr($content, $contentStart, $length) : substr($content, $contentStart, $length); 
     ob_start(); 
     ob_end_clean(); 
     echo $content; 
     exit(0); 
    } 

答えて

1

表示するコードがどのように機能するかはわかりません。それはしません。 1つには、file_get_contents()はありません。これは何をするのですか?

ob_start(); 
    ob_end_clean(); 

何もありません。定義されていない変数もたくさんあります。要するに、これは悪い例です。

file_get_contents()で大きなファイルを読んでから、echoと書いてありますが、これは私の意見では良い考えではありません。ファイル全体がメモリに読み込まれ、そこに格納されてから出力に送信されます。伝統的にファイルは常にチャンクで読み込まれてから、出力にチャンクを送ります。

// open the file in a binary mode 
$filename = '/mybigfile.huge'; 
$handle = fopen($filename,'rb'); 

if ($handle) 
{ 
    // send the right headers 
    header("Content-Type: ....."); 
    header("Content-Length: " . filesize($filename)); 
    ........ 

    // dump the file to the output 
    fpassthru($handle); 
    // close file 
    fclose($handle); 
} 
+0

のob_start()...あなたはそれをグーグルことができます。

出力にファイルをストリーミングするためのより良い方法はこれです。クライアントがHTTP_RANGEを送信できるようにしたい。 – AarioAi

+0

私のポイントは: 'ob_start();'、 'ob_end_clean();'の直後には何もありません。あなたはそれを残すことができ、結果は同じになります。 'HTTP_RANGE'に関して:私のコードは簡単な例ですが、あなたが望むならそれを拡張することができます。 –

+0

私は前にfopenを試みましたが、 'echo $ content'と同じでした。大きなファイルをメモリに読み込むのは間違った考えです---ファイルを直接ダウンロードするリンクを作るのが最善の方法です。しかし今はそうではありません...ファイルは他人によって作成され、クラウドファイルサーバーに移動する計画はありません。 ---私はそれをPHPで処理する必要があります。私はfpassthruを試しました、それは同じですが、わずか16KBはPHP 5.5サーバからダウンロードできますが、PHP7からは7.8Mです。 – AarioAi

関連する問題