Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

У меня была такая же проблема, и мое решение было похоже на правильный ответ на этот поток. Когда вы кладете файл в архив, вы не можете иметь абсолютные файлы (файлы, начинающиеся с косой черты), иначе они не будут открываться в 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 (ответ Plahcinski). Держу пари, он автоматически отбрасывает начальную косую черту.

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

Ответ 3

Недавно у меня была аналогичная проблема, как вы описали. Я обнаружил, что 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 по проблеме).

Ответ 4

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

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

Ответ 5

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

Ответ 6

У меня были проблемы с этим раньше. Попробуйте снять заголовок типа содержимого. вот код, который я разработал для него, который работал в 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)); 

Ответ 7

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

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

Итак, прежде чем переходить к использованию с использованием большого количества параметров с помощью exec ('zip...'), я предлагаю простую процедуру:

  • Найдите папку или файл, который ваш сайт застегнет.
  • run: zip -9 -r -k zip-modified-names.zip/path/to/your/folder
  • обратите внимание на то, что выжимает консоль. В моем случае ":" в именах файлов были удалены.
  • Переместите zip файл на компьютер Windows и попытайтесь открыть его.

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

Также опция -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));
}

Ответ 8

У меня была та же проблема. Этот код работал у меня, но я НАШЕЛ В ПЕРВОЙ ЛИНИИ в моем 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);

Ответ 9

            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

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

Ответ 10

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

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

Ответ 11

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

Ответ 12

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

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

Ответ 13

Для тех из вас, кто все еще стучит головой после попытки всего этого, и это все еще не работает, я смог решить мою проблему следующим образом.

$zipname = "download.zip";
$zip = new ZipArchive;
$zip->open($zipname, ZipArchive::CREATE);
foreach ($files as $file) {
    # download file
    $download_file = file_get_contents($file); <- important

    #add it to the zip
    $zip->addFromString(basename($file), $download_file); <- important  
}
$zip->close();

header('Content-Type: application/zip');
//header('Content-disposition: attachment; filename='.$zipname);
header("Content-Disposition: attachment; filename=\"$zipname\"");
header('Content-Length: ' . filesize($zipname));
readfile($zipname);
unlink($zipname);
exit;

Моя проблема заключалась в том, что мои пути к файлам входили в виде строк. Даже при том, что я попытался (string)$path это все еще не работало. Для меня это было использование file_get_contents файла, а затем встроенная функция addFromString которая сделала это для меня.

Ответ 14

Измените свой код:

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

С

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