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));
また、Firefoxで開いた後のWindowsのエラーのスクリーンショットは次のとおりです。
このエラーは、IEとWindows上のFirefoxの両方で発生します。Macでは正常に機能します。また、Windowsでは、ファイルサイズは正しいように見えます。
編集#2この問題は解決されました。以下の私の答えを参照してください。
さて、多くの争いの後、私は問題を理解しました。この問題は、次のコード行に起因します。
$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)));
私はこれと同じ問題を抱えていました、そして私の解決策はこのスレッドの正解に似ていました。ファイルをアーカイブに入れるとき、絶対ファイル(スラッシュで始まるファイル)を持つことはできません。そうしないと、何らかの理由でWindowsで開くことができません。
それで、彼(Jesse Bunch、この記事の執筆時点で選択された回答)が含まれているフォルダーを削除したためではなく、開始スラッシュを削除したために機能しました。
変更して問題を修正しました
$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 =圧縮したいフォルダ$ destination = Zipファイルの場所
私は2日間ZipArchiveを探し、PCLZipのすべての問題を5分で解決しました。
これがあなたとこの問題を抱えている他の人に役立つことを願っています(これは問題のトップグーグル結果に近いので)。
この提案はすべてあなたを助けるかもしれませんが、私の場合はob_clean();を書く必要があります。最初のヘッダーの前( '');私が前に含めたいくつかのファイルは、Windowsで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 。
私は以前にこれに問題がありました。コンテンツタイプヘッダーを削除してみてください。これが私が思いついたコードで、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のファイルパスと名前を好まないからです。また、圧縮時に異なる方法でエスケープすることもあります。例はたくさんありますが、最も重要なのは
したがって、exec( 'Zip ...')を介して多くのパラメーターの使用を再開する前に、簡単な手順に従うことをお勧めします。
これが機能する場合は、ファイル/ディレクトリ名から-kオプションで削除された文字を削除して、通常どおりに圧縮することをお勧めします。 -kなどの一部のパラメーターには副作用があることに注意してください。この場合、-kは-qオプション(シンボリックリンクの場合)と矛盾します。
また、-kオプションを使用すると、ファイル名が読み取れなくなる場合があります。私の場合、ファイルはアーカイブから必要なレコードを簡単に見つけることができるように作成時間(10:55:39.pdfなど)に基づいて名前が付けられましたが、-kオプションを使用すると105539.pdfになり、ユーザーが簡単に読み取ることができなくなりました。そのため、名前を10_55_39.pdfに変更しました。これは、-kオプションを使用せずにWindowsで開きますが、引き続き読み取り可能です。
これに加えて、PCLZipを使用すると、フォルダー全体を一度に追加したり、ファイルのパスを1行で変更したりできるため、作業が大幅に楽になります。私の場合、2番目と3番目のパラメーターを使用してZipファイルから/ tmp/directory /を削除します。これにより、別のWindows互換性の問題(Zipファイルに絶対パスがある)が回避されます。
$v_list = $Zip->create( $sourceFolder, PCLZIP_OPT_REMOVE_PATH, $sourceFolder . DIRECTORY_SEPARATOR);
if ($v_list == 0) {
throw new \Exception($Zip->errorInfo(true));
}
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
上記の解決策を試している間、これは私のために働きました。
私も同じ問題を抱えていました。このコードは私にとってはうまくいきましたが、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);
これをすべて試しても頭を叩いてもうまくいかなかった方のために、このように問題を修正することができました。
$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
を使用してそれを実行しました。
私はこの問題を1時間抱えています。 10種類の解決策を試した後、Zipファイルを出力した後にスクリプトが存在することを確認して解決しました。
readfile($Zip_name);
unlink($Zip_name);
**exit();**
他の誰かが数時間レンガの壁にぶつけて、私のように苦しんでいる場合に備えて。私は同じ問題を抱えていましたが、PHPにいくつかのライブラリをロードし、そのうちの1つに?>コードの後に空の行があることに気付くまで、どのソリューションも役に立ちませんでした。 include(/path/to/lib/lib.php);
が空の行を持つライブラリがブラウザに出力されたため、ZipはWindowsによって破損していると分類されました(Winzip、Total Commanderなどには問題はありませんでした)。したがって、インポートされたものがないことを確認してください。ライブラリまたは存在する場合は、スペースや空の行はありません。
Zipファイル名にタイムスタンプを使用していました。実際、Windowsファイルシステムは":\/*?<> |"のような特殊文字をサポートしていません。
時間部分から":"を削除すると、チャームのように機能します