Я использую 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:
Эта ошибка возникает как в IE, так и в Firefox в Windows. Он отлично работает на Mac. Кроме того, в Windows размер файла выглядит правильно:
Редактировать # 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. Иногда он также ускользает от них при застегивании. Примеры многочисленны, но самое главное
Поэтому, прежде чем переходить к использованию с использованием большого количества параметров с помощью exec ('zip …'), я предлагаю простую процедуру:
Если это работает, вам может быть лучше удалить символы, которые были удалены с помощью опции -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));