1. 導入
Webシステム開発において、アップロードされたファイルを一括でダウンロードさせたり、ログファイルをアーカイブして保存したりする要件は頻繁に発生します。PHPには標準で「ZipArchive」クラスが用意されており、これを利用することで外部ライブラリに依存せず、サーバーサイドで柔軟に圧縮・解凍処理を実装できます。本記事では、実務で安全かつ効率的にファイルアーカイブを扱う方法を解説します。
2. 基礎知識
「PHP Archive」と聞くと、かつてのFlash連携などを想起する方もいるかもしれませんが、現在のPHP開発におけるアーカイブ処理の主流は、標準拡張モジュールの「Zip」を利用したZIPファイルの操作です。
ZipArchiveクラスは、ZIPファイルの作成、既存アーカイブへの追加、ファイル内部の抽出などをオブジェクト指向で行うためのインターフェースを提供します。これを使うことで、ディレクトリ内のファイルを一括でZip化し、ユーザーにダウンロードさせる処理などが容易に実現可能です。
3. 実装/解決策
実務での実装において重要なのは、ファイルパスの制御と例外処理です。特にユーザーの入力値をもとにファイル操作を行う場合、パス・トラバーサル攻撃(../などを利用した不正なディレクトリへのアクセス)を防ぐためのバリデーションが必須となります。
以下の手順で実装を行います。
1. ZipArchiveインスタンスの生成。
2. openメソッドでアーカイブファイルを開く(作成)。
3. addFileメソッドで圧縮対象を追加。
4. closeメソッドで変更を確定・保存。
4. サンプルプログラム
以下に、指定したディレクトリ内のファイルをZIP化し、保存する実用的なサンプルコードを示します。
/
function createZipArchive($sourceDir, $zipFilePath) {
$zip = new ZipArchive();
// ZIPファイルを新規作成(既に存在する場合は上書き)
if ($zip->open($zipFilePath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
throw new Exception(“ZIPファイルを作成できませんでした: ” . $zipFilePath);
}
// ディレクトリ内のファイルを取得
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($sourceDir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($files as $file) {
// セキュリティ考慮:パスを正規化し、カレントディレクトリ外へのアクセスを制限する処理をここに追加してください
$filePath = $file->getRealPath();
if ($file->isDir()) {
// ディレクトリ構造を維持して追加
$zip->addEmptyDir(str_replace($sourceDir . ‘/’, ”, $filePath . ‘/’));
} else {
// ファイルをZIPに追加
$zip->addFile($filePath, str_replace($sourceDir . ‘/’, ”, $filePath));
}
}
// 処理を完了しファイルを閉じる
$zip->close();
}
try {
createZipArchive(‘./uploads’, ‘./backup/archive_’ . date(‘Ymd’) . ‘.zip’);
echo “アーカイブ作成が完了しました。”;
} catch (Exception $e) {
echo “エラー: ” . $e->getMessage();
}
?>
5. 応用・注意点
実務で扱う際に特に注意すべき点は以下の3点です。
・実行時間の制限(max_execution_time)
ファイル数が多い場合、アーカイブ処理に時間がかかりPHPのタイムアウトが発生することがあります。大量のファイルを扱う場合は、バックグラウンドジョブ(キュー)で処理することを検討してください。
・メモリ使用量
RecursiveIteratorIteratorを使用することでメモリ消費を抑えていますが、巨大なファイルを一度に処理する場合はサーバーリソースを監視してください。
・バリデーション
アップロード機能と組み合わせる場合、ファイル名に特殊文字やパス操作文字列が含まれていないか、必ずホワイトリスト形式でチェックしてください。また、公開ディレクトリ以下にバックアップファイルを生成しないよう、ドキュメントルート外の階層に保存するのがセオリーです。