23

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でのエラーのスクリーンショットは次のとおりです。

代替テキスト

このエラーは、Windows上のIEとFirefoxの両方で発生します。Macでは問題なく動作します。また、Windowsでは、ファイルサイズは正しいように見えます。

代替テキスト

編集#2この問題は解決されました。以下の私の答えを参照してください。

4

14 に答える 14

28

私はこれと同じ問題を抱えていましたが、私の解決策はこのスレッドの正解に似ていました。ファイルをアーカイブに入れるとき、絶対ファイル (スラッシュで始まるファイル) を持つことはできません。そうしないと、なんらかの理由で Wi​​ndows で開くことができません。

彼(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

于 2012-07-05T18:18:27.497 に答える
14

最近、あなたが説明したのと同様の問題が発生しました。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ファイルの場所

私はZipArchiveを探して2日間を過ごし、その後5分でPCLZipのすべての問題を解決しました。

これがあなたとこの問題を抱えている他の人に役立つことを願っています(これは問題のトップグーグル結果に近いため)。

于 2011-08-19T15:50:42.107 に答える
12

この提案はすべて役立つかもしれませんが、私の場合は、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;
于 2014-08-07T10:33:13.060 に答える
6

わかりました、多くの闘争の後、私は問題を理解しました。この問題は、次のコード行から発生します。

$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)));
于 2011-01-07T14:13:32.867 に答える
5

ZipArchiveにはIBM850でエンコードされたエントリ名が必要なため、アンダースコアなどの特殊文字を使用すると問題が発生します。オンラインPHPマニュアルのコメントを参照してください:http ://www.php.net/manual/en/function.ziparchive-addfile.php#95725 。

于 2011-05-30T17:39:54.470 に答える
3

私は以前にこれに問題がありました。コンテンツ タイプ ヘッダーを外してみてください。これは、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)); 
于 2011-01-06T21:51:20.043 に答える
2

他の人が提案したことに加えて、Windows は必ずしも Linux のファイル パスと名前を好むとは限らないため、ファイルとディレクトリの名前に注意することが重要です。また、圧縮時に別の方法でエスケープすることもあります。例はたくさんありますが、最も重要なのは

  • *ドットファイル (. と ..)、大文字と小文字の違いのみのファイル (name.txt と NAME.txt)、
  • 絶対ファイル パス (/tmp/file.txt)*。
  • Windows のファイル名で許可されているその他の文字は、Windows エクスプローラーを使用してファイルを開くときに問題を引き起こす可能性があります。私の場合、「:」文字が問題を引き起こしましたが、これを見つけるには多くの作業が必要でした。

したがって、exec('zip ...') を介して多くのパラメーターの使用を再開する前に、簡単な手順に従うことをお勧めします。

  1. Web サイトが圧縮されているフォルダーまたはファイルを見つけます。
  2. 実行: zip -9 -r -k zip-modified-names.zip /path/to/your/folder
  3. コンソールが吐き出すものに注意してください。 私の場合、ファイル名の「:」は削除されました。
  4. zip ファイルを Windows マシンに移動し、開いてみます。

これが機能する場合は、-k オプションによって取り除かれた文字をファイル/ディレクトリ名から削除した方がよい場合があります。通常の圧縮を試してください。 -k などの一部のパラメーターには副作用があることに注意してください。 この場合、-k は -q オプション (sym リンクの場合) と矛盾します。

また、-k オプションを使用すると、ファイル名が読めなくなる場合があります。私の場合、アーカイブから必要なレコードを簡単に見つけられるように、作成時間に基づいてファイルに名前を付けました (例: 10:55:39.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));
}
于 2015-06-19T06:00:06.930 に答える
1

私も同じ問題を抱えていました。このコードはうまくいきましたが、php-File の最初の行に入れなければなりませんでした。コードをファイルの途中に置くと、うまくいきませんでした。多分いくつかのエンコーディングの問題?!

// 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);
于 2012-04-13T14:18:14.690 に答える
1

私はこの問題を1時間抱えています。10の異なる解決策を試した後、ZIPファイルを出力した後にスクリプトが存在することを確認して解決しました:

            readfile($zip_name);
            unlink($zip_name);
            **exit();**
于 2015-07-02T16:21:42.787 に答える
0

他の誰かがレンガの壁に数時間ぶつけて、私のように苦しんでいる場合に備えて. PHPにいくつかのライブラリをロードし、そのうちの1つに ?> コードの後に​​空の行があることに気付くまで、同じ問題があり、解決策はどれも役に立ちませんでした。空行でライブラリを呼び出すとinclude(/path/to/lib/lib.php);ブラウザに出力され、Windows によって zip が破損していると分類されていました。(Winzip、Total Commander などには問題はありませんでした)。したがって、インポートされたライブラリがないことを確認するか、存在する場合は、スペースや空行がないことを確認してください....

于 2015-01-24T23:18:39.503 に答える
0

zipファイル名にタイムスタンプを使用していました。実際、Windows ファイル システムは、 " : \ / * ? < > | "などの特殊文字をサポートしていません。

時間部分から「:」を削除すると、魅力のように機能します

于 2014-02-20T13:11:29.880 に答える
-3

コードを変更してください:

 header('Content-Length: '.filesize($strZipFilename), TRUE);

と:

header('Content-Length: '.file_get_contents($strZipFilename));
于 2013-02-25T11:46:45.590 に答える