6

是否可以在大小未知且大小不断增加的远程文件上使用 PHP readfile 函数?这是场景:

我正在开发一个从第三方网站下载视频并同时将视频转码为 MP3 格式的脚本。然后通过 readfile 将此 MP3 传输给用户。

用于上述过程的查询是这样的:

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

因此文件被同时获取和编码。现在,当上述过程正在进行时,我开始通过 readfile 将输出 mp3 发送给用户。问题是编码过程需要一些时间,因此根据用户的下载速度,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() 可能会过早到达。

同样为了回应 theJeztah 的评论,我正在尝试实现这一目标,而不必让用户等待......所以这不是一个选择。

4

4 回答 4

2

由于您正在处理流,因此您可能应该使用流处理函数:)。想到了passthrudownload | 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 文档对此有点稀疏,但您应该能够在网络上找到更多可靠的示例。

于 2013-01-27T19:49:53.113 回答