0

外部 API からユーザーに大きなファイルを渡そうとしています (100MB 以上と考えてください)。

現在、スクリプトをできるだけ早くダウンロードするために、少し妄想的なスクリプトを使用しています (過去の失敗のため)。

「ダウンロード」とは、ファイルの実際のダウンロードではなく、ブラウザーでのダウンロード トリガーのみを意味します。ユーザーがファイルを保存する場所を選択できるポイント。

set_time_limit(0);

apache_setenv('no-gzip', 1);
ini_set('zlib.output_compression', 0);
ini_set('output_buffering', 0);
ini_set('implicit_flush', 1);
for($i = 0; $i < ob_get_level(); $i++) { ob_end_flush(); }
ob_implicit_flush(1);

header('Content-Description: File Transfer');
header('Content-type: application/octet-stream');
header('Content-Transfer-Encoding: Binary');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Cache-Control: private');

ob_flush();
flush();

$fh = fopen($external_api_url, 'rb');
while(!feof($fh))
{
    echo fread($fh, 512);
    ob_flush();
    flush();
}
fclose($fh);

このスクリプトを使用すると、ダウンロード ポップアップが表示されるまでに 50 MB のファイルの場合でも 20 秒かかり、大きなファイルの場合はさらに長くなります。

ストリームをより速く開始する方法はありますか?

編集: fpassthru() と readfile() も試しましたが、これらは同じ 50 MB のファイルに 40 秒かかるため、この方法の方が優れていると思います。また、さまざまな読み取りサイズ(512、256、64、その他のいくつか)で遊んでみましたが、違いに気づきませんでした)

4

1 に答える 1

0

ブラウザーがダウンロード ダイアログをトリガーするのに非常に時間がかかる理由は、API がデータの最初のチャンクを返すのに時間がかかるためです。これは、常に最初の 512 バイトをできるだけ速く書き込もうとしているにもかかわらず、長いファイルほど起動に時間がかかる理由を説明しています。

ローカル ファイルから読み取ってローカルでシミュレートしようとしましたが、ループsleep(5);の直前にステートメントがありました。while

ファイルを読み取ろうとする前に呼び出しを発行しながら、行を省略することで、データの前に Google Chrome にダウンロードを開始させることができました。(あなたはすでにこの第 2 部を行っています)header('Content-type: application/octet-stream');flush();

ただし、これは Firefox 3.6 では機能しないようです。そのため、ファイルの最初の文字を予測し ( BOMを見てください)、それを何よりも前にエコーし、その後それをあなたの最初のfread()電話の始まり。

それが役立つことを願っています!しかし、基本的に外部 API はあなたを台無しにしています。

于 2013-05-21T18:23:44.037 に答える