PHPのZipArchiveとは何か、使い方や基本操作について

採用はこちら

PHPのZipArchiveは、ZIP形式の圧縮ファイルをPHPから作成・読み込み・編集・展開するためのクラスです。

複数のファイルを1つのZIPファイルにまとめたり、既存のZIPファイルからファイルを取り出したり、ZIP内部のファイル名を変更したりできます。

Webアプリケーションでは、複数のPDFや画像をまとめてダウンロードさせる場合や、バックアップファイルをZIP形式で保存する場合などに利用されます。

ZipArchiveを利用すれば、シェルからzipunzipといった外部コマンドを直接実行しなくても、PHPのZIP拡張機能を通じてZIPファイルを操作できます。

目次

ZipArchiveでできること

ZIPファイルを新しく作成できる

ZipArchiveでは、新しいZIPファイルを作成できます。

複数のファイルをまとめたり、PHPで生成したCSVやテキストをZIPに格納したりすることが可能です。

既存のZIPファイルを編集できる

すでに存在しているZIPファイルを開き、ファイルの追加・削除・名前変更などを行えます。

そのため、ZIPファイルを単に作るだけではなく、既存アーカイブを更新する用途にも利用できます。

ZIPファイルを展開できる

ZIPファイルの中身を指定したディレクトリへ展開できます。

すべてのファイルを展開するだけでなく、特定のファイルだけを指定して展開することも可能です。

ZIP内のファイルを直接読み込める

ZIP全体を展開しなくても、指定したファイルだけを文字列やストリームとして読み込めます。

CSVやJSONなどの内容をZIPから直接処理したい場合に便利です。

ZipArchiveを利用するための条件

PHPのZIP拡張機能が必要

ZipArchiveはPHPのZIP拡張機能によって提供されています。

そのため、PHPがインストールされていても、ZIP拡張機能が無効になっている環境では利用できません。

利用できるかどうかは、次のように確認できます。

<?php

if (class_exists('ZipArchive')) {
    echo 'ZipArchiveを利用できます。';
} else {
    echo 'ZipArchiveを利用できません。';
}

ZipArchiveクラスが存在していれば、基本的にはZIP操作を行える環境です。

コマンドラインから確認する方法

PHPで有効になっている拡張機能は、次のコマンドでも確認できます。

php -m

表示された一覧に、

zip

が含まれていれば、ZIP拡張機能が読み込まれています。

次のように確認することもできます。

php -r "var_dump(class_exists('ZipArchive'));"

利用可能な場合は、

bool(true)

と表示されます。

なお、ZIP拡張機能のインストール方法や有効化方法は、OSやPHPの導入方法、PHPのバージョンなどによって異なります。

ZipArchiveの基本的な使い方

基本的な処理の流れ

ZipArchiveを使うときの基本的な流れは、次のとおりです。

$zip = new ZipArchive();

$zip->open(...);

$zip->addFile(...);

$zip->close();

大きく分けると、以下の順番で処理します。

  1. ZipArchiveオブジェクトを作成する
  2. open()でZIPファイルを開く
  3. ファイルの追加や削除などの処理を行う
  4. close()でZIPファイルを閉じる

特に書き込み処理を行う場合は、最後にclose()を明示的に呼び出して処理結果を確認することが重要です。

ZIPファイルを新しく作成する方法

ZipArchive::CREATEを使用する

新しいZIPファイルを作成するときは、open()の第2引数にZipArchive::CREATEを指定します。

<?php

$zip = new ZipArchive();

$result = $zip->open(
    'example.zip',
    ZipArchive::CREATE
);

if ($result === true) {
    $zip->close();

    echo 'ZIPファイルを作成しました。';
} else {
    echo 'ZIPファイルを作成できませんでした。';
}

ZipArchive::CREATEを指定すると、対象のZIPファイルが存在しない場合に新しく作成できます。

既存のZIPファイルが存在する場合は、そのアーカイブを開いて編集します。

open()の戻り値には注意が必要

=== trueで判定する

ZipArchive::open()は、成功時にはtrueを返します。

一方、失敗時にはエラーを表す整数値が返される場合があります。

そのため、次のような書き方は避けたほうが安全です。

if ($zip->open($path)) {
    // 処理
}

PHPでは整数値が真と評価されることがあるため、失敗時のエラーコードを成功と誤判定する可能性があります。

次のように厳密比較を行うのがおすすめです。

$result = $zip->open($path);

if ($result === true) {
    // 成功
}

実務では、この違いを理解しておくことが重要です。

ZIPファイルにファイルを追加する方法

addFile()を使用する

既存のファイルをZIPへ追加するときは、addFile()を使用します。

<?php

$zip = new ZipArchive();

if ($zip->open(
    'example.zip',
    ZipArchive::CREATE
) === true) {

    $zip->addFile('sample.txt');

    $zip->close();
}

このコードを実行すると、sample.txtexample.zipへ追加されます。

ZIP内部のファイル名を指定する

addFile()の第2引数を指定すると、ZIP内部で使用するファイル名を変更できます。

$zip->addFile(
    'sample.txt',
    'document.txt'
);

元のファイル名がsample.txtでも、ZIPの内部ではdocument.txtとして保存されます。

たとえば、実際のディレクトリ構造をZIP内部にそのまま表示したくない場合にも便利です。

$zip->addFile(
    'data/report_2026.csv',
    'report.csv'
);

ZIP内部のディレクトリ区切りには、基本的に/を使用すると互換性を確保しやすくなります。

複数のファイルをZIPに追加する方法

foreachで繰り返し追加する

複数のファイルをZIPにまとめる場合は、addFile()を繰り返して使用します。

<?php

$files = [
    'document1.pdf',
    'document2.pdf',
    'document3.pdf',
];

$zip = new ZipArchive();

if ($zip->open(
    'documents.zip',
    ZipArchive::CREATE
) === true) {

    foreach ($files as $file) {

        if (is_file($file)) {
            $zip->addFile(
                $file,
                basename($file)
            );
        }
    }

    $zip->close();
}

ファイル一覧を配列として管理しておけば、ZIPにまとめる対象を追加・削除しやすくなります。

文字列をZIP内のファイルとして追加する方法

addFromString()を使用する

PHPで生成した文字列をそのままZIP内のファイルとして保存したい場合は、addFromString()を利用します。

<?php

$zip = new ZipArchive();

if ($zip->open(
    'example.zip',
    ZipArchive::CREATE
) === true) {

    $zip->addFromString(
        'hello.txt',
        'Hello World!'
    );

    $zip->close();
}

この場合、事前にhello.txtを作成する必要はありません。

ZIPの内部にhello.txtが生成され、その内容としてHello World!が保存されます。

CSVを動的に作成して追加する

たとえば、PHPでCSVを生成してZIPに追加する場合は次のようにします。

$csv = "id,name\n";
$csv .= "1,Taro\n";
$csv .= "2,Hanako\n";

$zip->addFromString(
    'users.csv',
    $csv
);

CSVやJSON、XMLなどを動的に生成してまとめてダウンロードさせたい場合に便利です。

ただし、非常に大きな文字列をaddFromString()へ渡すと、PHP側のメモリ使用量が増える点には注意が必要です。

ZIP内にディレクトリを作成する方法

addEmptyDir()を使用する

ZIPファイルの中に空のディレクトリを追加するときは、addEmptyDir()を使用します。

$zip->addEmptyDir('images');

ZIP内部には次のようなディレクトリが作成されます。

images/

さらに、次のようにファイルを追加できます。

$zip->addFile(
    'photo.jpg',
    'images/photo.jpg'
);

ZIP内部は次のような構造になります。

images/
└── photo.jpg

ディレクトリ全体をZIP化する方法

RecursiveDirectoryIteratorを使用する

ディレクトリ内のファイルやサブディレクトリをまとめてZIP化する場合は、PHPのRecursiveDirectoryIteratorなどと組み合わせる方法があります。

<?php

$sourceDir = __DIR__ . '/documents';
$zipPath = __DIR__ . '/documents.zip';

$zip = new ZipArchive();

if ($zip->open(
    $zipPath,
    ZipArchive::CREATE | ZipArchive::OVERWRITE
) !== true) {
    exit('ZIPファイルを作成できませんでした。');
}

$iterator = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator(
        $sourceDir,
        FilesystemIterator::SKIP_DOTS
    ),
    RecursiveIteratorIterator::SELF_FIRST
);

foreach ($iterator as $file) {

    $filePath = $file->getRealPath();

    $relativePath = substr(
        $filePath,
        strlen($sourceDir) + 1
    );

    $relativePath = str_replace(
        '\\',
        '/',
        $relativePath
    );

    if ($file->isDir()) {

        $zip->addEmptyDir($relativePath);

    } elseif ($file->isFile()) {

        $zip->addFile(
            $filePath,
            $relativePath
        );
    }
}

$zip->close();

この方法なら、サブディレクトリを含めた構造を維持しながらZIPファイルを作成できます。

なお、複数ファイルを追加する方法としては、addGlob()addPattern()といったメソッドもあります。

用途や対象ファイルの構成に応じて使い分けるとよいでしょう。

ZIPファイルを展開する方法

extractTo()を使用する

ZIPファイルを解凍するときは、extractTo()を利用します。

<?php

$zip = new ZipArchive();

if ($zip->open('example.zip') === true) {

    $zip->extractTo('output');

    $zip->close();
}

たとえば、ZIP内部に、

sample.txt
image.jpg

が含まれている場合、outputディレクトリへ展開されます。

特定のファイルだけ展開する

ZIP全体ではなく、特定のファイルだけを展開することも可能です。

$zip->extractTo(
    'output',
    'sample.txt'
);

複数のファイルを指定する場合は配列を利用できます。

$zip->extractTo(
    'output',
    [
        'sample.txt',
        'image.jpg'
    ]
);

必要なファイルだけを取り出したい場合に便利です。

ZIP内のファイル一覧を取得する方法

numFilesとgetNameIndex()を使用する

ZIP内部のファイル数は、numFilesプロパティから取得できます。

getNameIndex()と組み合わせれば、すべてのエントリ名を確認できます。

<?php

$zip = new ZipArchive();

if ($zip->open('example.zip') === true) {

    for ($i = 0; $i < $zip->numFiles; $i++) {

        echo $zip->getNameIndex($i);
        echo '<br>';
    }

    $zip->close();
}

たとえば、次のようなファイル名を取得できます。

sample.txt
images/photo.jpg
data.csv

PHPのバージョンによっては、count()を利用してエントリ数を取得することも可能です。

ZIP内のファイル情報を取得する方法

statIndex()を使用する

インデックスを指定してZIP内のファイル情報を取得する場合は、statIndex()を利用します。

$info = $zip->statIndex(0);

print_r($info);

ファイル名やファイルサイズなどの情報を確認できます。

statName()を使用する

ファイル名から情報を取得したい場合は、statName()を利用します。

$info = $zip->statName(
    'sample.txt'
);

ZIP内部の特定ファイルについて詳しく確認するときに便利です。

ZIP内のファイルを削除する方法

deleteName()を使用する

ファイル名を指定して削除する場合は、deleteName()を利用します。

<?php

$zip = new ZipArchive();

if ($zip->open('example.zip') === true) {

    $zip->deleteName(
        'sample.txt'
    );

    $zip->close();
}

deleteIndex()を使用する

インデックスを指定して削除することもできます。

$zip->deleteIndex(0);

既存のZIPファイルを編集する場合に利用できます。

ZIP内のファイル名を変更する方法

renameName()を使用する

ファイル名を指定して名前を変更する場合は、renameName()を利用します。

$zip->renameName(
    'old.txt',
    'new.txt'
);

renameIndex()を使用する

インデックスを使う場合は、renameIndex()を利用できます。

$zip->renameIndex(
    0,
    'new.txt'
);

ZIP内のファイルを直接読み込む方法

getFromName()を使用する

ZIP全体を展開せずに特定ファイルの内容だけ取得したい場合は、getFromName()を利用します。

<?php

$zip = new ZipArchive();

if ($zip->open('example.zip') === true) {

    $content = $zip->getFromName(
        'sample.txt'
    );

    echo $content;

    $zip->close();
}

ZIP内にあるCSVやJSON、テキストファイルなどを直接読み込みたい場合に便利です。

ZIP内のファイルをストリームとして読み込む方法

getStream()を使用する

ZIP内部のファイルをストリームとして読み込みたい場合は、getStream()を利用します。

<?php

$zip = new ZipArchive();

if ($zip->open('example.zip') === true) {

    $stream = $zip->getStream(
        'data.csv'
    );

    if ($stream !== false) {

        while (($line = fgets($stream)) !== false) {
            echo htmlspecialchars($line);
        }

        fclose($stream);
    }

    $zip->close();
}

大きなファイルを一度に文字列として取得するのではなく、順番に読み込みたい場合などに役立ちます。

ZipArchive::OVERWRITEとは

既存ZIPを新しい内容で作り直す

既存のZIPファイルを新しい内容で作り直したい場合は、ZipArchive::OVERWRITEを利用できます。

一般的には、ZipArchive::CREATEと組み合わせます。

$zip->open(
    'example.zip',
    ZipArchive::CREATE | ZipArchive::OVERWRITE
);

毎回新しいZIPを生成したい処理などで利用されます。

ZipArchive::EXCLとは

既存ファイルが存在する場合に失敗させる

既存のZIPファイルを誤って上書きしたくない場合は、ZipArchive::EXCLを利用できます。

$zip->open(
    'example.zip',
    ZipArchive::CREATE | ZipArchive::EXCL
);

対象のアーカイブがすでに存在する場合に、新規作成を失敗させたいケースで役立ちます。

ZIPファイルをブラウザからダウンロードさせる方法

HTTPヘッダーを設定する

Webアプリケーションでは、作成したZIPファイルをそのままユーザーへダウンロードさせることがあります。

<?php

$zipPath = __DIR__ . '/download.zip';

$zip = new ZipArchive();

if ($zip->open(
    $zipPath,
    ZipArchive::CREATE | ZipArchive::OVERWRITE
) !== true) {
    exit('ZIPファイルを作成できませんでした。');
}

$zip->addFile(
    __DIR__ . '/sample.pdf',
    'sample.pdf'
);

if (!$zip->close()) {
    exit('ZIPファイルの保存に失敗しました。');
}

header('Content-Type: application/zip');

header(
    'Content-Disposition: attachment; filename="download.zip"'
);

header(
    'Content-Length: ' . filesize($zipPath)
);

readfile($zipPath);

一時的に作成したZIPファイルであれば、送信後に削除できます。

readfile($zipPath);

unlink($zipPath);

ただし、header()を実行する前にHTMLや文字列を出力してしまうと、正常にダウンロードできない場合があるため注意が必要です。

ZipArchiveのエラーを確認する方法

open()のエラーコードを確認する

open()が失敗した場合は、戻り値を確認すると原因を調査しやすくなります。

<?php

$zip = new ZipArchive();

$result = $zip->open(
    'example.zip'
);

if ($result !== true) {

    echo 'ZIPファイルを開けませんでした。';
    echo 'エラーコード: ' . $result;
}

ZipArchiveには、ZIPファイルが存在しない場合やZIP形式として不正な場合など、さまざまなエラーを表す定数が用意されています。

エラー処理を実装しておくことで、ZIP操作に失敗したときの原因を把握しやすくなります。

addFile()を使用するときの注意点

ファイルの存在を事前に確認する

存在しないファイルを追加しようとすると、意図したZIPを作成できない可能性があります。

そのため、実運用ではis_file()などで確認してから追加すると安全です。

$file = 'sample.pdf';

if (is_file($file)) {

    $zip->addFile(
        $file,
        basename($file)
    );
}

addFile()の戻り値も確認すると、より確実です。

if (!$zip->addFile(
    $file,
    basename($file)
)) {
    throw new RuntimeException(
        'ZIPへの追加に失敗しました。'
    );
}

元ファイルをすぐに削除しない

addFile()で追加したファイルは、環境によってはZipArchiveを閉じるまでロックされることがあります。

そのため、一時ファイルをZIPに追加した直後に削除するのは避けたほうが安全です。

次のような順番で処理します。

$zip->addFile(
    $tmpFile,
    'sample.csv'
);

$zip->close();

unlink($tmpFile);

ZIPを閉じてから元ファイルを削除するようにすると、トラブルを防ぎやすくなります。

close()は明示的に呼び出す

保存結果を確認できる

ZipArchiveオブジェクトが破棄される際にもアーカイブは閉じられますが、実務ではclose()を明示的に呼び出すことが重要です。

if (!$zip->close()) {
    throw new RuntimeException(
        'ZIPファイルの保存に失敗しました。'
    );
}

特に書き込み処理では、ファイル追加時には問題が発生せず、最後にZIPを保存するときにエラーになる可能性もあります。

そのため、close()の戻り値まで確認するとより安全です。

ユーザーがアップロードしたZIPを扱う際の注意点

無条件で展開しない

ユーザーがアップロードしたZIPファイルを扱う場合は、特にセキュリティへ注意する必要があります。

単純に、

$zip->extractTo(
    '/var/www/html/uploads/'
);

のようにWeb公開ディレクトリへ展開する設計は避けるのが安全です。

ファイル名やパスを確認する

ZIP内部には、予想していないファイル名やパスが含まれている可能性があります。

そのため、

  • 不審なパスが含まれていないか
  • 許可していない拡張子が含まれていないか
  • 実行可能なファイルが含まれていないか

などを確認することが重要です。

ファイル数や容量を制限する

非常に多くのファイルや巨大なデータが格納されたZIPを無制限に展開すると、サーバーのディスク容量や処理時間を圧迫する可能性があります。

そのため、

  • ZIP内部のファイル数
  • 圧縮ファイルのサイズ
  • 展開後の合計サイズ
  • 1ファイルあたりのサイズ

などに上限を設定することが望まれます。

大容量のZIPを扱う際の注意点

メモリやディスク容量を確認する

大量のファイルをZIP化したり、大きなZIPを展開したりすると、サーバーのリソースを多く消費する可能性があります。

特に注意したいのは次の項目です。

  • PHPのメモリ制限
  • PHPの最大実行時間
  • ディスクの空き容量
  • 一時ディレクトリの容量
  • Webサーバーのタイムアウト
  • PHP-FPMのタイムアウト

大容量ファイルを扱う場合は、ZIP操作だけではなくサーバー設定も確認する必要があります。

addFromString()の使いすぎに注意する

addFromString()へ非常に大きな文字列を渡すと、そのデータをPHPのメモリ上で保持する必要があります。

既存の大容量ファイルをZIP化したい場合は、状況に応じてaddFile()などを利用するほうが適していることがあります。

ZipArchiveの主なメソッド

よく使用するメソッド一覧

ZipArchiveで特によく使われる基本的なメソッドは次のとおりです。

メソッド主な用途
open()ZIPを開く・作成する
close()ZIPを閉じて変更を保存する
addFile()ファイルを追加する
addFromString()文字列をファイルとして追加する
addEmptyDir()ディレクトリを追加する
extractTo()ZIPを展開する
getFromName()名前を指定してファイル内容を取得する
getNameIndex()インデックスからファイル名を取得する
getStream()ZIP内のファイルをストリームで取得する
statName()名前を指定してファイル情報を取得する
statIndex()インデックスからファイル情報を取得する
deleteName()名前を指定してファイルを削除する
deleteIndex()インデックスを指定して削除する
renameName()ファイル名を変更する
renameIndex()インデックスを指定して名前を変更する

ZipArchiveを使った基本サンプル

複数ファイルをZIPにまとめる

最後に、複数のファイルを1つのZIPにまとめる基本的なサンプルを紹介します。

<?php

$zipPath = __DIR__ . '/example.zip';

$files = [
    __DIR__ . '/documents/file1.txt',
    __DIR__ . '/documents/file2.txt',
    __DIR__ . '/documents/file3.txt',
];

$zip = new ZipArchive();

$result = $zip->open(
    $zipPath,
    ZipArchive::CREATE | ZipArchive::OVERWRITE
);

if ($result !== true) {
    throw new RuntimeException(
        'ZIPファイルを開けませんでした。'
    );
}

foreach ($files as $file) {

    if (!is_file($file)) {
        continue;
    }

    if (!$zip->addFile(
        $file,
        basename($file)
    )) {

        $zip->close();

        throw new RuntimeException(
            'ZIPへの追加に失敗しました。'
        );
    }
}

if (!$zip->close()) {
    throw new RuntimeException(
        'ZIPファイルの保存に失敗しました。'
    );
}

echo 'ZIPファイルを作成しました。';

基本的には、

ZipArchiveオブジェクトを作成
↓
open()でZIPを開く
↓
addFile()などでファイルを追加
↓
close()でZIPを保存する

という流れを理解しておけば、多くのZIP処理に応用できます。

PHPのZipArchiveを活用しよう

PHPのZipArchiveは、ZIPファイルの作成・読み込み・編集・展開などをPHPから行える便利なクラスです。

addFile()を利用すれば既存ファイルをZIPへ追加でき、addFromString()を使えばPHPで生成した文字列を直接ZIP内部のファイルとして保存できます。

さらに、extractTo()による展開や、deleteName()renameName()などを使った既存ZIPの編集にも対応しています。

基本的な処理は、ZipArchiveオブジェクトを生成し、open()でアーカイブを開き、必要な操作を行ったあとにclose()で保存するという流れです。

一方で、ユーザーがアップロードしたZIPを展開する場合や、大容量ファイルを扱う場合には、セキュリティやサーバーリソースにも注意する必要があります。

ZipArchiveの基本メソッドと注意点を理解しておけば、ファイルの一括ダウンロード、バックアップ、データ出力など、さまざまなPHPアプリケーションで活用できます。

以上、PHPのZipArchiveとは何か、使い方や基本操作についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次