【PHP実践|実務向け】PHPのZipArchiveクラスを活用したディレクトリ再帰的圧縮テクニック

導入

Web開発の実務において、ユーザーがアップロードしたファイル群をバックアップしたり、特定のデータセットをまとめてダウンロードさせたりする機能は頻繁に求められます。PHPでZIPファイルを扱う際、標準の ZipArchive クラスは非常に強力ですが、単一ファイルの追加だけでなく「ディレクトリ構造を維持したまま再帰的に圧縮する」実装には、少し工夫が必要です。今回は、実務でも即戦力となるディレクトリ圧縮の仕組みを解説します。

基礎知識

ZipArchive クラスは、PHP 5.2以降で利用可能なZIPファイルを操作するための標準クラスです。
ZIP圧縮において重要なのは「パスの管理」です。サーバー上の絶対パスをそのままZIP内に含めてしまうと、解凍時に予期せぬ階層構造になってしまうことがあります。そのため、RecursiveIteratorIterator と RecursiveDirectoryIterator を組み合わせることで、ディレクトリ構造を効率的に走査し、相対パスを計算しながら追加する手法が一般的です。

実装/解決策

再帰的な圧縮を実現するには、以下の手順を踏みます。
1. RecursiveIteratorIterator でディレクトリを全探索する。
2. 走査中のパスから、圧縮対象のベースディレクトリを除去し、相対パスを算出する。
3. ファイルなら addFile()、ディレクトリなら addEmptyDir() を使用してZIPに追加する。

サンプルプログラム

以下のコードは、指定したディレクトリをZIPファイルとして保存する実用的な関数です。

  • ディレクトリを再帰的に圧縮する関数
  • @param string $sourceDir 圧縮対象のディレクトリパス
  • @param string $outZipPath 出力先のZIPファイルパス
  • /
    function zipDirectory(string $sourceDir, string $outZipPath): bool {
    $zip = new ZipArchive();

    // ZIPファイルを新規作成(既に存在する場合は上書き)
    if ($zip->open($outZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
    return false;
    }

    // ディレクトリのパスを正規化
    $sourceDir = realpath($sourceDir);
    $baseLen = strlen($sourceDir);

    // 再帰的にディレクトリをイテレート
    $files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
    RecursiveIteratorIterator::SELF_FIRST
    );

    foreach ($files as $file) {
    $filePath = $file->getRealPath();
    // ZIP内の相対パスを作成
    $relativePath = substr($filePath, $baseLen + 1);

    if ($file->isDir()) {
    $zip->addEmptyDir($relativePath);
    } else {
    $zip->addFile($filePath, $relativePath);
    }
    }

    return $zip->close();
    }

    // 使用例
    zipDirectory(__DIR__ . ‘/data’, ‘./backup.zip’);
    ?>

    応用・注意点

    1. メモリ制限に注意: 大規模なディレクトリを圧縮する場合、PHPのメモリ制限(memory_limit)に抵触することがあります。その際は、プロセスを分けたり、実行時間を延長する設定を検討してください。
    2. パスの重複と安全性: ユーザー入力をそのままパスとして利用すると、ディレクトリトラバーサル攻撃を受ける危険性があります。必ず realpath() やパスのバリデーションを行い、対象が意図したディレクトリ内にあるか確認してください。
    3. 文字コード: Windows環境などで作成されたZIPファイルを扱う場合、ファイル名のエンコーディング(UTF-8とShift-JISなど)で文字化けが発生することがあります。必要に応じてファイル名を変換する処理を挟むのが定石です。

    このように、ZipArchive を適切に抽象化して関数化しておくことで、プロジェクト全体でのコードの再利用性が高まり、堅牢なバックアップ・ダウンロード機能が構築可能になります。

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