PHP ZipArchive поврежден в Windows

Я использую класс ZipArchive PHP для создания zip-файла, содержащего фотографии, а затем отправляю его в браузер для загрузки. Вот мой код:

/**
 * 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;

}

этот код очень хорошо работает со всеми браузерами, кроме IE. В IE файл загружается правильно, но zip-архив пуст. При попытке извлечь файлы, Windows сообщает, что zip-архив поврежден. У кого-нибудь была эта проблема раньше?

редактировать обновление: после предложения от @profitphp, Я изменил свои заголовки на это:

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

кроме того, вот скриншот ошибки в Windows после открытия с Firefox:

alt text

эта ошибка возникает как в IE, так и в Firefox В Windows. Он отлично работает в Mac. Кроме того, в Windows размер файла кажется правильным:

alt text

правка #2 этот вопрос sovled. См. мой ответ ниже.

13 ответов


у меня была такая же проблема, и мое решение было похоже на правильный ответ в этой теме. Когда вы помещаете файл в архив, у вас не может быть абсолютных файлов (файлов, начинающихся с косой черты), иначе он по какой-то причине не откроется в Windows.

Так что он работал не потому, что он (Джесси Банч, выбранный ответ на момент написания этой статьи) удалил содержащуюся папку, а потому, что он удалил начальную косую черту.

я исправил проблему путем изменения

$zip->addFile($file, $file); // $file is something like /path/to/file.png

to

// we make file relative by removing beginning slash so it will open in Windows
$zip->addFile($file, ltrim($file, '/'));

и тогда он смог открыть в Windows!

наверное, по той же причине pclzip (ответ Plahcinski) не работает. Бьюсь об заклад, он автоматически снимает начальную косую черту.

Я бы не понял этого без конкретный комментарий на PHP ZipArchive::addFile на странице документации.


недавно у меня была аналогичная проблема, как вы описали. Я обнаружил, что ZipArchive в лучшем случае нестабилен.

Я решил свои проблемы с этой простой библиотекой

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 = папка, которую я хотел zip $destination = расположение zip-файла

Я провел 2 дня, глядя на ZipArchive, а затем решил все проблемы с PCLZip за 5 минут.

надеюсь, это поможет у вас и у кого-либо еще есть эта проблема (так как это близко к верхнему результату google по этой проблеме).


все эти предложения могут помочь вам, но в моем случае мне нужно написать ob_clean(); перед первым заголовком("); потому что некоторый файл, который я включаю перед печатью некоторых символов, которые сломали zip-файл в 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;

хорошо, после долгих раздоров я понял проблему. Проблема возникает из следующей строки кода:

$objZip->addFile($filename,sprintf('/press_photos/%s-%s', $objPhoto->getEntryID(), basename($filename)));

по какой причине /press_photos/ часть этого пути для локального (внутреннего) имени файла внутри zip-архива заставляла Windows думать, что zip-файл поврежден. После изменения строки, чтобы выглядеть так, как показано ниже, Windows правильно открыла zip-файлы. Фу.

$objZip->addFile($filename,sprintf('%s-%s', $objPhoto->getEntryID(), basename($filename)));

использовать специальные символы, такие как подчеркивание, вызывает проблемы, потому что одному необходимо закодированных IBM850 entrynames. См. комментарии в онлайн-руководстве по PHP:http://www.php.net/manual/en/function.ziparchive-addfile.php#95725 .


У меня были проблемы с этим раньше. Попробуйте снять заголовок типа содержимого. вот код, который я придумал для него, который работал в IE и FF. Обратите внимание на прокомментированные строки, были те же проблемы с различными комбо тех, кто находится на.

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

В дополнение к тому, что другие предлагали, важно обратить внимание на ваши имена файлов и каталогов поскольку Windows не обязательно нравится путь и имена файлов Linux. Иногда он также ускользает от них по-разному, когда застегивается. Примеров множество, но самое главное

  • *Dot-файлов (. и..), файлы с различиями только в случае (имя.txt и имя.txt),
  • абсолютные пути к файлам (/tmp / file.формат txt.*)
  • некоторые другие персонажи которые разрешены в именах файлов в Windows могут вызвать проблемы, когда Проводник Windows используется для открытия файлов. В моем случае": "персонаж был нарушителем сделки, но потребовалось много работы, чтобы узнать это.

поэтому, прежде чем вы возобновите использование, используя много параметров через exec('zip ...'), Я предлагаю следовать простой процедуре:

  1. найдите папку или файл ваш веб-сайт застегивается.
  2. run:zip -9-r-k zip-модифицированные имена.застежка-молния /path/to/your / folder
  3. обратите внимание на то, что консоль выплевывает. в моем случае': 'в именах файлов были удалены.
  4. переместите zip-файл на компьютер с windows и попытайтесь открыть его.

Если это работает,вам может быть лучше удалить символы, которые были удалены с помощью опции-k из ваших имен файлов / каталогов, попробуйте выполнить обычное сжатие. обратите внимание, что некоторые параметры, такие как-k, имеют побочные эффекты. В этом случае - K противоречит опции-q (для ссылок sym).

также опция-k может сделать ваши имена файлов нечитаемыми. В моем случае мои файлы были названы на основе времени создания (например, 10:55:39.pdf) для облегчения поиска необходимой записи из архивов, но опция-k превратила ее в 105539.pdf, который не легко читается пользователями. Поэтому я изменил имена на 10_55_39.pdf, который открывается в Windows без использования опции-k, но все еще читается.

в дополнение к этому, используя PCLZip сделает вашу жизнь намного проще, так как вы можете добавить целую папку сразу, а также изменить путь к файлам в одной простой строке. В моем случае я удаляю /tmp / directory/ из моих zip-файлов со вторым и третьим параметрами, что позволяет избежать другой проблемы совместимости windows (имея абсолютный путь в zip-файлах):

$v_list = $zip->create( $sourceFolder, PCLZIP_OPT_REMOVE_PATH, $sourceFolder . DIRECTORY_SEPARATOR);
if ($v_list == 0) {
    throw new \Exception($zip->errorInfo(true));
}

У меня была та же проблема. Этот код работал для меня, но я должен был поместить первую строку в свой php-файл! Если я помещал код в середину файла, я не работал. Может быть, некоторые проблемы с кодировкой ?!

// Prepare File
$file = tempnam("tmp", "zip");
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);

// Staff with content
$zip->addFile($filepathOnServer, 'mypic.jpg');

// Close and send to users
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="filename.zip"');
readfile($file);
unlink($file);

            ob_clean(); //very important
            // http headers for zip downloads
            header("Pragma: public");
            header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
            header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
            header("Cache-Control: public");
            header('Content-Type: application/x-download');
            header("Content-Disposition: attachment; filename=\"filename.zip\"");
            header("Content-Length: ".filesize($filepath ));

            @readfile($filepath );
            unlink($filepath);  //very important
            exit;//very important

это работает для меня при попытке вышеуказанных решений.


Я использовал отметку времени в имени zip-файла. На самом деле файловая система windows не поддерживает специальные символы, такие как ":\/*? | "

после удаления ":" из часть времени он работает как шарм


код. При вызове библиотеки с include(/path/to/lib/lib.php); в браузер была выведена пустая строка, в результате чего zip был классифицирован как поврежденный Windows. (Winzip, Total Commander и т. д. не имели с этим проблем). Поэтому убедитесь, что нет импортированная библиотека или, если она есть, в ней нет пробелов или пустых строк....


У меня была эта проблема в течение часа. Попробовав 10 различных решений, я решил его, убедившись, что скрипт существует после вывода ZIP-файла:

            readfile($zip_name);
            unlink($zip_name);
            **exit();**

изменить ваш код:

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

С:

header('Content-Length: '.file_get_contents($strZipFilename));