Zip and download files directory from Amazon S3 with Laravel

Well, this scenario probably can drive you crazy. Say, you have a Laravel web system, and all your photo uploads to the system are saved in another host. In this case, let’s take Amazon S3 bucket.

You may wanna find out a way to download an entire folder with files inside, zipped, with a single click. That can be a fair request from your client.

So, today I’m going to show you how to do that.

We do this like this, first files are download to the host of our system, then they are zipped and downloaded to the local computer of whoever download. That’s the plan!

first of all, I’m gonna create a method in a specific controller.

public function downloadAlbum($id){

}

Then I’m gonna create the logic to get all the photos from a specific album.

public function downloadAlbum($id){
   $photos = Photos::where('album_id', $id)->get();
}

Perfect! Now I have all the photos of the particular album.

Then, I’m using PHP’s ZipArchive class to create the zip file.

public function downloadAlbum($id){
   $photos = Photos::where('album_id', $id)->get();

   $zip = new \ZipArchive();
   $zip->open('/var/www/html/mysite/uploads/zip/myalbum'.time().'.zip', \ZipArchive::CREATE);
}

What the above code does is, it creates an empty ZIP Archive file with the file name similar to myalbum35635353455.zip.

Now we need to download photos from Amazon S3, and put them in the Zip Archive we’ve just created.

For that, I’m using a foreach loop.

public function downloadAlbum($id){
   $photos = Photos::where('album_id', $id)->get();

   $zip = new \ZipArchive();
   $zip->open('/var/www/html/mysite/uploads/zip/myalbum'.time().'.zip', \ZipArchive::CREATE);

   foreach ($photos as $photo){
      $zip->addFromString($photo->image, file_get_contents("http://mysite.s3-ap-southeast-1.amazonaws.com/albums/".$id."/".$photo->image));

   }

}

Well, that’s pretty much it. Now, the images are downloaded from the S3 bucket and put them inside the Zip Archive.

Now we need to download this Zip file. And don’t forget to close the Zip object after the loop.

public function downloadAlbum($id){
   $photos = Photos::where('album_id', $id)->get();

   $zip = new \ZipArchive();
   $zip->open('/var/www/html/mysite/uploads/zip/myalbum'.time().'.zip', \ZipArchive::CREATE);

   foreach ($photos as $photo){
      $zip->addFromString($photo->image, file_get_contents("http://mysite.s3-ap-southeast-1.amazonaws.com/albums/".$id."/".$photo->image));
   }

$zip->close();

}

Completed method

Finally, send the Zip file to the web browser as a download

public function downloadAlbum($id){
  $photos = Photos::where('album_id', $id)->get();

  $zip = new \ZipArchive();
  $zip->open('/var/www/html/mysite/uploads/zip/myalbum'.time().'.zip', \ZipArchive::CREATE);

  foreach ($photos as $photo){
     $zip->addFromString($photo->image, file_get_contents("http://mysite.s3-ap-southeast-1.amazonaws.com/albums/".$id."/".$photo->image));
  }

  $zip->close();

  header('Content-disposition: attachment; filename='.$album->name.'.zip');
  header('Content-type: application/zip');
  readfile('/var/www/html/mysite/uploads/zip/myalbum'.time().'.zip');

}


That’s it! Now you can add a route to this method and call it on specific album to download.

Leave a Reply

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