全体構造

全体構造

質問が4つあります:

  1. PHP を使用して zip ファイル全体を抽出せずに、zip ファイル全体をスキャンしてその内部を移動することは可能ですか?
  2. 時間効率は良いでしょうか? たとえば、たくさんの小さなファイル(特に過去のたくさんの画像)を含む約 50 GB の zip ファイルがあり、PHP を使用してファイル エクスプローラーを作成したいと考えています。
  3. これを再帰的に実行できますか? つまり、大きな zip の中に多くの zip がある場合、それらを解析できますか?
  4. zip を解析できる場合、通常のファイル ブラウザーと同じように内部のファイルを開くことができるということですか?

答え1

おそらく。簡単なGoogle検索でこれZip アーカイブが完全にサポートされているようです。

答え2

すべてに賛成です。少なくとも「zip ファイル全体をスキャンする」実際にファイル全体をスキャンすることを意味するわけではありません。ファイルが小さければ問題ありませんが、ファイルが大きい場合は問題になります。

簡単に言うと、ZIP ファイルは、ファイル全体を読み込まなくても、ファイルのリスト、更新、削除、追加ができるように作成されています。また、元々 ZIP は、複数のディスクにまたがるディスクを保存するためによく使用されていたことにも注意してください。つまり、ディスク #1 から始まり、ディスク #44 で終わる zip ファイルを持つことができます。

ディスク#29 のファイル 342 を抽出するためにディスク#1 からディスク#28 までが必要ないという事実は、ファイルが 1 つのディスク上にある場合にも当てはまりますが、概念的には理解しやすいかもしれません。ファイル#342 を抽出するために、ファイル#1 からファイル#341 まで読み取ることはありません。

それはさておき、簡単に言うと、ZIP アーカイブは中央ディレクトリで終わります。このディレクトリには、ZIP アーカイブの現在の状態に関する情報が保持されており、これが使用されるものです。


全体構造

zip アーカイブの全体的な構造は通常、次のようになります (簡略化):

Local File Header 1
      File Data   1
      Descriptor  1 (optional) 
Local File Header 2
      File Data   2
      Descriptor  2 (optional)
Local File Header N
      File Data   N
      Descriptor  N (optional)

Central Directory
   Details File 1
   Details File 2
   Details File N
   End Of Central Directory

しかしZIPアーカイブ"許可する"非アーカイブ データの場合、エントリの削除と追加 (データの削除が必須ではない場合)。

ここではAllowはかなり柔軟に使用されています

したがって、アーカイブは次のようになります。

Local File Header 1
      File Data   1
Local File Header 2
      File Data   2
Non Archive Data    << not part of the archive, but part of the file.
Local File Header 3
      File Data   3
      Descriptor  3
Non Archive Data    << not part of the archive, but part of the file.
Central Directory   << old central directory
   Details File 1
   Details File 2
   End Of Central Directory

Local File Header 4
      File Data   4

Central Directory
   Details File 1
   Details File 3
   Details File 4
   End Of Central Directory

ここでは、一部のレコード間にデータが追加され、ファイル 2 は削除されたがデータは削除されず、ファイル 4 が追加され、古いものは削除されずに新しい中央ディレクトリが書き込まれるというシナリオがあります。

実際に、既存のファイルに zip アーカイブを追加しても、そのまま使用できます。

foo.zip
[GIF IMAGE]
[ZIP FILE RECORD]
[LETTER TO MOM]
[ZIP FILE RECORD]
[CENTRAL DIRECTORY]

このファイルはひどい混乱状態だと言う人もいるかもしれませんが、ZIP アーカイブとしてはまだ読み取り可能です。仕様上有効ではないと主張して無視することもできますが、それはまた別の話です。

要点は、

適切な ZIP リーダーは、最後の中央ディレクトリを使用します。このディレクトリには、アーカイブの現在の状態に関する情報が常に保持されます。ファイル名、時間、日付、圧縮方法、ディスクの開始、ディスクの終了、ファイル数、各ファイルの開始と終了、各ファイルのチェックサムなどの情報が提供されます。

ZIP アーカイブは、CD に各ファイルの開始位置と終了位置が記されている巨大なデータの塊として考えることができます。


一般的に

もちろん、ほとんどの zip アーカイブはこれよりもずっとクリーンですが、これは少しだけコンテキストを説明するためだけです。

簡単に言うと、アーカイブ内のファイルの概要を取得するには、CD を読み込むだけです。これにより、たとえば次のリストを表示できます。

file1 date size_compressed size_uncompressed
file2 date size_compressed size_uncompressed
file3 date size_compressed size_uncompressed
file4 date size_compressed size_uncompressed

ローカルファイルヘッダーは、破損したファイルを回復する場合やCDが紛失した場合などに便利ですが、欠落している場合もあります。通常はファイルデータのサイズを保持しますが、常に保持されるわけではありません。保持されていない場合は、通常

Local File Header
  ...
  size_compressed: 0
  size_uncompressed: 0
  ...
File Data
Descriptor
   size_compressed: 3214
   size_uncompressed: 6128

そのため、ファイルをバイト 0 から読み取る場合、データの開始位置と終了位置を推測して読み取らなければならないという問題が発生します。

その理由として、ZIP はデータ ストリームをアーカイブできるという点が挙げられます。したがって、書き込む前にファイルのサイズやチェックサムを知ることはできず、結果としてヘッダーにこの情報を保持することはできません。また、ファイルは複数のディスクにまたがる可能性があることにも留意してください。ただし、サイズは常に CD に追加する必要があります。


ファイルの開始位置と終了位置を読み取ることができるため、ファイルを厳選することも簡単です。CD で、ファイルがオフセット 632156 で開始し、952144 で終了するとしたら、それらのバイトを読み取り、圧縮されている場合はそれに応じて解凍します。

ネストされたファイル、アーカイブ内のアーカイブ、アーカイブ内のアーカイブなどがある場合、各アーカイブを検索して、それぞれの CD を解析する必要があります。

サイドノート:簡単もちろんここでは相対的です。

中央ディレクトリレコードの終了

アーカイブが複数のディスクにまたがることができるように、CDも同様に可能です。中央ディレクトリレコードの終了CD がどのディスクから始まり、どのディスクから終わるかに関する情報を保持します。最近では通常同じディスクですが、これは重要な注意点であり、仕様からフォーマットを確認すると理解しやすくなります。

もちろん、これには他にも多くのことがあります。すべては、サポートしたい内容によって異なります。たとえば、データを暗号化できるかどうかなどです。

全文を読むにはAPPNOTE.TXT

ZIP アーカイブの構築方法の基本を理解しておくと、PHP Zip などのライブラリを使用するときに何ができて何ができないかがわかりやすくなります。


PHP ジップ

まだ使ったことはありませんが、見たところ必要な機能はすべて備わっているようです。推測要求されるまでファイル データは読み込まれません。たとえば、次の例 2 をご覧ください。php.net/manual/ja/zip.examples.php より

大きなアーカイブでテストして時間を計ります。CD のみを読み取る場合は、巨大なアーカイブでも比較的高速になるはずです。


一度、趣味で ZIP パーサーを書いたことがありますが、それはまた別の話です(笑)。

関連情報