6

サイズが不明でサイズが増加しているリモートファイルで PHP readfile 関数を使用することは可能ですか? シナリオは次のとおりです。

サードパーティの Web サイトからビデオをダウンロードし、同時にビデオを MP3 形式にトランスコードするスクリプトを開発しています。この MP3 は、readfile を介してユーザーに転送されます。

上記のプロセスに使用されるクエリは次のようになります。

wget -q -O- "VideoURLHere" | ffmpeg -i - "Output.mp3" > /dev/null 2>&1 &

そのため、ファイルの取得とエンコードが同時に行われます。上記のプロセスが進行中のとき、出力 mp3 を readfile 経由でユーザーに送信し始めます。問題は、エンコード プロセスに時間がかかるため、ユーザーのダウンロード速度によっては、ファイル全体がエンコードされる前に readfile が推定 EoF に達し、ユーザーが部分的なコンテンツや不完全なファイルを受け取ることになります。

これを修正するための最初の試みは、ユーザーのダウンロードに速度制限を適用することでしたが、エンコード時間と速度は負荷によって異なり、部分的なダウンロードにつながるため、これは絶対確実ではありません.

エンコーディングと同時にダウンロードを提供し、完全なファイルをエンドユーザーに送信することを保証できるように、このシステムを実装する方法はありますか?

どんな助けでも大歓迎です。

編集: ピーターに応えて、私は実際に fread(read readfile_chunked) を使用しています:

 <?php
 function readfile_chunked($filename,$retbytes=true) {
            $chunksize = 1*(1024*1024); // how many bytes per chunk
            $totChunk = 0;
            $buffer = '';
            $cnt =0;
            $handle = fopen($filename, 'rb');
            if ($handle === false) {
                return false;
            }
            while (!feof($handle)) {
                //usleep(120000); //Used to impose an artificial speed limit
                $buffer = fread($handle, $chunksize);
                echo $buffer;
                ob_flush();
                flush();
                if ($retbytes) {
                    $cnt += strlen($buffer);
                }
            }
                $status = fclose($handle);
            if ($retbytes && $status) {
                return $cnt;        // return num. bytes delivered like readfile() does.
            }
            return $status;
        }
        readfile_chunked($linkToMp3);
    ?>

ユーザーのダウンロード速度とエンコード速度によっては、早期に EOF() に到達する可能性があるため、これは完全なダウンロードを保証するものではありません。

また、Jeztah のコメントに応えて、ユーザーを待たせることなくこれを達成しようとしています..それはオプションではありません。

4

4 に答える 4

2

ストリームを扱っているので、おそらくストリーム処理関数を使用する必要があります:)。パススルーdownload | transcodeが思い浮かびますが、これはコマンドがスクリプトで開始された場合にのみ機能します。

外部から開始する場合は、stream_get_contentsを確認してください。

于 2013-01-28T17:09:26.753 に答える
1

Evertが言及したLibeventは、ファイルをバッファとして使用する必要ある一般的なソリューションのようです。ただし、あなたの場合、ファイルをバッファとして使用せずに、スクリプト内ですべてインラインで実行できます。

<?php
header("Content-Type: audio/mpeg");
passthru("wget -q -O- http://localhost/test.avi | ffmpeg -i - -f mp3 -");
?>
于 2013-02-10T02:27:54.717 に答える
0

inotifyのようなものを除いて、新しいデータがあることについて通知されることはないと思います。

EOFにclearstatcache()達した場合は、200ミリ秒ごとにファイルの変更時間(呼び出し間を使用)のポーリングを開始することをお勧めします。ファイルサイズが大きくなったら、ファイルを再度開いて、最後の位置までシークして続行できます。

于 2013-01-27T22:04:18.380 に答える
-1

このようなアプリケーションにはlibeventを使用することを強くお勧めします。

このような場合に最適です。

PHPのドキュメントはこれについては少しまばらですが、Web上でより確かな例を見つけることができるはずです。

于 2013-01-27T19:49:53.113 に答える