【Laravel】zip、gzip、bz2で圧縮してダウンロードする方法

こんにちは。フリーランス・コンサルタント&エンジニアの 九保すこひ です。

さてさて、ウェブサイトの構築をしていると特に管理系のページではファイルをアップロードしたり逆にダウンロードする機能というのが必要になってきたりします。

Laravelを使えばアップロード&ダウンロード機能はそれほど難しいわけでもありませんが、それでもダウンロードするファイルを圧縮、または複数のファイルを1つに固めてダウンロードするとなったらどうでしょう。さすがにそこまではLaravelといえども面倒は見てくれないので、これは自分自身で実装する必要があります。

そこで!

今回は、そんな圧縮や展開(昔で言う解凍)する機能をLaravelで実装する方法をお届けします。

ぜひ皆さんのお役に立てると嬉しいです!

開発環境: Laravel 5.8

前提として

gzipbz2は、それぞれ以下のPHPモジュールが有効になっている必要があります。

  • gzip ・・・ zlib
  • bz2 ・・・ bz2

phpinfo()で表示した内容が以下のようになっていれば有効になっています。

私の環境ではすでにインストールされた状態でしたが、もしインストールされていない場合は以下のようにしてコマンドからパッケージを検索してみるといいでしょう。

sudo apt search php | grep bz2

ファイルを圧縮してダウンロードする

zip圧縮してダウンロードする

zipでひとつのファイルにまとめるにはZipArchiveを使います。

$save_path = storage_path('app/test.zip');
$zip = new \ZipArchive();
$zip->open($save_path, \ZipArchive::CREATE);

for($i = 1 ; $i <= 3 ; $i++) {

    $filename = 'test_'. $i .'.txt';    // test_1.txt 〜 test_3.txt
    $file_path = storage_path('app/'. $filename);

    // ファイルを追加
    $zip->addFile($file_path, $filename);

    // 文字列から追加
    $zip->addFromString('additional.txt', '文字列からファイル追加');

}

$zip->close();

return response()->download($save_path);

まず$save_pathですが、これは今からつくるzipファイルの保存場所になります。

そして、ループの中でzipファイルの中身を追加しています。

  • addFile ・・・ ファイルを追加
  • addFromString ・・・ 文字列からファイルを追加

ここで重要なのがaddFile()の第2引数、addFromString()の第一引数の「ローカル名」です。

これは、展開(解凍)した際のパスにあたるもので、例えば、以下のようにするとtextsの中に各ファイルを格納することができます。

$zip->addFile($file_path, 'texts/'. $filename);

実際にtextsをつけてzip化させた場合のファイル構成はこちら。

gzip圧縮してダウンロードする

gzip圧縮の場合は、PharDataを使います。

$tar_path = storage_path('app/test.tar');
$gzip_path = storage_path('app/test.tar.gz');

$pd = new \PharData($tar_path);

for($i = 1 ; $i <= 3 ; $i++) {

    $filename = 'test_'. $i .'.txt';    // test_1.txt 〜 test_3.txt
    $file_path = storage_path('app/'. $filename);

    // ファイルを追加
    $pd->addFile($file_path, $filename);

    // 文字列から追加
    $pd->addFromString('additional.txt', '文字列からファイル追加');

}

$pd->compress(\Phar::GZ);
// @unlink($tar_path);

return response()->download($gzip_path);

基本的には、zip圧縮のZipArchiveと同じですが、ひとつ違うのはgzipファイルを作成する手順が以下のようになる部分です。

  1. tarファイルをつくる
  2. tar.gz(gzip)ファイルをつくる

つまり、結果的にtarファイルとtar.gzファイル2つが作成されるので、不要であれば自分で削除する必要があるということです。コメント化していますがコードの最後の方でunlink()を使っているのはこのためです。

bz2圧縮してダウンロードする

bz2圧縮はgzip圧縮とほぼ同じです。

$tar_path = storage_path('app/test.tar');
$bz2_path = storage_path('app/test.tar.bz2');

$pd = new \PharData($tar_path);

for($i = 1 ; $i <= 3 ; $i++) {

    $filename = 'test_'. $i .'.txt';    // test_1.txt 〜 test_3.txt
    $file_path = storage_path('app/'. $filename);

    // ファイルを追加
    $pd->addFile($file_path, $filename);

    // 文字列から追加
    $pd->addFromString('additional.txt', '文字列からファイル追加');

}

$pd->compress(\Phar::BZ2);
// @unlink($tar_path);

return response()->download($bz2_path);

gzipと違っているのは、保存するパスと以下の圧縮パラメータです。

$pd->compress(\Phar::BZ2);

ちなみに

エラーが発生したら

以下のようなエラーが発生した場合は、「すでに同じ名前のファイルがあるので先に消してね」という意味ですので、先にファイルをunlink()などで削除してから圧縮を実行してください。

phar "******" exists and must be unlinked prior to conversion

ダウンロードしたら元ファイルを削除した場合

開発内容によっては、ダウンロードしたファイルをわざわざサーバーに置いておかなくてもいい場合があると思います。そんな場合以下のようにdeleteFileAfterSend()をつけるだけで自動的に削除してくれます。

return response()->download($save_path)->deleteFileAfterSend();

ダウンロードするファイルの名前を指定する

Laravelのダウンロードでファイル名を指定をするにはdownload()の第2引数に名前を入れるだけでOKです。

return response()->download($bz2_path, 'my.tar.gz');
開発のご依頼お待ちしております
開発のご依頼はこちらから: お問い合わせ
どうぞよろしくお願いいたします! by 九保すこひ

おわりに

ということで、今回はLaravelで圧縮ファイルを作成してダウンロードする方法をご紹介しました。

ダウンロード部分はLaravelのみしか有効ではありませんが、圧縮部分はPHP単体でも、その他のフレームワークでも使えると思いますので、ぜひ参考になると嬉しいです。

ちなみにその昔よくlzh形式とかrar形式のファイルとかってあったと思いますが、最近見なくなってしまいました。(windowsでは普通に使ってるのかな??)

ではでは〜!

「今回は文字の量も圧縮バージョンでした😅」

このエントリーをはてなブックマークに追加       follow us in feedly