PHP ZipArchive Corrupt в Windows - PullRequest
       5

PHP ZipArchive Corrupt в Windows

19 голосов
/ 07 января 2011

Я использую PHP-класс ZipArchive для создания 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 Эта проблема устранена.Смотрите мой ответ ниже.

Ответы [ 13 ]

23 голосов
/ 05 июля 2012

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

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

Я исправил проблему, изменив

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

на

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

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

Это, вероятно, та же самая причина, по которой работает pclzip (ответ Плахчинского).Бьюсь об заклад, он автоматически удаляет начальный слеш.

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

14 голосов
/ 19 августа 2011

У меня недавно была похожая проблема, как вы описали.Я обнаружил, что 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 = папка, в которую я хотел заархивировать $ destination = местоположение файла zip

Я потратил 2 дня на поиск ZipArchive, а затем решил все проблемы с PCLZip за 5 минут.у вас и у всех, у кого возникла эта проблема (так как она находится рядом с топ-результатом Google по данной проблеме).

8 голосов
/ 07 августа 2014

Все эти предложения могут помочь вам, но в моем случае мне нужно написать ob_clean ();перед первым заголовком ('');потому что некоторые файлы, которые я включаю перед печатью некоторых символов, которые разбивают zip-файл на windows

6 голосов
/ 07 января 2011

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

$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)));
5 голосов
/ 30 мая 2011

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

3 голосов
/ 07 января 2011

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

2 голосов
/ 19 июня 2015

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

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

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

  1. Найдите папку или файл, на котором находится ваш веб-сайт.
  2. запустите: zip -9 -r -k zip-modified-names.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));
}
1 голос
/ 02 мая 2018
            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

Это сработало для меня, когда я пробовал описанные выше решения.

1 голос
/ 13 апреля 2012

У меня была такая же проблема. Этот код работал для меня, но я должен был поставить первую строку в моем 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);
0 голосов
/ 02 июля 2015

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

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