1

嗨,

我有一个带有多个复选框的表单,它允许用户在提示下载 zip 文件之前选择他们想要的小册子。zip 存档下载功能正常工作。但我意识到下载会话将在不下载整个文件(比如 8MB)的情况下终止,并且下载的 zip 文件将损坏。

参考下面的代码,并不能解决问题。任何人都可以建议我需要查看哪些设置,或者我错过了任何功能?

if($send) {     
    // Make sure program execution doesn't time out
    // Set maximum script execution time in seconds (0 means no limit)
    set_time_limit(0);

    $post = $_POST;     
    $file_folder = "pdf/";  // folder to load files
    $zip = new ZipArchive();    // Load zip library 
    $zip_name = "File-".time().".zip";          // Zip name
    if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){       // Opening zip file to load files
        $error .=  "* Sorry ZIP creation failed at this time<br/>";
    }
    foreach($post['brochure'] as $file){                
        $zip->addFile($file_folder.$file);          // Adding files into zip
    }
    $zip->close();
    if(file_exists($zip_name)){
        // set headers push to download the zip
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: public");
        header('Content-type: application/zip');
        header("Content-Transfer-Encoding: Binary");
        header('Content-Disposition: attachment; filename="'.$zip_name.'"');
        header("Content-Length: ".filesize($zip_name)); 
        readfile($zip_name);
        // remove zip file is exists in temp path
        unlink($zip_name);

        $fp = @fopen($zip_name, "rb");
        if ($fp) {
         while(!feof($fp)) {
             print(fread($fp, 1024*8));
             flush(); // this is essential for large downloads
             if (connection_status()!=0) {
                 @fclose($file);
                 die();
             }
         }
         @fclose($file);
        }
    }
4

3 回答 3

1

而不是制作“readfile()”,您是否尝试过这种解决方案?

if(file_exists($zip_name)){
    header("Pragma: public");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    header("Cache-Control: public");
    header('Content-type: application/zip');
    header("Content-Transfer-Encoding: Binary");
    header('Content-Disposition: attachment; filename="'.$zip_name.'"');
    header("Content-Length: ".filesize($zip_name)); 

    echo file_get_contents($file);
    exit
}

对我来说,它更简单,而且很多时候对我来说都很好。

在此之后,我看到的问题是你做了:

unlink($zip_name);
$fp = @fopen($zip_name, "rb");
if ($fp) {
    ...
}

这部分代码不应该继续,因为您在打开文件之前取消了链接!

于 2012-07-18T07:58:04.740 回答
0

设法用下面的代码解决我的问题。基本上我不应该在调用 fopen 之前取消链接文件。

if($send) {
    // Make sure program execution doesn't time out
    // Set maximum script execution time in seconds (0 means no limit)
    set_time_limit(0);

    $post = $_POST;     
    $file_folder = "pdf/";  // folder to load files
    $zip = new ZipArchive();    // Load zip library 
    $zip_name = "File-".time().".zip";          // Zip name
    if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE){       // Opening zip file to load files
        $error .=  "* Sorry ZIP creation failed at this time<br/>";
    }
    foreach($post['brochure'] as $file){                
        $zip->addFile($file_folder.$file);          // Adding files into zip
    }
    $zip->close();
    if(file_exists($zip_name)){

        // set headers push to download the zip
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: public");
        header('Content-type: application/zip');
        header("Content-Transfer-Encoding: Binary");
        header('Content-Disposition: attachment; filename="'.$zip_name.'"');
        header("Content-Length: ".filesize($zip_name)); 

        //readfile($zip_name);
        // remove zip file is exists in temp path
        //unlink($zip_name);

        $fp = @fopen($zip_name, "rb");
        if ($fp) {
         while(!feof($fp)) {
             echo fread($fp, 8192);
             flush(); // this is essential for large downloads
             if (connection_status()!=0) {
                 @fclose($zip_name);
                 die();
             }
         }
         @fclose($zip_name);
        }
        unlink($zip_name);
    }
}
于 2012-07-19T03:42:38.203 回答
0

首先,你的if ($fp) {...}代码块永远不应该被执行,因为你之前已经完成了unlink($zip_name);。所以这个块是没有用的。

次要的,我建议你更换

readfile($zip_name);

ob_clean();
flush();
readfile($zip_name);

这将防止意外的边框效果。

最后,如果您仍然有损坏的存档(我相信),那么我认为这是因为在下载刷新之前、期间或之后发生了一些 PHP 错误(请注意,您的 PHP 代码似乎没有在下载,所以代码可能会继续,之后可能会发生一些错误)。如果发生了这样的 PHP 错误或 PHP 通知,则 PHP 错误消息已随流式输出。这很容易检查:使用文本编辑器打开损坏的存档以查看二进制内容,然后 PHP 错误消息应该在存档二进制内容的最开始或最底部显示清晰易读。无需以 HEXA 模式打开存档。

于 2012-07-18T08:10:45.513 回答