PHP скрипт загрузки создает нечитаемый ZIP-файл на Mac

Для справки, я уже прочитал и попробовал ответы в этих и нескольких других потоках:

Создание и обслуживание zip-файлов с помощью php

Открытие загруженного zip-файла создает файл cpgz?

У меня есть zip-файл на моем сервере.

  1. Когда я использую Filezilla для перемещения этого Zip-файла с моего сервера на свой Mac, я могу открыть его в обычном режиме.

  2. Когда я использую этот PHP-код для загрузки Zip-файла на свою Linux-машину, он открывается нормально.

  3. Когда я использую этот PHP-код для загрузки Zip-файла на свой Mac, используя Safari или Firefox, я получаю сообщение об ошибке «Декомпрессионный сбой» или «Структура архива повреждена» или я получаю файл .cpgz – который, я считаю, означает, что компьютер застегивает файл, а не разархивирует его.

Вот код PHP, который я использую для доставки zip-файла.

$zipname = "myfile.zip"; $zippath = "/path/to/" . $zipname; if ($downloadzip = fopen ($zippath, "r")) { $fsize = filesize($zippath); header("Content-type: application/zip"); header("Content-Disposition: attachment; filename=\"".$zipname."\""); header("Content-length: $fsize"); header('Content-Transfer-Encoding: binary'); #header("Cache-control: private"); //use this to open files directly echo fpassthru($downloadzip); // deliver the zip file } fclose ($downloadzip); 

Я нашел несколько заголовков, которые работают. Я действительно не знаю, почему это работает, я просто счастлив, что это работает … Я пробовал много разных вещей, файлов .htaccess, настроек php.ini / zlib.

Вот ответ http://perishablepress.com/http-headers-file-downloads/

 $zipName = 'myfile.zip'; $zipPath = 'mydirectory/' . $zipName; if (file_exists($zipPath)) { 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/octet-stream"); header("Content-Disposition: attachment; filename=\"".$zipName."\""); header("Content-Transfer-Encoding: binary"); header("Content-Length: ".filesize($zipPath)); ob_end_flush(); @readfile($zipPath); } 

Часто проблема связана с дополнительными символами, которые были напечатаны или вышли на страницу, прежде чем вы зачитали файл. Даже пробел приведет к сбою. Чтобы устранить эту проблему, вызовите ob_end_clean(); прежде чем вы прочитаете файл, который очистит выходной буфер и отключит буферизацию.

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

 while (ob_get_level()) { ob_end_clean(); } 

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

Для тех, кто интересуется, я вставил свой сценарий загрузки ниже. Мои zip-файлы теперь загружаются отлично, и пока это отлично работает.

 if (file_exists($zip_file_path)) { 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"); //We can likely use the 'application/zip' type, but the octet-stream 'catch all' works just fine. header("Content-type: application/octet-stream"); header("Content-Disposition: attachment; filename='$zip_file_name'"); header("Content-Transfer-Encoding: binary"); header("Content-Length: ".filesize($zip_file_path)); while (ob_get_level()) { ob_end_clean(); } @readfile($zip_file_path); exit; } 

Вот что работает

 $zipName = 'myfile.zip'; $zipPath = 'mydirectory/' . $zipName; if (file_exists($zipPath)) { 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/octet-stream"); header("Content-Disposition: attachment; filename=\"".$zipName."\""); header("Content-Transfer-Encoding: binary"); header("Content-Length: ".filesize($zipPath)); ob_end_flush(); @readfile($zipPath); } 

Ну, я полагаю, вы знаете, что ваша переменная $ fsize не записывается в этот заголовок, потому что она заключена в кавычки. Вы можете попробовать что-то вроде этого:

 header('Cache-Control: public'); header('Content-Description: File Transfer'); header('Content-Disposition: attachment; filename=\"".$zipname."\"'); header('Content-Type: application/zip');