9

ユーザーに大きな zip ファイルを提供しようとしています。2 つの同時接続がある場合、サーバーはメモリ (RAM) を使い果たします。メモリ量を 300MB から 4GB (Dreamhost VPS) に増やしたところ、問題なく動作しました。

2 つ以上の同時接続を許可する必要があります。実際の 4GB では、20 の同時接続が可能になります (残念です)。

さて、私が使用している現在のコードでは、実際のファイル サイズの 2 倍のメモリが必要です。それは残念です。ファイルをユーザーに「ストリーミング」するようなものが必要です。したがって、ユーザーに提供されているチャンクを超えないように割り当てます。

次のコードは、CodeIgniter (PHP フレームワーク) で使用しているものです。

ini_set('memory_limit', '300M'); // it was the maximum amount of memory from my server
set_time_limit(0); // to avoid the connection being terminated by the server when serving bad connection downloads
force_download("download.zip", file_get_contents("../downloads/big_file_80M.zip"));exit;

force_download 関数は次のとおりです (CodeIgniter のデフォルトのヘルパー関数)。

function force_download($filename = '', $data = '')
{
    if ($filename == '' OR $data == '')
    {
        return FALSE;
    }

    // Try to determine if the filename includes a file extension.
    // We need it in order to set the MIME type
    if (FALSE === strpos($filename, '.'))
    {
        return FALSE;
    }

    // Grab the file extension
    $x = explode('.', $filename);
    $extension = end($x);

    // Load the mime types
    @include(APPPATH.'config/mimes'.EXT);

    // Set a default mime if we can't find it
    if ( ! isset($mimes[$extension]))
    {
        $mime = 'application/octet-stream';
    }
    else
    {
        $mime = (is_array($mimes[$extension])) ? $mimes[$extension][0] : $mimes[$extension];
    }

    // Generate the server headers
    if (strpos($_SERVER['HTTP_USER_AGENT'], "MSIE") !== FALSE)
    {
        header('Content-Type: "'.$mime.'"');
        header('Content-Disposition: attachment; filename="'.$filename.'"');
        header('Expires: 0');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header("Content-Transfer-Encoding: binary");
        header('Pragma: public');
        header("Content-Length: ".strlen($data));
    }
    else
    {
        header('Content-Type: "'.$mime.'"');
        header('Content-Disposition: attachment; filename="'.$filename.'"');
        header("Content-Transfer-Encoding: binary");
        header('Expires: 0');
        header('Pragma: no-cache');
        header("Content-Length: ".strlen($data));
    }

    exit($data);
}

Google で見つけたチャンク ベースのコードをいくつか試しましたが、ファイルは常に破損して配信されました。おそらく悪いコードが原因です。

誰でも私を助けることができますか?

4

6 に答える 6

3

このスレッドにはいくつかのアイデアがあります。readfile() メソッドがメモリを節約するかどうかはわかりませんが、有望に思えます。

于 2011-06-01T02:33:06.233 に答える
3

このファイルの内容 ($data) を PHP 経由で送信していますか?

その場合、これを処理する各 Apache プロセスは、データがキャッシュされるため、最終的にこのファイルのサイズまで大きくなります。

あなたの唯一の解決策は、PHP 経由でファイルの内容/データを送信せず、ユーザーをファイルシステムのダウンロード URL にリダイレクトすることです。

生成された一意のシンボリック リンク、または非表示の場所を使用します。

于 2011-06-01T12:38:28.217 に答える
0

$dataをファイルデータ全体で使用することはできません。ファイルの内容ではなく、パスだけをこの関数に渡してみてください。次に、すべてのヘッダーを1回送信し、その後、fread()を使用してこのファイルの一部を読み取り、そのチャンクをエコーし​​、flush()を呼び出して繰り返します。その間に他のヘッダーが送信されると、最終的に転送が破損します。

于 2011-06-01T02:38:34.003 に答える
0

大きなファイルをドキュメントルートにシンボリックリンクし(許可された唯一のファイルではないことを前提としています)、Apacheに処理させます。(そうすれば、バイト範囲も受け入れることができます)

于 2011-06-01T02:42:07.060 に答える
0

ini_set前に追加SESSION_START();

于 2011-07-07T11:50:00.573 に答える