0

我正在为一个网站开发一个 PHP 页面,该页面将压缩文件并允许用户下载它。zip 的文件大小可以从几 MB 到 100 MB 不等。我的 PHP 脚本在临时目录中创建 zip 文件,然后将文件内容写入浏览器。完成后,脚本会更新 MySQL 数据库中的下载计数器并从 temp 目录中删除 zip 文件。

这一切都很好,直到我遇到一个需要超过 30 秒的大型 zip 下载。 max_execution_time在 php.ini 文件中设置为 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 和 PHP 5.3 的 EasyPHP。似乎这可能与 GoDaddy 有关。

此外,在 GoDaddy 和本地站点上,我在脚本调用max_execution_time之前和之后打印出来set_time_limit,结果分别为 30 和 0,所以我不确定 GoDaddy 方面发生了什么。

4

3 回答 3

0
  1. 也许你的 HTTP 服务器配置有问题?你在用什么,配置是什么?
  2. 另一种变体,当下载结束时,连接状态可能不等于0。因此,根本不会评估您在数据库更新条件下的代码。
  3. php.ini 中是否配置了任何错误日志记录?如果是,您是否查看了 php.error.log,可能存在一些内存泄漏和“内存不足”错误。
于 2012-04-30T21:11:07.443 回答
0

您应该能够在 php5.ini 中设置 max_execution_time 并使用 PHP 信息页面进行检查。你能提供你的 php5.ini 的部分和你从 PHPinfo 页面的输出吗?

于 2012-05-01T21:54:29.783 回答
0

仍然不确定为什么我上面使用的代码在托管站点上不起作用,但我找到了一种解决方法。如果我register_shutdown_function在实时站点上使用 PHP 调用,则数据库会正确更新并删除文件。

这是关机功能代码:

<?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);
}

?>
于 2012-05-01T17:02:26.077 回答