/home/mip/www/img/credit/datatables/guides.tar
FlySystem.rst000064400000002070151520665140007241 0ustar00Usage with FlySystem
===============

For saving or uploading the generated zip, you can use the
`Flysystem <https://flysystem.thephpleague.com>`_ package, and its many
adapters.

For that you will need to provide another stream than the ``php://output``
default one, and pass it to Flysystem ``putStream`` method.

.. code-block:: php

    // Open Stream only once for read and write since it's a memory stream and
    // the content is lost when closing the stream / opening another one
    $tempStream = fopen('php://memory', 'w+');

    // Create Zip Archive
    $zipStream = new ZipStream(
        outputStream: $tempStream,
        outputName: 'test.zip',
    );
    $zipStream->addFile('test.txt', 'text');
    $zipStream->finish();

    // Store File
    // (see Flysystem documentation, and all its framework integration)
    // Can be any adapter (AWS, Google, Ftp, etc.)
    $adapter = new Local(__DIR__.'/path/to/folder');
    $filesystem = new Filesystem($adapter);

    $filesystem->writeStream('test.zip', $tempStream)

    // Close Stream
    fclose($tempStream);
Varnish.rst000064400000001207151520665140006715 0ustar00Usage with Varnish
=============

Serving a big zip with varnish in between can cause random stream close.
This can be solved by adding attached code to the vcl file.

To avoid the problem, add the following to your varnish config file:

.. code-block::
    sub vcl_recv {
        # Varnish can’t intercept the discussion anymore
        # helps for streaming big zips
        if (req.url ~ "\.(tar|gz|zip|7z|exe)$") {
            return (pipe);
        }
    }
    # Varnish can’t intercept the discussion anymore
    # helps for streaming big zips
    sub vcl_pipe {
        set bereq.http.connection = "close";
        return (pipe);
    }
Symfony.rst000064400000011067151520665140006754 0ustar00Usage with Symfony
===============

Overview for using ZipStream in Symfony
--------

Using ZipStream in Symfony requires use of Symfony's ``StreamedResponse`` when
used in controller actions.

Wrap your call to the relevant ``ZipStream`` stream method (i.e. ``addFile``,
``addFileFromPath``, ``addFileFromStream``) in Symfony's ``StreamedResponse``
function passing in any required arguments for your use case.

Using Symfony's ``StreamedResponse`` will allow Symfony to stream output from
ZipStream correctly to users' browsers and avoid a corrupted final zip landing
on the users' end.

Example for using ``ZipStream`` in a controller action to zip stream files
stored in an AWS S3 bucket by key:

.. code-block:: php

    use Symfony\Component\HttpFoundation\StreamedResponse;
    use Aws\S3\S3Client;
    use ZipStream;

    //...

    /**
    * @Route("/zipstream", name="zipstream")
    */
    public function zipStreamAction()
    {
        // sample test file on s3
        $s3keys = array(
        "ziptestfolder/file1.txt"
        );

        $s3Client = $this->get('app.amazon.s3'); //s3client service
        $s3Client->registerStreamWrapper(); //required

        // using StreamedResponse to wrap ZipStream functionality
        // for files on AWS s3.
        $response = new StreamedResponse(function() use($s3keys, $s3Client)
        {
            // Define suitable options for ZipStream Archive.
            // this is needed to prevent issues with truncated zip files
            //initialise zipstream with output zip filename and options.
            $zip = new ZipStream\ZipStream(
                outputName: 'test.zip',
                defaultEnableZeroHeader: true,
                contentType: 'application/octet-stream',
            );

            //loop keys - useful for multiple files
            foreach ($s3keys as $key) {
                // Get the file name in S3 key so we can save it to the zip
                //file using the same name.
                $fileName = basename($key);

                // concatenate s3path.
                // replace with your bucket name or get from parameters file.
                $bucket = 'bucketname';
                $s3path = "s3://" . $bucket . "/" . $key;

                //addFileFromStream
                if ($streamRead = fopen($s3path, 'r')) {
                    $zip->addFileFromStream(
                        fileName: $fileName,
                        stream: $streamRead,
                    );
                } else {
                    die('Could not open stream for reading');
                }
            }

            $zip->finish();

        });

        return $response;
    }

In the above example, files on AWS S3 are being streamed from S3 to the Symfon
application via ``fopen`` call when the s3Client has ``registerStreamWrapper``
applied. This stream is then passed to ``ZipStream`` via the
``addFileFromStream`` function, which ZipStream then streams as a zip to the
client browser via Symfony's ``StreamedResponse``. No Zip is created server
side, which makes this approach a more efficient solution for streaming zips to
the client browser especially for larger files.

For the above use case you will need to have installed
`aws/aws-sdk-php-symfony <https://github.com/aws/aws-sdk-php-symfony>`_ to
support accessing S3 objects in your Symfony web application. This is not
required for locally stored files on you server you intend to stream via
``ZipStream``.

See official Symfony documentation for details on
`Symfony's StreamedResponse <https://symfony.com/doc/current/components/http_foundation.html#streaming-a-response>`_ 
``Symfony\Component\HttpFoundation\StreamedResponse``.

Note from `S3 documentation <https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-stream-wrapper.html>`_:

    Streams opened in "r" mode only allow data to be read from the stream, and
    are not seekable by default. This is so that data can be downloaded from
    Amazon S3 in a truly streaming manner, where previously read bytes do not
    need to be buffered into memory. If you need a stream to be seekable, you
    can pass seekable into the stream context options of a function.

Make sure to configure your S3 context correctly!

Uploading a file
--------

You need to add correct permissions
(see `#120 <https://github.com/maennchen/ZipStream-PHP/issues/120>`_)

**example code**


.. code-block:: php

    $path = "s3://{$adapter->getBucket()}/{$this->getArchivePath()}";

    // the important bit
    $outputContext = stream_context_create([
        's3' => ['ACL' => 'public-read'],
    ]);

    fopen($path, 'w', null, $outputContext);
StreamOutput.rst000064400000001470151520665140007761 0ustar00Stream Output
===============

Stream to S3 Bucket
---------------

.. code-block:: php

    use Aws\S3\S3Client;
    use Aws\Credentials\CredentialProvider;
    use ZipStream\ZipStream;

    $bucket = 'your bucket name';
    $client = new S3Client([
        'region' => 'your region',
        'version' => 'latest',
        'bucketName' => $bucket,
        'credentials' => CredentialProvider::defaultProvider(),
    ]);
    $client->registerStreamWrapper();

    $zipFile = fopen("s3://$bucket/example.zip", 'w');

    $zip = new ZipStream(
        enableZip64: false,
        outputStream: $zipFile,
    );

    $zip->addFile(
        fileName: 'file1.txt',
        data: 'File1 data',
    );
    $zip->addFile(
        fileName: 'file2.txt',
        data: 'File2 data',
    );
    $zip->finish();

    fclose($zipFile);
PSR7Streams.rst000064400000001032151520665140007371 0ustar00Usage with PSR 7 Streams
===============

PSR-7 streams are `standardized streams <https://www.php-fig.org/psr/psr-7/>`_.

ZipStream-PHP supports working with these streams with the function
``addFileFromPsr7Stream``. 

For all parameters of the function see the API documentation.

Example
---------------

.. code-block:: php

    $stream = $response->getBody();
    // add a file named 'streamfile.txt' from the content of the stream
    $zip->addFileFromPsr7Stream(
        fileName: 'streamfile.txt',
        stream: $stream,
    );
Nginx.rst000064400000001057151520665140006371 0ustar00Usage with nginx
=============

If you are using nginx as a webserver, it will try to buffer the response.
So you'll want to disable this with a custom header:

.. code-block:: php
    header('X-Accel-Buffering: no');
    # or with the Response class from Symfony
    $response->headers->set('X-Accel-Buffering', 'no');

Alternatively, you can tweak the
`fastcgi cache parameters <https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html#fastcgi_buffers>`_
within nginx config.

See `original issue <https://github.com/maennchen/ZipStream-PHP/issues/77>`_.index.rst000064400000007670151520665140006424 0ustar00ZipStream PHP
=============

A fast and simple streaming zip file downloader for PHP. Using this library will
save you from having to write the Zip to disk. You can directly send it to the
user, which is much faster. It can work with S3 buckets or any PSR7 Stream.

.. toctree::

   index
   Symfony
   Options
   StreamOutput
   FlySystem
   PSR7Streams
   Nginx
   Varnish
   ContentLength

Installation
---------------

Simply add a dependency on ``maennchen/zipstream-php`` to your project's
``composer.json`` file if you use Composer to manage the dependencies of your
project. Use following command to add the package to your project's
dependencies:

.. code-block:: sh
   composer require maennchen/zipstream-php

If you want to use``addFileFromPsr7Stream```
(``Psr\Http\Message\StreamInterface``) or use a stream instead of a
``resource`` as ``outputStream``, the following dependencies must be installed
as well:

.. code-block:: sh
   composer require psr/http-message guzzlehttp/psr7

If ``composer install`` yields the following error, your installation is missing
the `mbstring extension <https://www.php.net/manual/en/book.mbstring.php>`_,
either `install it <https://www.php.net/manual/en/mbstring.installation.php>`_
or run the follwoing command:

.. code-block::
    Your requirements could not be resolved to an installable set of packages.

    Problem 1
        - Root composer.json requires PHP extension ext-mbstring * but it is
          missing from your system. Install or enable PHP's mbstrings extension.

.. code-block:: sh
   composer require symfony/polyfill-mbstring

Usage Intro
---------------

Here's a simple example:

.. code-block:: php

   // Autoload the dependencies
   require 'vendor/autoload.php';

   // create a new zipstream object
   $zip = new ZipStream\ZipStream(
      outputName: 'example.zip',

      // enable output of HTTP headers
      sendHttpHeaders: true,
   );

   // create a file named 'hello.txt'
   $zip->addFile(
      fileName: 'hello.txt',
      data: 'This is the contents of hello.txt',
   );

   // add a file named 'some_image.jpg' from a local file 'path/to/image.jpg'
   $zip->addFileFromPath(
      fileName: 'some_image.jpg',
      path: 'path/to/image.jpg',
   );

   // add a file named 'goodbye.txt' from an open stream resource
   $filePointer = tmpfile();
   fwrite($filePointer, 'The quick brown fox jumped over the lazy dog.');
   rewind($filePointer);
   $zip->addFileFromStream(
      fileName: 'goodbye.txt',
      stream: $filePointer,
   );
   fclose($filePointer);

   // add a file named 'streamfile.txt' from the body of a `guzzle` response
   // Setup with `psr/http-message` & `guzzlehttp/psr7` dependencies required.
   $zip->addFileFromPsr7Stream(
      fileName: 'streamfile.txt',
      stream: $response->getBody(),
   );

   // finish the zip stream
   $zip->finish();

You can also add comments, modify file timestamps, and customize (or
disable) the HTTP headers. It is also possible to specify the storage method
when adding files, the current default storage method is ``DEFLATE``
i.e files are stored with Compression mode 0x08.

Known Issues
---------------

The native Mac OS archive extraction tool prior to macOS 10.15 might not open
archives in some conditions. A workaround is to disable the Zip64 feature with
the option ``enableZip64: false``. This limits the archive to 4 Gb and 64k files
but will allow users on macOS 10.14 and below to open them without issue.
See `#116 <https://github.com/maennchen/ZipStream-PHP/issues/146>`_.

The linux ``unzip`` utility might not handle properly unicode characters.
It is recommended to extract with another tool like
`7-zip <https://www.7-zip.org/>`_.
See `#146 <https://github.com/maennchen/ZipStream-PHP/issues/146>`_.

It is the responsability of the client code to make sure that files are not
saved with the same path, as it is not possible for the library to figure it out
while streaming a zip.
See `#154 <https://github.com/maennchen/ZipStream-PHP/issues/154>`_.
ContentLength.rst000064400000002534151520665140010063 0ustar00Adding Content-Length header
=============

Adding a ``Content-Length`` header for ``ZipStream`` can be achieved by
using the options ``SIMULATION_STRICT`` or ``SIMULATION_LAX`` in the
``operationMode`` parameter.

In the ``SIMULATION_STRICT`` mode, ``ZipStream`` will not allow to calculate the
size based on reading the whole file. ``SIMULATION_LAX`` will read the whole
file if neccessary.

``SIMULATION_STRICT`` is therefore useful to make sure that the size can be
calculated efficiently.

.. code-block:: php
    use ZipStream\OperationMode;
    use ZipStream\ZipStream;

    $zip = new ZipStream(
        operationMode: OperationMode::SIMULATE_STRICT, // or SIMULATE_LAX
        defaultEnableZeroHeader: false,
        sendHttpHeaders: true,
        outputStream: $stream,
    );

    // Normally add files
    $zip->addFile('sample.txt', 'Sample String Data');

    // Use addFileFromCallback and exactSize if you want to defer opening of
    // the file resource
    $zip->addFileFromCallback(
        'sample.txt',
        exactSize: 18,
        callback: function () {
            return fopen('...');
        }
    );

    // Read resulting file size
    $size = $zip->finish();
    
    // Tell it to the browser
    header('Content-Length: '. $size);
    
    // Execute the Simulation and stream the actual zip to the client
    $zip->executeSimulation();

Options.rst000064400000004260151520665140006740 0ustar00Available options
===============

Here is the full list of options available to you. You can also have a look at
``src/ZipStream.php`` file.

.. code-block:: php

    use ZipStream\ZipStream;

    require_once 'vendor/autoload.php';

    $zip = new ZipStream(
        // Define output stream
        // (argument is eiter a resource or implementing
        // `Psr\Http\Message\StreamInterface`)
        //
        // Setup with `psr/http-message` & `guzzlehttp/psr7` dependencies
        // required when using `Psr\Http\Message\StreamInterface`.
        outputStream: $filePointer,

        // Set the deflate level (default is 6; use -1 to disable it)
        defaultDeflateLevel: 6,

        // Add a comment to the zip file
        comment: 'This is a comment.',

        // Send http headers (default is true)
        sendHttpHeaders: false,

        // HTTP Content-Disposition.
        // Defaults to 'attachment', where FILENAME is the specified filename.
        // Note that this does nothing if you are not sending HTTP headers.
        contentDisposition: 'attachment',

        // Output Name for HTTP Content-Disposition
        // Defaults to no name
        outputName: "example.zip",

        // HTTP Content-Type.
        // Defaults to 'application/x-zip'.
        // Note that this does nothing if you are not sending HTTP headers.
        contentType: 'application/x-zip',

        // Set the function called for setting headers.
        // Default is the `header()` of PHP
        httpHeaderCallback: header(...),

        // Enable streaming files with single read where general purpose bit 3
        // indicates local file header contain zero values in crc and size
        // fields, these appear only after file contents in data descriptor
        // block.
        // Set to true if your input stream is remote
        // (used with addFileFromStream()).
        // Default is false.
        defaultEnableZeroHeader: false,

        // Enable zip64 extension, allowing very large archives
        // (> 4Gb or file count > 64k)
        // Default is true
        enableZip64: true,

        // Flush output buffer after every write
        // Default is false
        flushOutput: true,
    );