How To Make ZIP Files From Multiple Directories in Laravel

Laravel zip file

We will use ZipArchive to compress files in a specific directory and return the URL to the zip file with Subdirectories in storage to download via RESTful API.

Sometimes the requirements for a project are to download multiple files at once and the best way to do that is to make a zip file for these files. For example, downloading a student’s certificates and files for applying to a college. Let’s say we have storage named attachments and every student has a folder with his/her id for saving his/her images and file, now we need to compress this folder and download it.

You may like these tutorials

Create a Zip file.

Let’s create a trait and name it app\Traits\FilesProcessing.php and create the folder if it doesn’t exist.

We will add a function to create a zip file. the function will take two parameters the first for the path of the student directory that will be compressed and the side the name of the zip file.

<?php
namespace App\Traits;
use File;
use Storage;

trait FilesProcessing{

public function create_Zip($pathToFilesToCompress,$name){
        //creating zip
        $zip = new \ZipArchive();

        //create zip file in zips storage
        $fileName = storage_path('app/zips/'.  $name);

        if ($zip->open($fileName, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)== TRUE)
        {
            //Get all the files in the directory
            $files = File::files($pathToFilesToCompress);

            //Compress the file to and add to the zip file.
            foreach ($files as $key => $value){
                $relativeName = basename($value);
                $zip->addFile($value, $relativeName);
            }
            //Close the zip file
            $zip->close(); 

            //Return a URL to to download
            return Storage::disk('zips')->url($name);
        }
        return false;
        
   }
}

We create a zip file in “zips” storage in Laravel. Here $files = File::files($pathToFilesToCompress); we get all the files in the directory then compress them and add them to our zip file and close the file then get the URL for download Storage::disk('zips')->url($name);

Let’s create the controller function. we send the student id with our request $request->student_id and we get the directory path and make the file name using it. Finally, we return the URL as JSon.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Traits\FilesProcessing;
use Storage;
class FileController extends Controller
{
    use FilesProcessing;
 public function downloadAttachments(Request $request){

        //Get student data
        $path =storage_path('app/attachments/'. $request->student_id);
       
        //Make zip file name
        $name = $request->student_id.'.zip';
        
        //Prepare the zip file
        $zipURL =  $this->create_Zip($path,$name);

        return response()->json(['url' =>  $zipURL]);
    }
}

Here is the API route.

use App\Http\Controllers\FileController;
Route::post('/downloadAttachments', [FileController::class, 'downloadAttachments']);

Zip Multiple Directories and Subdirectories

Let’s create a zip file to download multiple student attachments at once for different directories and add them as a subdirectory in our Zip file.

Let’s create a new function in trait FilesProcessing

  trait FilesProcessing{
 //..
 public function create_Zip_from_Folders_array($folders,$name){
        //creating zip
        $zip = new \ZipArchive();

        //create zip file in zips storage
        $fileName = storage_path('app/zips/'.  $name);
        if ($zip->open($fileName, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)== TRUE)
        {
            //Loop each directory to get files
            foreach ($folders as $folder){
                //Get all the files in the directory
                $files = File::files($folder['path']);
                //Compress the file to and add to the zip file.
                foreach ($files as $key => $value){
                    $relativeName = basename($value);
                    $zip->addFile($value,$folder['id'].'/'. $relativeName);
                }
            }
        }

        //Close the zip file
        $zip->close(); 
        //Return a URL to to download
        return Storage::disk('zips')->url($name);
    }
}

The function takes an array of folder storage paths and student id and the zip file name. Then we loop these directories to get the files in them and add them to our Zip file under the student id as a subdirectory name.

In the controller, we send an array of student ids and create an array of directories paths and ids.

class FileController extends Controller
{
 //..
   public function bulkAction(Request $request){

        //Make array of folder storage paths and student id
        $folders = [];
        foreach($request->student_ids  as $student_id){
            array_push( 
                $folders,
                [
                    'path' => storage_path('app/attachments/'. $student_id),
                    'id' => $student_id
                ]);
        }
  trait FilesProcessing{
 //..

        //Make a unique file name using data and time
        $dateTime = now();
        $name = $dateTime->format('YmdHis').'.zip';

        //Make the zip file
        $zipUrl =   $this->create_Zip_from_Folders_array($folders,$name);

        return response()->json(['url' => $zipUrl]);

    }
}

The zip file name will be unique by using the date and time.

Here is the API route to the bulk download.

Route::post('/bulkAction', [FileController::class, 'bulkAction']);
postman array request

That’s all thank you

Leave a Reply

Your email address will not be published. Required fields are marked *