• Stars
    star
    381
  • Rank 112,502 (Top 3 %)
  • Language
    PHP
  • License
    MIT License
  • Created over 5 years ago
  • Updated 4 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Easily create Zip files on-the-fly and provide a streaming download

Streaming Zips with Laravel

Latest Version on Packagist Total Downloads Software License Build Status

A fast and simple streaming zip file downloader for Laravel.

  • Builds zip files from local or S3 file sources, or any other PSR7 stream.
  • Provides a direct download stream to your user. The zip download begins immediately even though the zip is still being created. No need to save the zip to disk first.
  • Calculates the zip filesize up front for the Content-Length header. The user gets an accurate download time estimate in their browser.
  • Built on top of the excellent ZipStream-PHP library.

Quickstart

1. Install the package

composer require stechstudio/laravel-zipstream

The service provider and facade will be automatically wired up.

2. In a controller method call the create method on the Zip facade

use Zip;

class ZipController {

    public function build()
    {
        return Zip::create("package.zip", [
            "/path/to/Some File.pdf",
            "/path/to/Export.xlsx"       
        ]);
    }
}

That's it! A StreamedResponse will be returned and the zip contents built and streamed out. The user's browser will begin downloading a package.zip file immediately.

Customize the internal zip path for a file

By default any files you add will be stored in the root of the zip, with their original filenames.

You can customize the filename and even create subfolders within the zip by providing your files array with key/value pairs:

Zip::create("package.zip", [

    // Will be stored as `Some File.pdf` in the zip
    "/path/to/Some File.pdf",          
 
    // Will be stored as `Export.xlsx` in the zip
    "/path/to/data.xlsx" => 'Export.xlsx',
 
    // Will create a `log` subfolder in the zip and be stored as `log/details.txt`
    "/path/to/log.txt" => "log/details.txt"
 
]);

Fluent usage

You can also provide your files one at a time:

Zip::create("package.zip")
    ->add("/path/to/Some File.pdf")
    ->add("/path/to/data.xlsx", 'Export.xlsx')
    ->add("/path/to/log.txt", "log/details.txt");

Add HTTP file sources

You can add HTTP URLs as the source filepath. Note that zip filesize can only be calculated up front if the HTTP source provides a Content-Length header, not all URLs do.

Zip::create("package.zip")
    ->add("https://...", "myfile.pdf");

Add raw file data

You can provide raw data instead of a filepath:

Zip::create("package.zip")
    ->addRaw("...file contents...", "hello.txt");

Support for S3

Install AWS sdk and configure S3

You can stream files from S3 into your zip.

  1. Install the aws/aws-sdk-php package

  2. Setup an AWS IAM user with s3:GetObject permission for the S3 bucket and objects you intend to zip up.

  3. Store your credentials as AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_DEFAULT_REGION in your .env file.

Add S3 files to your zip

Provide s3:// paths when creating the zip:

Zip::create("package.zip")
    ->add("s3://bucket-name/path/to/object.pdf", "Something.pdf");

By default, this package will try to create an S3 client using the same .env file credentials that Laravel uses. If needed, you can wire up a custom S3 client to the zipstream.s3client container key. Or you can even pass in your own S3 client when adding a file to the zip. To do this, you'll need to create an S3File model instance yourself so that you can provide the client, like this:

use STS\ZipStream\Models\S3File;

// Create your own client however necessary
$s3 = new Aws\S3\S3Client();

Zip::create("package.zip")->add(
    S3File::make("s3://bucket-name/path/to/object.pdf")->setS3Client($s3)
);

Zip size prediction

By default this package attempts to predict the final zip size and sends a Content-Length header up front. This means users will see accurate progress on their download, even though the zip is being streamed out as it is created!

This only works if files are not compressed.

If you have issues with the zip size prediction you can disable it with ZIPSTREAM_PREDICT_SIZE=false in your .env file.

Specify your own filesizes

It can be expensive retrieving filesizes for some file sources such as S3 or HTTP. These require dedicated calls, and can add up to a lot of time if you are zipping up many files. If you store filesizes in your database and have them available, you can drastically improve performance by providing filesizes when you add files. You'll need to make your own File models instead of adding paths directly to the zip.

Let's say you have a collection of Eloquent $files, are looping through and building a zip. If you have a filesize attribute available, it would look something like this:

use STS\ZipStream\Models\File;

// Retrieve file records from the database
$files = ...;

$zip = Zip::create("package.zip");

foreach($files AS $file) {
    $zip->add(
        File::make($file->path, $file->name)->setFilesize($file->size)
    );
}

Configure compression

By default this package uses no compression. Why?

  1. This makes building the zips super fast, and is light on your CPU
  2. This makes it possible to predict the final zip size as mentioned above.

If you want to compress your zip files set ZIPSTREAM_FILE_METHOD=deflate in your .env file. Just realize this will disable the Content-Length header.

Save Zip to disk

Even though the primary goal of this package is to enable zip downloads without saving to disk, there may be times you'd like to generate a zip on disk as well. And you might as well make use of this package to do so.

Use the saveTo method to write the entire zip to disk immediately. Note that this expects a folder path, the zip name will be appended.

Zip::create("package.zip")
    // ... add files ...
    ->saveTo("/path/to/folder");

And yes, if you've properly setup and configured S3 you can even save to an S3 bucket/path.

Zip::create("package.zip")
    // ... add files ...
    ->saveTo("s3://bucket-name/path/to/folder");

Caching zip while still streaming download

What if you have a lot of users requesting the same zip payload? It might be nice to stream out the zip while also caching it to disk for the future.

Use the cache method to provide a cache path. Note this should be the entire path including filename.

Zip::create("package.zip")
    // ... add files ...
    ->cache("/path/to/folder/some-unique-cache-name.zip");

You might use an internal DB id for your cache name, so that the next time a user requests a zip download you can determine if one is already built and just hand it back.

Events

  • STS\ZipStream\Events\ZipStreaming: Dispatched when a new zip stream begins processing
  • STS\ZipStream\Events\ZipStreamed: Dispatched when a zip finishes streaming
  • STS\ZipStream\Events\ZipSizePredictionFailed: Fired if the predicted filesize doesn't match the final size. If you have filesize prediction enabled it's a good idea to listen for this event and log it, since that might mean the zip download failed or was corrupt for your user.

Filename sanitization

By default this package will try to translate any non-ascii character in filename or folder's name to ascii. For example, if your filename is 中文_にほんご_Ч_Ɯ_☺_someascii.txt. It will become __C___someascii.txt using Laravel's Str::ascii($path).

If you need to preserve non-ascii characters, you can disable this feature with an .env setting:

ZIPSTREAM_FILE_SANITIZE=false

License

The MIT License (MIT). Please see License File for more information.

More Repositories

1

filament-impersonate

Filament plugin that makes it easy to impersonate your users
PHP
232
star
2

laravel-ssh-tunnel

Easy creation & maintenance of an SSH Tunnel for Laravel/Lumen
PHP
191
star
3

backoff

PHP library providing retry functionality with multiple backoff strategies and jitter support
PHP
187
star
4

Laravel-PHP-CS-Fixer

Artisan Command for FriendsOfPHP/PHP-CS_Fixer
PHP
146
star
5

laravel-jwt

Helper package that makes it easy to generate, consume, and protect routes with JWT tokens in Laravel
PHP
121
star
6

laravel-env-security

Securely manage Laravel .env files for different deployment environments
PHP
75
star
7

laravel-bref-bridge

Bref, the Laravel way.
PHP
71
star
8

laravel-metrics

Easily track metrics from Laravel events and ship to InfluxDB, Prometheus, CloudWatch, or PostHog.
PHP
46
star
9

libvips-lambda

libvips Executable for AWS Lambda
Shell
46
star
10

aws-lambda-build

Docker Image for building AWS Lambda executables.
Dockerfile
40
star
11

laravel-aws-lambda

⛔️ DEPRECATED: Running Laravel on AWS Lambda
PHP
33
star
12

laravel-visual-testing

Visual UI screenshot testing with Laravel Dusk using percy.io
PHP
32
star
13

php-lambda

Build PHP executables for AWS Lambda
Dockerfile
24
star
14

laravel-record

What if Laravel's Collection and Model classes had a baby?
PHP
22
star
15

laravel-raw-sessions

Laravel session driver to establish bridge with raw PHP $_SESSION
PHP
18
star
16

laravel-hubspot

PHP
17
star
17

bref-extensions

Build tools for compiling binaries and extensions against the bref layer.
Dockerfile
14
star
18

codeception-laravel-unittest

PHP
11
star
19

laravel-vfs-adapter

Virtual Filesystem Storage Adapter for Laravel
PHP
10
star
20

filament-opcache

Manage OPcache from your Filament admin panel.
PHP
7
star
21

laravel-socialite-auth

PHP
6
star
22

filament-phpinfo

View phpinfo from your Filament admin panel.
Blade
4
star
23

phpinfo

Easily interact with your PHP configuration
PHP
4
star
24

laravel-upload-server

PHP
3
star
25

chalice_helpers

Some utilities for AWS Chalice
Python
3
star
26

aws-events

Library to help manage the plethora of event configurations in AWS Lambda
PHP
3
star
27

bai2

PHP library for parsing BAI2 files
PHP
2
star
28

laravel-storage-connect

Laravel package to easily connect to cloud storage accounts and upload files
PHP
2
star
29

insult-service

Random Insults from Martin Luther
JavaScript
1
star
30

laravatar

Minimalist Blade component for displaying a Gravatar, or falling back to initials.
PHP
1
star
31

laravel-locking-migrations

PHP
1
star
32

laravel-email-events

Laravel package to normalize webhooks from email providers like SendGrid or Postmark
PHP
1
star
33

lbb-core

Laravel Vapor Core Lambda Bootstrap for your own Lambda Layer, like bref!
PHP
1
star
34

slack-laravel-api

Laravelized Slack PHP Api
PHP
1
star