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 MYH:i:s', filemtime($strZipFilename)).' GMT', TRUE, 200); header('Cache-Control: no-cache', TRUE); header('Pragma: Public', TRUE); header('Expires: ' . gmdate('D, d MYH: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 Эта проблема опрокинута. См. Мой ответ ниже.

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. Найдите папку или файл, который ваш сайт застегнет.
  2. run: zip -9 -r -k zip-modified-names.zip / path / to / your / folder
  3. обратите внимание на то, что выжимает консоль. В моем случае «:» в именах файлов были удалены.
  4. Переместите 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)); } 

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

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

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