現在の位置: ホーム> 最新記事一覧> zip_read()とzip_entry_read()が一緒に使用すると、常に問題があるのはなぜですか?調査の問題を共有します

zip_read()とzip_entry_read()が一緒に使用すると、常に問題があるのはなぜですか?調査の問題を共有します

M66 2025-06-28

1. zip_read()およびzip_entry_read()の基本的な用途

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ドキュメントによって与えられる典型的な使用法です。多くのシナリオではうまく機能しますが、もう少し複雑であるか、コンテンツの読み取りが特定のサイズを超えている限り、問題が発生します。


2。よくある質問

  1. コンテンツを読み取ることができませんzip_entry_read()は空の文字列を返します。

  2. 一部のファイルは、読み取りの途中で中断されます:部分的なコンテンツのみを読み取ることができます。

  3. エラーまたはスタックを報告する:圧縮されたパッケージによっては、PHPの実行が停止します。

  4. 読み取り順序は混乱しています。複数のエントリの内容は一緒にインターリーブされます。

これらの問題には共通点が1つあります。Ziparchiveなどの他のライブラリに切り替える限り、問題は通常消えます。これは、問題がZIPファイル自体ではなく、 ZIP_*関数の使用または実装メカニズムにある可能性が高いことを示しています。


3。問題の根本原因の分析

1。ZIP_READ()はSTATEFULです

ZIP_READ()は、基本的に、呼び出されるたびにZIPの読み取りポインターを内部的に維持するイテレーターです。読み取りプロセス中に次のZIP_READ()を呼び出すと(たとえば、エントリの読み取りが終了する前に)、前のエントリの読み取りステータスが破壊されます。

2。zip_entry_read()は、1回限りのストリーム読み取りです

zip_entry_read()は、すべてのデータが一度に読み取られることを保証するものではありません。特に固定長(1024など)を渡す場合、空の文字列が返されるまで読み取る必要があります。そうしないと、コンテンツが失われます。

3。zip_entry_read()およびzip_read()は互いに干渉します

これは、この記事の中核でもあります。ZIP_ENTRY_READ ()は、基本的にZIP_READ()によって現在維持されているエントリ状態に依存します。 zip_entry_read()を呼び出すときにzip_read()を再度呼び出すと、前者の動作が中断されます。


4.アイデアと提案を調査します

?アイデア1:zip_read()を呼び出す前にzip_entry_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);
}

?アイデア2:zipが破損しているか、特別なコードがあるかを確認します

一部のzipファイルは、非標準ツールによって圧縮される場合があり、不規則な構造が含まれている場合があります。 Ziparchiveクラスを使用して、 ISReadable()メソッドと協力して、最初に整合性を確認することをお勧めします。

 $zip = new ZipArchive();
if ($zip->open('example.zip') === TRUE) {
    // 検証ロジック
    $zip->close();
}

?アイデア3:zip_*シリーズ関数の代わりにziparchiveの使用を検討してください

ZIP_OPEN()などの機能は簡潔で使いやすいですが、 Ziparchiveクラスはより強力で安定しており、複雑なZIPファイルに適していますが、早期に実験的(または推奨されない)とマークされていました。


5。別の例:Ziparchive実装

$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()読み取り中断の問題もありません。また、生産環境での使用により適しています。


6。結論

zip_read()zip_entry_read()が一緒に使用すると頻繁に発生する理由は、内部ポインター状態に強い依存しているためです。順序の処理やリズムを読むことに注意しないと、論理的な障害が発生しやすくなります。 ZIP操作の安定性要件が高いプロジェクトを、この基礎となる機能のセットではなく、 Ziparchiveを使用することを優先することをお勧めします。

ZIP_*関数ファミリを使用する必要がある場合は、常に読み取り順序が厳密であることを確認し、各エントリの内容をそのまま読み取り、エントリを閉じることなく次のラウンドの読書に入らないようにしてください。

参照文書: https://www.php.net/manual/zh/ref.zip.php