{"id":16616531,"url":"https://github.com/selective-php/zip-responder","last_synced_at":"2025-10-08T06:51:49.067Z","repository":{"id":45566725,"uuid":"326173446","full_name":"selective-php/zip-responder","owner":"selective-php","description":"A ZIP file and stream responder (PSR-7)","archived":false,"fork":false,"pushed_at":"2023-11-04T22:39:38.000Z","size":63,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-02T20:53:52.308Z","etag":null,"topics":["php","php7","php8","psr-7","slim-framework","slim4","zip"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/selective-php.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-02T12:01:15.000Z","updated_at":"2025-02-14T16:56:17.000Z","dependencies_parsed_at":"2022-08-30T04:10:44.812Z","dependency_job_id":"f50b8ba2-34a1-4e44-b7a8-8c95f077eaf4","html_url":"https://github.com/selective-php/zip-responder","commit_stats":{"total_commits":24,"total_committers":3,"mean_commits":8.0,"dds":"0.16666666666666663","last_synced_commit":"64e08cb21d1485bd123c60a84892b01c30b4a795"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/selective-php/zip-responder","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selective-php%2Fzip-responder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selective-php%2Fzip-responder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selective-php%2Fzip-responder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selective-php%2Fzip-responder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/selective-php","download_url":"https://codeload.github.com/selective-php/zip-responder/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/selective-php%2Fzip-responder/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278903006,"owners_count":26065786,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php","php7","php8","psr-7","slim-framework","slim4","zip"],"created_at":"2024-10-12T02:13:25.555Z","updated_at":"2025-10-08T06:51:49.051Z","avatar_url":"https://github.com/selective-php.png","language":"PHP","readme":"# selective/zip-responder\n\nA ZIP responder (PSR-7).\n\n[![Latest Version on Packagist](https://img.shields.io/github/release/selective-php/zip-responder.svg)](https://packagist.org/packages/selective/zip-responder)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)\n[![Build Status](https://github.com/selective-php/zip-responder/workflows/build/badge.svg)](https://github.com/selective-php/zip-responder/actions)\n[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/selective-php/zip-responder.svg)](https://scrutinizer-ci.com/g/selective-php/zip-responder/code-structure)\n[![Quality Score](https://img.shields.io/scrutinizer/quality/g/selective-php/zip-responder.svg)](https://scrutinizer-ci.com/g/selective-php/zip-responder/?branch=master)\n[![Total Downloads](https://img.shields.io/packagist/dt/selective/zip-responder.svg)](https://packagist.org/packages/selective/zip-responder/stats)\n\n## Table of Contents\n\n* [Requirements](#requirements)\n* [Installation](#installation)\n* [Usage](#usage)\n    * [Sending a ZIP file](#sending-a-zip-file)\n    * [Sending a ZIP file from a string](#sending-a-zip-file-from-a-string)  \n    * [Sending a ZIP stream](#sending-a-zip-stream)\n    * [Sending a ZipArchive file](#sending-a-ziparchive-file)\n    * [Sending a ZipStream-PHP archive](#sending-a-zipstream-php-archive)\n    * [Sending a PhpZip archive](#sending-a-phpzip-archive)\n* [Slim 4 Integration](#slim-4-integration)\n\n## Requirements\n\n* PHP 7.3+ or 8.0+\n* A PSR-7 StreamFactory implementation, e.g. [nyholm/psr7](https://github.com/Nyholm/psr7)\n\n## Installation\n\n```\ncomposer require selective/zip-responder\n```\n\n## Usage\n\nCreating a new ZipResponder instance using the `nyholm/psr7` Psr17Factory:\n\n```php\nuse Selective\\Http\\Zip\\ZipResponder;\nuse Nyholm\\Psr7\\Factory\\Psr17Factory;\n\n$zipResponder = new ZipResponder(new Psr17Factory());\n```\n\nCreating a new ZipResponder instance using the `slim/psr7` StreamFactory:\n\n```php\nuse Selective\\Http\\Zip\\ZipResponder;\nuse Slim\\Psr7\\Factory\\StreamFactory;\n\n$zipResponder = new ZipResponder(new StreamFactory());\n```\n\n\n\n### Sending a ZIP file\n\nSend ZIP file to browser, force direct download:\n\n```php\nreturn $zipResponder-\u003ewithZipFile($response, 'source.zip', 'output.zip');\n```\n\n### Sending a ZIP file from a string\n\n```php\nreturn $zipResponder-\u003ewithZipString($response, file_get_contents('example.zip'), 'output.zip');\n```\n\n### Sending a ZIP stream\n\nSend ZIP stream to the browser, force direct download:\n\n```php\n$stream = fopen('test.zip', 'r');\n \nreturn $zipResponder-\u003ewithZipStream($response, $stream, 'output.zip');\n```\n\n### Sending a ZIP stream on the fly\n\nSending a file directly to the client is not intended according to the PSR-7 specification, \nbut can still be realized with the help of a CallbackStream.\n\n```php\nuse Selective\\Http\\Zip\\Stream\\CallbackStream;\n\n$callbackStream = new CallbackStream(function () {\n    echo 'my binary zip content';\n}\n\n$response = $zipResponder-\u003ewithZipHeaders($response, $outputName, true);\n\nreturn $response-\u003ewithBody($callbackStream);\n```\n\n### Sending a ZipArchive file\n\nThe ZIP extension enables you to transparently read or write ZIP compressed archives and the files inside them.\nA [ZipArchive](https://www.php.net/manual/en/class.ziparchive.php) does not support\n\"memory mapped files\", like PHP streams. You can only access local files with ZipArchive. For this purpose, you can\ncreate a temporary file, or you can use an existing file from the filesystem.\n\n```php\nuse ZipArchive;\n// ...\n\n// Create temporary filename\n$filename = tempnam(sys_get_temp_dir(), 'zip');\n\n// Add files to temporary ZIP file\n$zip = new ZipArchive();\n$zip-\u003eopen($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE);\n$zip-\u003eaddFromString('test.txt', 'my content');\n$zip-\u003eclose();\n\n// Render ZIP file into the response as stream\nreturn $zipResponder-\u003ewithZipStream($response, fopen($filename, 'r'), 'download.zip');\n```\n\n### Sending a ZipStream-PHP archive\n\n[ZipStream-PHP](https://github.com/maennchen/ZipStream-PHP) is a library for streaming dynamic ZIP files without writing\nto the disk. You can send the file directly to the user, which is much faster and improves testability.\n\n**Installation:**\n\n```\ncomposer require maennchen/zipstream-php\n```\n\nCreating and sending a ZIP file (only in-memory) to the browser:\n\n```php\nuse ZipStream\\ZipStream;\n\n// ...\n\n// Create ZIP file, only in-memory\n$stream = fopen('php://memory', 'w+b');\n\n$zip = new ZipStream(\n    outputStream: $stream,\n    // disable output of HTTP headers\n    sendHttpHeaders: false,\n);\n\n// create a file named 'hello.txt'\n$zip-\u003eaddFile(\n    fileName: 'hello.txt',\n    data: 'This is the contents of hello.txt',\n);\n\n$zip-\u003efinish();\n\n$response = $zipResponder-\u003ewithZipStream($response, $stream, 'download.zip');\n```\n\nSending a ZIP-stream on the fly:\n\n```php\nuse Selective\\Http\\Zip\\Stream\\CallbackStream;\nuse ZipStream\\ZipStream;\n//...\n\n$callbackStream = new CallbackStream(function () {\n    // Flush ZIP file directly to output stream (php://output)\n    $zip = new ZipStream(\n        flushOutput: true,\n        sendHttpHeaders: false,\n    );\n\n    // Add files to ZIP file and stream it directly\n    $zip-\u003eaddFile('test.txt', 'my file content');\n    $zip-\u003eaddFile('test2.txt', 'my file content 2');\n    $zip-\u003eaddFile('test3.txt', 'my file content 4');\n    $zip-\u003efinish();\n});\n\n$response = $zipResponder-\u003ewithZipHeaders($response, $outputName, true);\n\nreturn $response-\u003ewithBody($callbackStream);\n```\n\n### Sending a PhpZip archive\n\n[PhpZip](https://github.com/Ne-Lexa/php-zip) is a library for extended work with ZIP-archives.\n\n**Installation:**\n\n```\ncomposer require nelexa/zip\n```\n\nNote, when you use the `nelexa/zip` component, you may not need the `selective/zip-responder` \ncomponent because the `nelexa/zip` already provides its own PSR-7 responder.\n\n**Example**\n\n```php\nuse PhpZip\\ZipFile;\n\n// ...\n\n$zipFile = new ZipFile();\n$zipFile-\u003eaddFromString('test.txt', 'File content');\n\nreturn $zipFile-\u003eoutputAsResponse($response, 'download.zip');\n```\n\nIn case you want to keep your architecture more clean (SRP), \nyou may use the `selective/zip-responder` responder to create \nand send a ZIP file to the browser as follows:\n\n```php\nuse PhpZip\\ZipFile;\n\n// ...\n\n// Create new archive\n$zipFile = new ZipFile();\n\n// Add entry from string\n$zipFile-\u003eaddFromString('test.txt', 'File content');\n     \nreturn $zipResponder-\u003ewithZipString($response, $zipFile-\u003eoutputAsString(), 'download.zip');\n```\n\n## Slim 4 Integration\n\nCreate a DI container definition for: `StreamFactoryInterface::class` and `ZipResponder::class`\n\nA `nyholm/psr7` and PHP-DI example:\n\n```php\n\u003c?php\n\nuse Nyholm\\Psr7\\Factory\\Psr17Factory;\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Selective\\Http\\Zip\\ZipResponder;\n\nreturn [\n    // ...\n\n    StreamFactoryInterface::class =\u003e function (ContainerInterface $container) {\n        return $container-\u003eget(Psr17Factory::class);\n    },\n\n    ZipResponder::class =\u003e function (ContainerInterface $container) {\n        return new ZipResponder($container-\u003eget(StreamFactoryInterface::class));\n    },\n];\n```\n\nA `slim/psr7` and PHP-DI example:\n\n```php\n\u003c?php\n\nuse Psr\\Container\\ContainerInterface;\nuse Psr\\Http\\Message\\StreamFactoryInterface;\nuse Slim\\Psr7\\Factory\\StreamFactory;\nuse Selective\\Http\\Zip\\ZipResponder;\n\nreturn [\n    // ...\n    \n    StreamFactoryInterface::class =\u003e function () {\n        return new StreamFactory();\n    },\n    \n    ZipResponder::class =\u003e function (ContainerInterface $container) {\n        return new ZipResponder($container-\u003eget(StreamFactoryInterface::class));\n    },\n];\n```\n\nThe responder should only be used within an action handler or middleware.\n\n**Action class example using dependency injection:**\n\n```php\n\u003c?php\n\nnamespace App\\Action;\n\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Selective\\Http\\Zip\\ZipResponder;\nuse ZipArchive;\n\nfinal class ZipDemoAction\n{\n    /**\n     * @var ZipResponder\n     */\n    private $zipResponder;\n\n    public function __construct(ZipResponder $zipResponder)\n    {\n        $this-\u003ezipResponder = $zipResponder;\n    }\n\n    public function __invoke(\n        ServerRequestInterface $request, \n        ResponseInterface $response\n    ): ResponseInterface {\n        $filename = tempnam(sys_get_temp_dir(), 'zip');\n\n        $zip = new ZipArchive();\n        $zip-\u003eopen($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE);\n        $zip-\u003eaddFromString('test.txt', 'my content');\n        $zip-\u003eclose();\n\n        return $this-\u003ezipResponder-\u003ewithZipFile($response, $filename, 'filename.zip');\n    }\n}\n```\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE) for more information.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselective-php%2Fzip-responder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fselective-php%2Fzip-responder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fselective-php%2Fzip-responder/lists"}