【PHP】PHPでZipを作成しダウンロードするやり方

【PHP】PHPでZipを作成しダウンロードするやり方

PHP

公開: 2017-10-28

更新: 2020-04-29

こんにちは、お読みいただきありがとうございます。
Ken(@gootablog)です。

以前PHPでファイルや画像をZipにしてダウンロードする機能を作ったので、備忘録を兼ねて書いていきたいと思います。

PHPにZipの拡張機能があるか確認

ターミナルなどコマンドラインを使って確認をする場合は

$ php -m

というコマンドを実行するとPHPを動作させる環境に追加されている拡張機能(モジュール)の一覧を確認できます。表示された一覧にzipという記述があれば追加されています。

phpinfo()を使ってページに表示して確認する場合は

echo phpinfo(INFO_MODULES);

と書いてページを表示すると、PHPのモジュール関連だけが表示されます。
zipの部分が以下の記述になっていれば大丈夫です。

Zipの拡張機能を追加する

僕が使っている環境下(MacOS,VPS,AWS)などではPHPをインストールする時に入っていたみたいで試せていないのですが、入っていない場合は下記のリンクを参考にしてみてください。

ZIP インストールの手順
ZIP Archive のインストール

Zipをダウンロードするためサンプルコード

今回はこのスクリプトと同じ階層にfilesというディレクトリを作成し、そのなかにhoge.phpというファイルを設置してそれをZipでダウンロードすることができるようにします。

以下はダウンロードするためのサンプルコード。

//php

//実行時間の制限をかけない
set_time_limit(0);

//パスやファイル名の設定
$zip_name = 'create_zip_'.date('Ymd').'.zip';
$zip_tmp_dir = dirname(__FILE__).'/tmp_zip/';

//ZipArchiveインスタンス作成
$zip_obj = new ZipArchive();


$result = $zip_obj -> open($zip_tmp_dir.$zip_name, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
if(!$result){
    echo 'error code : '.$result;
    exit();
}

//zipにまとめたいファイルのパス・zip内でのパスを配列にまとめる
$files[] = [
    'zip_path' => 'hoge.php',
    'file_path' => dirname(__FILE__).'/files/hoge.php'
];

foreach ($files as $file)
{
    //ファイルを追加する場合
    $zip_obj -> addFile($file['file_path'], $file['zip_path']);
}

//何かしらの文字列を追加する場合
$zip_obj -> addFromString('test.txt', 'test');

$zip_obj -> close();

//ダウンロード
header('Content-Type: application/force-download;');
header('Content-Length: '.filesize($zip_tmp_path.$zip_name));
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_tmp_path.$zip_name);

//サーバー内のzipを削除
unlink($zip_tmp_dir.$zip_name);

解説

//実行時間の制限をかけない
set_time_limit(0);

パラメータに0を渡すと、実行時間に制限をかけないように設定できます。
Zipにするファイルが多いと処理に時間がかかることがあるので必要なら設定をします。
デフォルトの設定だと30秒になっているので、ほとんどの場合は設定しなくても大丈夫かと。

$result = $zip_obj -> open($zip_tmp_dir.$zip_name, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
if(!$result){
    echo 'error code : '.$result;
    exit();
}

open(zipを作成するパス, オプション)とすると、指定したバスにZipが作成されて読みこみ・書きこみができる状態になります。

僕が設定しているオプションでは指定したパスにZipが無かったら作成をして、ある場合はそれを上書きして書き込むということを設定しています。

オープンに成功した場合はTrueが返ってくるので、if文で分岐をしています。

 //ファイルを追加する場合
 $zip_obj -> addFile($file['file_path'], $file['zip_path']);

Zipにファイルを追加します。

ファイルに追加する情報はあらかじめ配列でまとめておいて、それをforeachで回してZipに追加するようにしています。
1つ目のパラメータにはZipでのパスを設定しています。2つ目には実際に参照するファイルのパスを書いています。

サンプルコードの状態だと、Zipを解凍したフォルダの中にhoge.phpというファイルが入っています。

もし、フォルダの中にファイルを置きたい場合は、Zipに追加するファイルのパスをdirname/hoge.phpとすると、解凍時にdirnameというフォルダの中にhoge.phpというファイルが入るようになります。

//何かしらの文字列を追加する場合
$zip_obj -> addFromString('file_path', 'text');

何かしらのテキストをファイルに出力して追加したい場合は、addFromString()を使います。1つ目のパラメータにはこれまでと同じようにZipでのパスを指定します。2つ目には文字列を書きます。

こうすることで、指定した文字列がファイルとしてZipに追加されます。

$zip_obj -> close();

colse()とすることでオープンされていたアーカイブを閉じて、変更内容を保存します。

//ダウンロード
header('Content-Type: application/force-download;');
header('Content-Length: '.filesize($zip_tmp_path.$zip_name));
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_tmp_path.$zip_name);

Zipをダウンロードします。
やり方は通常のファイルをダウンロードするやり方と同じです。

通常のファイルのダウンロードはコチラ
【PHP】PHPでファイルをダウンロードする

//サーバー内のzipを削除
unlink($zip_tmp_dir.$zip_name);

作成したZipを削除します。Zipを自動生成しているのでこちらのコードを書いています。

Zipにするファイルが同じ場合で1度だけZipを作成して、以後それをダウンロードしたいという場合は書かなくても大丈夫です。

これでファイルや画像のデータをまとめてZipにしてダウンロードすることができます。めっちゃ便利!

PHPでファイルや画像をZipにしてダウンロードするコード(コメントなし)

コメント無しのバージョンも書いておくので、よかったら使ってみてください。

//php

set_time_limit(0);

$zip_name = 'create_zip_'.date('Ymd').'.zip';
$zip_tmp_dir = dirname(__FILE__).'/tmp_zip/';

$zip_obj = new ZipArchive();

$result = $zip_obj -> open($zip_tmp_dir.$zip_name, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
if(!$result){
    echo 'error code : '.$result;
    exit();
}

$files[] = [
    'zip_path' => 'hoge.php',
    'file_path' => dirname(__FILE__).'/files/hoge.php'
];

foreach ($files as $file){
    $zip_obj -> addFile($file['file_path'], $file['zip_path']);
}

$zip_obj -> addFromString('test.txt', 'test');

$zip_obj -> close();

header('Content-Type: application/force-download;');
header('Content-Length: '.filesize($zip_tmp_path.$zip_name));
header('Content-Disposition: attachment; filename="'.$zip_name.'"');
readfile($zip_tmp_path.$zip_name);

unlink($zip_tmp_dir.$zip_name);