我正在为一个网站的PHP页面工作,该网站将文件压缩在一起并允许用户下载它。 zip 的文件大小可以从几 MB 到 100MB 不等。 我的 PHP 脚本在临时目录中创建 zip 文件,然后将文件内容写出到浏览器。 完成此操作后,脚本将更新 MySQL 数据库中的下载计数器,并从临时目录中删除 zip 文件。
这一切都很好,直到我遇到一个需要超过 30 秒的大型 zip 下载。 php.ini 文件中的max_execution_time
设置为 30,所以这是有道理的,但如果我尝试使用 set_time_limit(0)
或更改max_execution_time
,则会出现相同的结果。 zip 文件从浏览器中成功下载,其中包含所有正确的文件,但脚本似乎随后停止,因为数据库未更新且服务器上的临时 zip 文件未删除。
这是一个带有Apache和PHP 5.2的Linux环境。
该网站托管在GoDaddy上,所以我不确定他们是否对更改脚本可以执行的时间限制有限制,但基本上我想让这个特定的脚本无限期运行,直到它完成。
关于为什么我无法设置时间限制或任何解决方法的任何想法?
这是我的代码:
<?php
// Don't stop the script if the user
// closes the browser
ignore_user_abort(true);
set_time_limit(0);
// Generate random name for ZIP file
$zip_file = "";
$characters = "0123456789abcdefghijklmnopqrstuvwxyz";
do
{
$zip_file = "tmp/";
for ($p = 0; $p < 10; $p++)
$zip_file .= $characters[mt_rand(0, strlen($characters))];
$zip_file .= ".zip";
} while (file_exists($zip_file));
// Prepare ZIP file
$zip = new ZipArchive();
/* Open and add files to ZIP (this part works fine)
.
.
.
*/
// Close and save ZIP
$zip->close();
// Check browser connection
if (connection_status() == 0)
{
// Send ZIP
header("Content-Type: application/zip");
header("Content-Length: " . filesize($zip_file));
header("Content-Disposition: attachment; filename=Download.zip");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
// Save and then delete file
//readfile($zip_file);
if ($file = fopen($zip_file, "r"))
{
// Set buffer size
$buffer_size = 1024 * 8;
// While we're still transmitting
// send over bytes!
while(!feof($file) && (connection_status() == 0))
{
print(fread($file, $buffer_size));
flush();
usleep(10000); //<!-- Download speed cap
}
// Close file descriptor
fclose($file);
}
}
/* Update database download counter if connection_status() == 0
.
.
.
*/
// Delete the file
unlink($zip_file);
?>
更新:我刚刚尝试从本地Web服务器进行另一次下载,并将usleep
命令提高到10000以减慢下载时间。 总下载时间略多于 1 分钟,数据库已更新,文件已从/tmp 中删除。 我的本地环境在Windows 7机器上运行带有Apache的EasyPHP和PHP 5.3。 似乎这可能与GoDaddy有关。
此外,在 GoDaddy 和本地站点上,我从我的脚本中调用set_time_limit
之前和之后打印了max_execution_time
,结果分别为 30 和 0,所以我不确定 GoDaddy 方面发生了什么事情。
- 也许是 HTTP 服务器配置中的问题?您使用什么,配置是什么?
- 另一种变体,当下载结束时,连接状态可能不等于 0。因此,根本不计算数据库更新条件中的代码。
- 在 php.ini 中是否配置了任何错误日志记录?如果是,您是否查看了php.error.log,也许存在一些内存泄漏和"内存不足"错误。
仍然不确定为什么我上面使用的代码在托管站点上不起作用,但我找到了解决方法。 如果我在活动站点上使用 PHP 中的 register_shutdown_function
调用,数据库将正确更新并删除文件。
以下是关机函数代码:
<?php
$filesize = 0;
$total_bytes_read = 0;
$download_query = "";
$zip_file = "tmp/download.zip";
register_shutdown_function("shutdown");
/* Other code for creating ZIP file and reading it out to the browser
.
.
.
*/
function shutdown()
{
global $filesize;
global $total_bytes_read;
global $zip_file;
global $download_query;
// Update the database if file was fully downloaded
if ($filesize != 0 && $filesize == $total_bytes_read)
{
/* Do database update with $download_query
.
.
.
*/
}
// Delete the file
unlink($zip_file);
}
?>
你应该能够在 php5 中设置你的max_execution_time.ini并通过 PHP 信息页面进行检查。 你能提供你的php5.ini的部分和你从PHPinfo页面输出吗?