【发布时间】:2012-04-13 09:33:33
【问题描述】:
全部,
我已经建立了一个表格,如果用户填写表格,我的代码可以确定该用户需要下载哪些(大)文件。我用下载按钮显示每个文件,我想在按钮旁边显示该文件的下载状态(下载正在进行、取消/中止或完成)。因为文件很大(200 MB+),所以我使用一个众所周知的函数来读取要以块下载的文件。 我的想法是记录数据库中每个(100 KB)块的读取,这样我就可以跟踪下载进度。 我的代码如下:
function readfile_chunked($filename, $retbytes = TRUE)
{
// Read the personID from the cookie
$PersonID=$_COOKIE['PERSONID'];
// Setup connection to database for logging download progress per file
include "config.php";
$SqlConnectionInfo= array ( "UID"=>$SqlServerUser,"PWD"=>$SqlServerPass,"Database"=>$SqlServerDatabase);
$SqlConnection= sqlsrv_connect($SqlServer,$SqlConnectionInfo);
ChunckSize=100*1024; // 100 kbyte buffer
$buffer = '';
$cnt =0;
$handle = fopen($filename, 'rb');
if ($handle === false)
{
return false;
}
$BytesProcessed=0;
while (!feof($handle))
{
$buffer = fread($handle, $ChunckSize);
$BytesSent = $BytesSent + $ChunckSize;
// update database
$Query= "UPDATE [SoftwareDownload].[dbo].[DownloadProgress] SET LastTimeStamp = '" . time() . "' WHERE PersonID='$PersonID' AND FileName='$filename'";
$QueryResult = sqlsrv_query($SqlConnection, $Query);
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;
}
奇怪的是,我的下载以恒定的速度平稳运行,但我的数据库会以峰值更新:有时我会在一秒钟内看到几十个数据库更新(所以几十个 100 KB 块),下一刻,我看到没有数据库更新(因此 PHP 没有提供 100 k 块)长达一分钟(此超时取决于可用于下载的带宽)。一分钟内没有写入任何进度的事实使我的代码认为下载已中止。 与此同时,我看到 IIS 的内存使用量在增加,因此我认为 IIS 会缓冲 PHP 提供的数据块。 我的网络服务器在 FastCGI 模式下运行 Windows 2008 R2 数据中心(64 位)、IIS 7.5 和 PHP 5.3.8。我可以做些什么(在我的代码、我的 PHP 配置或 IIS 配置中)以防止 IIS 缓存 PHP 提供的数据,或者如果生成的数据实际传递到下载客户端? 提前致谢!
【问题讨论】:
-
无法通过 PHP 获取下载进度 :)
-
@OptimusCrime:错了。使用数据库写入状态,并使用 Ajax 读取。也许使用 APC。
-
@OptimusCrime - 如果你按照 OP 正在做的事情,将文件分成单独的部分,并在每个部分交付时记录
-
谢谢大家,但 Ben 所说的正是我的问题所在:我将文件分成几部分,并在交付部分时写入数据库。但是,由于 IIS 介于两者之间,PHP 将文件部分传递给 IIS 而不是客户端。我想知道如何绕过 IIS 缓存,所以我的部分以更流畅的方式交付(而不是“让我们在缓冲区中推送 100 兆字节并等待一分钟) -for-it-to-clear”的方式,就像现在正在发生的那样)。