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:
эта ошибка возникает как в IE, так и в Firefox В Windows. Он отлично работает в Mac. Кроме того, в Windows размер файла кажется правильным:
правка #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 ...'), Я предлагаю следовать простой процедуре:
- найдите папку или файл ваш веб-сайт застегивается.
- run:zip -9-r-k zip-модифицированные имена.застежка-молния /path/to/your / folder
- обратите внимание на то, что консоль выплевывает. в моем случае': 'в именах файлов были удалены.
- переместите 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));