PHPでは、一般的なプロセスは次のとおりです。
$zip = zip_open("example.zip");
if (is_resource($zip)) {
while ($entry = zip_read($zip)) {
echo "Name: " . zip_entry_name($entry) . "\n";
if (zip_entry_open($zip, $entry, "r")) {
$contents = zip_entry_read($entry, 1024);
echo "Content: " . $contents . "\n";
zip_entry_close($entry);
}
}
zip_close($zip);
}
上記のコードは、公式のPHPドキュメントによって与えられる典型的な使用法です。多くのシナリオではうまく機能しますが、もう少し複雑であるか、コンテンツの読み取りが特定のサイズを超えている限り、問題が発生します。
コンテンツを読み取ることができません: zip_entry_read()は空の文字列を返します。
一部のファイルは、読み取りの途中で中断されます:部分的なコンテンツのみを読み取ることができます。
エラーまたはスタックを報告する:圧縮されたパッケージによっては、PHPの実行が停止します。
読み取り順序は混乱しています。複数のエントリの内容は一緒にインターリーブされます。
これらの問題には共通点が1つあります。Ziparchiveなどの他のライブラリに切り替える限り、問題は通常消えます。これは、問題がZIPファイル自体ではなく、 ZIP_*関数の使用または実装メカニズムにある可能性が高いことを示しています。
ZIP_READ()は、基本的に、呼び出されるたびにZIPの読み取りポインターを内部的に維持するイテレーターです。読み取りプロセス中に次のZIP_READ()を呼び出すと(たとえば、エントリの読み取りが終了する前に)、前のエントリの読み取りステータスが破壊されます。
zip_entry_read()は、すべてのデータが一度に読み取られることを保証するものではありません。特に固定長(1024など)を渡す場合、空の文字列が返されるまで読み取る必要があります。そうしないと、コンテンツが失われます。
これは、この記事の中核でもあります。ZIP_ENTRY_READ ()は、基本的にZIP_READ()によって現在維持されているエントリ状態に依存します。 zip_entry_read()を呼び出すときにzip_read()を再度呼び出すと、前者の動作が中断されます。
現在のエントリコンテンツが読み取られていない場合は、次のzip_read()を入力しないでください。そうしないと、読み取りポインターが事前に移動され、コンテンツが失われたり不正確なコンテンツが不正確になります。
while ($entry = zip_read($zip)) {
zip_entry_open($zip, $entry, "r");
$content = "";
while ($data = zip_entry_read($entry, 1024)) {
$content .= $data;
}
echo $content;
zip_entry_close($entry);
}
一部のzipファイルは、非標準ツールによって圧縮される場合があり、不規則な構造が含まれている場合があります。 Ziparchiveクラスを使用して、 ISReadable()メソッドと協力して、最初に整合性を確認することをお勧めします。
$zip = new ZipArchive();
if ($zip->open('example.zip') === TRUE) {
// 検証ロジック
$zip->close();
}
ZIP_OPEN()などの機能は簡潔で使いやすいですが、 Ziparchiveクラスはより強力で安定しており、複雑なZIPファイルに適していますが、早期に実験的(または推奨されない)とマークされていました。
$zip = new ZipArchive();
if ($zip->open('example.zip') === TRUE) {
for ($i = 0; $i < $zip->numFiles; $i++) {
$entryName = $zip->getNameIndex($i);
echo "File: " . $entryName . "\n";
$stream = $zip->getStream($entryName);
if ($stream) {
while (!feof($stream)) {
echo fread($stream, 1024);
}
fclose($stream);
}
}
$zip->close();
}
この方法はより効率的であるだけでなく、 ZIP_ENTRY_READ()読み取り中断の問題もありません。また、生産環境での使用により適しています。
zip_read()とzip_entry_read()が一緒に使用すると頻繁に発生する理由は、内部ポインター状態に強い依存しているためです。順序の処理やリズムを読むことに注意しないと、論理的な障害が発生しやすくなります。 ZIP操作の安定性要件が高いプロジェクトを、この基礎となる機能のセットではなく、 Ziparchiveを使用することを優先することをお勧めします。
ZIP_*関数ファミリを使用する必要がある場合は、常に読み取り順序が厳密であることを確認し、各エントリの内容をそのまま読み取り、エントリを閉じることなく次のラウンドの読書に入らないようにしてください。