PHP ZipArchive Corrupt in Windows

2020-03-08 07:54发布

I am using PHP's ZipArchive class to create a zip file containing photos and then serve it up to the browser for download. Here is my code:

/**
 * Grabs the order, packages the files, and serves them up for download.
 *
 * @param string $intEntryID 
 * @return void
 * @author Jesse Bunch
 */
public static function download_order_by_entry_id($intUniqueID) {

    $objCustomer = PhotoCustomer::get_customer_by_unique_id($intUniqueID);

    if ($objCustomer):

        if (!class_exists('ZipArchive')):
            trigger_error('ZipArchive Class does not exist', E_USER_ERROR);
        endif;

        $objZip = new ZipArchive();
        $strZipFilename = sprintf('%s/application/tmp/%s-%s.zip', $_SERVER['DOCUMENT_ROOT'], $objCustomer->getEntryID(), time());

        if ($objZip->open($strZipFilename, ZIPARCHIVE::CREATE) !== TRUE):

            trigger_error('Unable to create zip archive', E_USER_ERROR);

        endif;          

        foreach($objCustomer->arrPhotosRequested as $objPhoto):

            $filename = PhotoCart::replace_ee_file_dir_in_string($objPhoto->strHighRes);
            $objZip->addFile($filename,sprintf('/press_photos/%s-%s', $objPhoto->getEntryID(), basename($filename)));

        endforeach;

        $objZip->close();

        header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($strZipFilename)).' GMT',  TRUE, 200);
        header('Cache-Control: no-cache', TRUE);
        header('Pragma: Public', TRUE);
        header('Expires: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT', TRUE);
        header('Content-Length: '.filesize($strZipFilename), TRUE);
        header('Content-disposition: attachment; filename=press_photos.zip', TRUE);

        header('Content-Type: application/octet-stream', TRUE);

        ob_start();
        readfile($strZipFilename);
        ob_end_flush();
        exit;

    else:

        trigger_error('Invalid Customer', E_USER_ERROR);

    endif;

}

This code works really well with all browsers but IE. In IE, the file downloads correctly, but the zip archive is empty. When trying to extract the files, Windows tells me that the zip archive is corrupt. Has anyone had this issue before?

Edit Update: After suggestion from @profitphp, I changed my headers to this:

header("Cache-Control: public");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
//header("Content-Description: File Transfer");
//header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"pressphotos.zip\"");
//header("Content-Transfer-Encoding: binary");
header("Content-length: " . filesize($strZipFilename));

Also, here is a screenshot of the error in Windows after opening with Firefox:

alt text

This error occurs in both IE and Firefox on Windows. It works fine in Mac. Also, in Windows, the filesize appears to be correct:

alt text

Edit #2 This issue is sovled. See my answer below.

14条回答
Ridiculous、
2楼-- · 2020-03-08 08:27

I recently had a similar issue as you described. I found ZipArchive to be unstable at best.

I solved my problems with this simple library

http://www.phpconcept.net/pclzip

include_once('libs/pclzip.lib.php');

...

function zip($source, $destination){
$zipfile = new PclZip($destination);
$v_list = $zipfile->create($source, '', $source); }

$source = folder i wanted to zip $destination = zip file location

I spent 2 days looking to ZipArchive and then solved all problems with PCLZip in 5 minutes.

Hope this helps you and anyone else having this issue (as this is near the top google result on the issue).

查看更多
做个烂人
3楼-- · 2020-03-08 08:29

All of this suggestions may help you, but in my case I need to write an ob_clean(); before first header(''); because some file that I include before print some characters that broken zip file on windows.

$zip=new ZipArchive();
$zip->open($filename, ZIPARCHIVE::CREATE);
$zip->addFile($file_to_attach,$real_file_name_to_attach);
$zip->close();

ob_clean();
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Content-Type: application/x-download');
header('Content-Disposition: attachment; filename="file.zip"');
readfile($filename);
exit;
查看更多
冷血范
4楼-- · 2020-03-08 08:33

The use of special characters, such as underscore, causes problems because ZipArchive requires IBM850 encoded entrynames. See comments in the online PHP manual: http://www.php.net/manual/en/function.ziparchive-addfile.php#95725 .

查看更多
ら.Afraid
5楼-- · 2020-03-08 08:33

I've had issues with this before. Try taking off the content type header. here is the code i came up with for it that worked in IE and FF. Notice the commented lines, was having the same issues with different combos of those being on.

header("Cache-Control: public");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
//header("Content-Description: File Transfer");
//header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"adwords-csv.zip\"");
//header("Content-Transfer-Encoding: binary");
header("Content-length: " . filesize($filename)); 
查看更多
我想做一个坏孩纸
6楼-- · 2020-03-08 08:34

I was using time stamp in zip file name. Actually windows file system doesn't support special characters like " : \ / * ? < > | "

After removing ":" from the time part it works like a charm

查看更多
Rolldiameter
7楼-- · 2020-03-08 08:38

Change your code:

 header('Content-Length: '.filesize($strZipFilename), TRUE);

With:

header('Content-Length: '.file_get_contents($strZipFilename));
查看更多
登录 后发表回答