[PHP]zip_entry_compressionmethodとは?非推奨のZIP圧縮方式取得関数とZipArchiveへの移行を徹底解説

PHP

はじめに

これまでの記事で、非推奨の手続き型ZIP関数群から zip_close()、zip_entry_close()、zip_entry_compressedsize() を解説してきました。今回取り上げる zip_entry_compressionmethod() も同じ非推奨の関数群に属し、ZIPアーカイブ内の各エントリがどの圧縮アルゴリズムで圧縮されているかを文字列として取得するための関数です。

ZIPフォーマットは、実は単一の圧縮方式ではなく、deflate(最も一般的)、store(無圧縮)など、エントリごとに異なる圧縮方式を許容する仕様になっています。zip_entry_compressionmethod() は、この圧縮方式を確認するための関数です。これまでの記事と同様、この関数もPHP 7.2.0以降で非推奨とされており、現在は ZipArchive クラスの利用が推奨されています。本記事では、この関数の役割と、ZipArchive を使った現代的な代替実装を詳しく解説します。


関数概要

項目内容
関数名zip_entry_compressionmethod()
所属拡張Zip拡張(手続き型インターフェース)
シグネチャzip_entry_compressionmethod(resource $zip_entry): string
引数$zip_entry — zip_read() などで取得したエントリのリソース
戻り値圧縮方式を表す文字列(例: "deflate", "stored")
対応バージョンPHP 4.1.0以降。PHP 7.2.0以降は非推奨
代表的な戻り値"stored"(無圧縮), "deflated", "unknown" など
推奨される代替ZipArchive::statIndex() / statName() の 'comp_method' フィールド

圧縮方式ごとの違い(イメージ図)

  ZIPアーカイブ内の各エントリ
              │
   ┌──────────┼──────────────┐
   ▼          ▼              ▼
  "stored"     "deflated"     その他の方式
  (無圧縮)     (最も一般的)     (bzip2など、環境による)
   │          │              │
   ▼          ▼              ▼
  圧縮前=圧縮後  圧縮前>圧縮後   ライブラリの対応状況に依存
  サイズが同じ   サイズが縮小
              │
              ▼
    zip_entry_compressionmethod()
    ★この記事の対象(手続き型・非推奨)
              │
    ZipArchive::statIndex()['comp_method']
    (現在推奨される代替、数値の定数で返る)

ポイントは、zip_entry_compressionmethod() が文字列で圧縮方式を返すのに対し、ZipArchive 側の代替である comp_method フィールドは整数の定数(ZipArchive::CM_STORE, ZipArchive::CM_DEFLATE など)で返す、という表現形式の違いがある点です。移行の際はこの型の違いに注意が必要です。


実践サンプル7選

例1:非推奨の古い関数を使った基本的な使い方(参考・非推奨)

<?php

class LegacyCompressionMethodReader
{
    /**
     * 注意: PHP 7.2.0以降、この一連の関数は非推奨です
     * 新規開発ではZipArchiveの使用を強く推奨します
     */
    public function getMethods(string $zipPath): array
    {
        $methods = [];
        $zip = zip_open($zipPath);

        if (is_resource($zip)) {
            while ($entry = zip_read($zip)) {
                $name = zip_entry_name($entry);
                $methods[$name] = zip_entry_compressionmethod($entry);
            }
            zip_close($zip);
        }

        return $methods;
    }
}

$reader = new LegacyCompressionMethodReader();
print_r($reader->getMethods('/tmp/sample.zip'));

例2:ZipArchiveを使った推奨の代替実装

<?php

class ModernCompressionMethodReader
{
    private const METHOD_NAMES = [
        ZipArchive::CM_STORE   => 'stored',
        ZipArchive::CM_DEFLATE => 'deflated',
        ZipArchive::CM_BZIP2   => 'bzip2',
    ];

    /**
     * ZipArchive::statIndex()の'comp_method'は整数の定数で返るため、
     * 人間が読める文字列に変換するマッピングを用意する
     */
    public function getMethods(string $zipPath): array
    {
        $methods = [];
        $zip = new ZipArchive();

        if ($zip->open($zipPath) === true) {
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $stat = $zip->statIndex($i);
                $methodCode = $stat['comp_method'];
                $methods[$stat['name']] = self::METHOD_NAMES[$methodCode] ?? "unknown({$methodCode})";
            }
            $zip->close();
        }

        return $methods;
    }
}

$reader = new ModernCompressionMethodReader();
print_r($reader->getMethods('/tmp/sample.zip'));

例3:無圧縮(stored)で格納されたエントリを検出するツール

<?php

class UncompressedEntryDetector
{
    /**
     * "stored"(無圧縮)方式のエントリを検出する
     * (既に圧縮済みのファイルなどで意図的に使われることがある)
     */
    public function findUncompressedEntries(string $zipPath): array
    {
        $found = [];
        $zip = new ZipArchive();

        if ($zip->open($zipPath) === true) {
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $stat = $zip->statIndex($i);
                if ($stat['comp_method'] === ZipArchive::CM_STORE) {
                    $found[] = $stat['name'];
                }
            }
            $zip->close();
        }

        return $found;
    }
}

$detector = new UncompressedEntryDetector();
print_r($detector->findUncompressedEntries('/tmp/sample.zip'));

例4:新しいZIPを作成する際に圧縮方式を明示的に指定するクラス

<?php

class CompressionMethodSpecifier
{
    /**
     * ZipArchive::addFile()やsetCompressionName()を使い、
     * エントリごとに圧縮方式を明示的に制御する
     * (古いインターフェースには存在しなかった書き込み機能)
     */
    public function createWithMixedCompression(string $outputPath, array $storeFiles, array $deflateFiles): bool
    {
        $zip = new ZipArchive();
        if ($zip->open($outputPath, ZipArchive::CREATE) !== true) {
            return false;
        }

        foreach ($storeFiles as $localName => $filePath) {
            $zip->addFile($filePath, $localName);
            $zip->setCompressionName($localName, ZipArchive::CM_STORE);
        }

        foreach ($deflateFiles as $localName => $filePath) {
            $zip->addFile($filePath, $localName);
            $zip->setCompressionName($localName, ZipArchive::CM_DEFLATE, 9);
        }

        return $zip->close();
    }
}

例5:アーカイブ内の圧縮方式の統計を集計するツール

<?php

class CompressionMethodStatistics
{
    /**
     * アーカイブ全体で、どの圧縮方式が
     * どれだけの割合で使われているかを集計する
     */
    public function collectStatistics(string $zipPath): array
    {
        $stats = [];
        $zip = new ZipArchive();

        if ($zip->open($zipPath) === true) {
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $stat = $zip->statIndex($i);
                $method = $stat['comp_method'];
                $stats[$method] = ($stats[$method] ?? 0) + 1;
            }
            $zip->close();
        }

        return $stats;
    }
}

$statistics = new CompressionMethodStatistics();
print_r($statistics->collectStatistics('/tmp/sample.zip'));

例6:互換性検証のため、対応していない圧縮方式を検出するバリデーター

<?php

class UnsupportedMethodValidator
{
    private const SUPPORTED_METHODS = [
        ZipArchive::CM_STORE,
        ZipArchive::CM_DEFLATE,
    ];

    /**
     * 特定のシステム(一部の古いZIPリーダーなど)が
     * 対応していない圧縮方式が使われていないかを検証する
     */
    public function validate(string $zipPath): array
    {
        $unsupported = [];
        $zip = new ZipArchive();

        if ($zip->open($zipPath) === true) {
            for ($i = 0; $i < $zip->numFiles; $i++) {
                $stat = $zip->statIndex($i);
                if (!in_array($stat['comp_method'], self::SUPPORTED_METHODS, true)) {
                    $unsupported[] = $stat['name'];
                }
            }
            $zip->close();
        }

        return $unsupported;
    }
}

$validator = new UnsupportedMethodValidator();
print_r($validator->validate('/tmp/sample.zip'));

例7:非推奨関数からZipArchiveへの互換ラッパー

<?php

class CompressionMethodCompatWrapper
{
    private const METHOD_NAMES = [
        ZipArchive::CM_STORE   => 'stored',
        ZipArchive::CM_DEFLATE => 'deflated',
    ];

    /**
     * 古いzip_entry_compressionmethod()と同様に
     * 文字列を返すインターフェースを維持しつつ、
     * 内部実装だけをZipArchiveに切り替える
     */
    public function getMethodName(string $zipPath, string $entryName): ?string
    {
        $zip = new ZipArchive();

        if ($zip->open($zipPath) !== true) {
            return null;
        }

        $stat = $zip->statName($entryName);
        $zip->close();

        if ($stat === false) {
            return null;
        }

        return self::METHOD_NAMES[$stat['comp_method']] ?? 'unknown';
    }
}

$wrapper = new CompressionMethodCompatWrapper();
echo $wrapper->getMethodName('/tmp/sample.zip', 'readme.txt') . PHP_EOL;

関連関数との比較

関数/メソッド役割zip_entry_compressionmethodとの違い
zip_entry_compressionmethod()手続き型インターフェースで圧縮方式を文字列で取得本記事の対象。PHP 7.2.0以降は非推奨
zip_entry_compressedsize()圧縮後のサイズを取得方式ではなく、サイズという別の情報を扱う(前回記事を参照)
ZipArchive::statIndex()['comp_method']圧縮方式を整数の定数で取得戻り値が文字列ではなく整数定数である点が異なる
ZipArchive::setCompressionName()エントリの圧縮方式を書き込み時に指定読み取り専用だった古いインターフェースにはない、書き込み機能
ZipArchive::CM_STORE / CM_DEFLATE圧縮方式を表す定数zip_entry_compressionmethod()が返す文字列に相当する値

よくある落とし穴(注意点)

  1. PHP 7.2.0以降でE_DEPRECATED警告が発生する これまでの記事と同様、この関数を使用すると非推奨警告が発生します。早期の ZipArchive への移行が推奨されます。
  2. 戻り値の型が文字列から整数定数に変わる 古い関数は "stored" や "deflated" のような文字列を返しますが、ZipArchive の comp_method は ZipArchive::CM_STORE(0)のような整数定数を返します。移行時にこの型の違いを見落とすと、文字列比較のロジックが機能しなくなります(例2・例7を参照)。
  3. 読み取り専用であり、圧縮方式の変更ができない 古いインターフェースは圧縮方式を「確認する」ことしかできませんでしたが、ZipArchive::setCompressionName() を使えば、新規作成時に圧縮方式を明示的に「指定する」ことも可能です(例4を参照)。
  4. サポートされる圧縮方式は環境(libzipのバージョン)に依存する bzip2やXZなど、deflate以外の圧縮方式のサポート状況は、サーバーにインストールされているlibzipのバージョンやビルドオプションに依存します。特定の方式のサポートが必要な場合、事前に動作確認をしておくことが重要です(例6を参照)。
  5. 未知の圧縮方式コードへのフォールバック処理を用意する 将来的に新しい圧縮方式が追加された場合や、環境によって未対応の値が返ってきた場合に備え、マッピングテーブルにない値が来た際のフォールバック処理(?? 'unknown'など)を用意しておくと安全です(例2・例7を参照)。

まとめ

観点まとめ
何をする関数かZIPエントリの圧縮方式を文字列(例: “deflated”)で取得する(手続き型インターフェース)
現在の状態PHP 7.2.0以降で非推奨。将来的に削除される可能性がある
推奨される代替ZipArchive::statIndex() / statName() の comp_method フィールド(整数定数)
主な用途圧縮方式の確認、対応していない方式の検証、統計情報の収集
注意点戻り値の型の違い(文字列→整数定数)、読み取り専用から書き込み対応への機能拡張、環境依存のサポート状況

zip_entry_compressionmethod() は、ZIPエントリの圧縮アルゴリズムを確認するための、非推奨の手続き型関数です。ZipArchive への移行では、戻り値の型が文字列から整数定数に変わる点に注意しつつ、setCompressionName() のような新しい書き込み機能も含めて活用していくことをおすすめします。

タイトルとURLをコピーしました