Php下载zip档案大文件大小


Php download zip archive big filesize

Hihi,

我有一个带有多个复选框的表单,它允许用户在被提示下载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);
        }
    }

您尝试过这种解决方案吗?

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) {
    ...
}

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

首先,您的if ($fp) {...}块永远不应该执行,因为您之前刚刚执行过unlink($zip_name);。所以这个块没用。

其次,我建议你更换

readfile($zip_name);

带有

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

这将防止意外的边界影响。

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

设法用下面的代码解决我的问题。基本上,我不应该在调用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);
    }
}