所有
我已经构建了一个表单,如果用户填写表单,我的代码可以确定该用户需要下载哪些(大)文件。我用下载按钮显示每个文件,我想在按钮旁边显示该文件的下载状态(正在下载,取消/中止或完成)。因为文件很大(200 MB +),我使用一个众所周知的函数来读取要在chuncks中下载的文件。 我的想法是记录数据库中每个(100千字节)块的读数,这样我就可以跟踪下载的进度。 我的代码如下:
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千字节的块),下一刻我看到没有数据库更新(所以没有100 k块由PHP提供)长达一分钟(这个超时取决于下载的可用带宽)。一分钟没有进展的事实使我的代码认为下载已中止。 与此同时,我看到IIS的内存使用量在增加,因此我认为IIS可以缓冲PHP提供的数据块。 我的网络服务器在FastCGI模式下运行Windows 2008 R2数据中心(64位),IIS 7.5和PHP 5.3.8。有什么我可以做的(在我的代码中,在我的PHP配置或IIS配置中)以防止IIS缓存PHP提供的数据,或者有任何方法可以在PHP中查看生成的数据是否实际传递给了下载客户端? 提前谢谢!
答案 0 :(得分:1)
由于没有得到有用的答案,我通过严格使用Apache来下载文件创建了一个真正的狡猾的解决方法。整个表单,CSS等仍然通过IIS提供,只是下载链接是Apache的服务器(反向代理服务器位于其间,所以用户不必操纵端口号,代理负责这一点)。 Apache不会缓存PHP输出,因此我在数据库中获得的时间戳是可靠的。
答案 1 :(得分:0)
我曾经问了一次 similar question ,并在那里得到了很好的答案。
基本上,您使用APC缓存来缓存变量,然后使用来自客户端的Ajax调用在不同的页面中检索它。
另一种可能性是对数据库执行相同操作。将进度写入数据库并让客户端使用Ajax调用来测试(比如每秒)。