PHPackages                             ntdash/zipstore - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [File &amp; Storage](/categories/file-storage)
4. /
5. ntdash/zipstore

ActiveLibrary[File &amp; Storage](/categories/file-storage)

ntdash/zipstore
===============

a single level virtual zip store

v0.3.0(1mo ago)115MITPHPPHP ^8.1

Since Apr 8Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/ntdash/zip-store)[ Packagist](https://packagist.org/packages/ntdash/zipstore)[ RSS](/packages/ntdash-zipstore/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (3)Dependencies (11)Versions (7)Used By (0)

ZIPStore
========

[](#zipstore)

A PHP library for generating and streaming virtual ZIP archives on-the-fly without consuming disk space. Perfect for constraint environments where storage is limited.

Table of Contents
-----------------

[](#table-of-contents)

- [Overview](#overview)
- [Key Features](#key-features)
- [Important Limitations](#important-limitations)
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
    - [Basic Usage](#basic-usage)
    - [Advanced Reading](#advanced-reading)
    - [Adding Files with Custom Names](#adding-files-with-custom-names)
    - [Handling Duplicates](#handling-duplicates)
    - [Stream to Output](#stream-to-output)
- [Advanced Features](#advanced-features)
    - [Custom Entry File Handlers](#custom-entry-file-handlers)
    - [Seeking Behavior](#seeking-behavior)
- [Configuration Options](#configuration-options)
- [Architecture](#architecture)
- [Examples](#examples)
    - [Simple File Download Server](#simple-file-download-server)
    - [Backup Logs Files](#backup-logs-files)
    - [ZIP From Database BLOBs](#zip-from-database-blobs)
- [License](#license)

Overview
--------

[](#overview)

**ZipStore** enables you to add files to a virtual ZIP store and then read from it as if it were a native file resource, using familiar `seek()` and `read()` operations. The library generates ZIP file components on-demand while reading file contents live, making it ideal for serving large file downloads with minimal memory and disk overhead.

Call `open()` at any point to capture a snapshot of the store's current entry list into an independent `OpenedStore` — a seekable read view over the ZIP data as it stood at that moment. The `Store` itself remains open: you can keep calling `addFile()` after `open()`, and those additions will not affect already-taken snapshots. Calling `open()` multiple times yields independent `OpenedStore` instances, each with its own cursor, each reflecting the state of the store at the time of that call.

### Key Features

[](#key-features)

- **On-the-fly ZIP generation** - Components are created during reading, not upfront
- **Minimal storage footprint** - Perfect for resource-constrained environments
- **Native file interface** - Use `seek()` and `read()` just like file streams
- **UTF-8 support** - Proper Unicode filename handling
- **Pluggable file handlers** - Implement custom `ZipStoreEntryFile` for non-local filesystem sources
- **Performance optimized** - Lazy loading and caching of ZIP structures
- **Standards compliant** - Generates valid ZIP files compatible with standard tools
- **Zero cleanup** - No manual resource management needed

Important Limitations
---------------------

[](#important-limitations)

ZipStore focuses on stream-friendly ZIP generation and **does not support**:

- File compression (deflate, bzip2, etc.)
- Encryption
- Files larger than `3.75 GiB` per entry
- More than 65,535 entries per archive
- Archive file larger than `4 GiB` since there is no support for ZIP64 yet

These limitations are by design to keep the library lightweight and performant. For complex ZIP operations, consider using `php-zip` extension directly.

Requirements
------------

[](#requirements)

- PHP **≥ 8.1**

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

[](#installation)

Install via Composer:

```
composer require ntdash/zip-store
```

Quick Start
-----------

[](#quick-start)

### Basic Usage

[](#basic-usage)

```
use ZipStore\Store;

// Create a store
$store = new Store();

// Add files
$store->addFile("path/to/file.json");
$store->addFiles([
    "path/to/video.webm",
    "path/to/sample.png"
]);

// Snapshot the store's current entry list into an independent OpenedStore.
// The Store remains open — further addFile() calls won't affect this snapshot.
$openedStore = $store->open();

// Read bytes from any position
$offset = 0;
$bytes = 1024 * 1024 * 4; // 4 MiB

$openedStore->seek($offset);
$buffer = $openedStore->read($bytes);

// current offset after seek and read
echo $openedStore->tell();  // 4194304
```

### Advanced Reading

[](#advanced-reading)

```
// Read with specific offset
$buffer = $openedStore->read(length: 1024 * 1024 * 4, offset: 1024);

// Default read size is 512 KiB
$buffer = $openedStore->read(offset: 2048);

// Check if end of file
if ($openedStore->eof()) {
    echo "Reached end of ZIP file";
}

// Get total ZIP file size
$totalSize = $openedStore->getSize();
```

### Adding Files with Custom Names

[](#adding-files-with-custom-names)

```
$store->addFile(
    "path/to/original-file.txt",
    "custom-name-in-zip.txt"
);
```

### Handling Duplicates

[](#handling-duplicates)

Control how duplicate entry names are handled:

```
use ZipStore\Store;

// Append numerical suffix to duplicates (default)
$store = new Store(Store::DUP_APPEND_NUM);

// Overwrite previous entry with same name
$store = new Store(Store::DUP_OVERWRITE);

// Throw exception on duplicates
$store = new Store(Store::DUP_FAILED | Store::STRICT);
```

### Stream to Output

[](#stream-to-output)

Common pattern for sending ZIP to client. `open()` snapshots the store at this point — call `getSize()` on the returned `OpenedStore` to get the exact byte count before streaming begins:

```
$opened = $store->open();

header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="archive.zip"');
header('Content-Length: ' . $opened->getSize());

$opened->passthru();
```

Advanced Features
-----------------

[](#advanced-features)

### Custom Entry File Handlers

[](#custom-entry-file-handlers)

By default, ZipStore uses the file system to read file contents. You can provide custom implementations of `ZipStoreEntryFile` to handle non-filesystem sources like database BLOBs, S3 objects, or in-memory streams.

#### Registering Custom File Handler

[](#registering-custom-file-handler)

Set your custom file handler globally before creating entries:

```
use ZipStore\Entry;
use ZipStore\Store;
use ZipStore\EntryArgument;

// Register your custom entry file class
EntryArgument::setEntryFileClass(CustomEntryFile::class);

// Now when you add entries, they'll use your custom handler
$store = new Store();
$store->addFile('custom-data-identifier');
// Snapshot the current entry list — returns an independent OpenedStore cursor
$opened = $store->open();
```

**Important:** The custom class must implement both `__serialize()` and `__unserialize()` magic methods for proper serialization support.

### Seeking Behavior

[](#seeking-behavior)

The `OpenedStore::seek()` method supports all `fseek()` behaviors:

```
use ZipStore\OpenedStore;

// SEEK_SET (0): Absolute position from start
$opened->seek(1024, SEEK_SET);

// SEEK_CUR (1): Relative to current position
$opened->seek(512, SEEK_CUR);

// SEEK_END (2): Relative to end of file
$opened->seek(-1024, SEEK_END);
```

Configuration Options
---------------------

[](#configuration-options)

### Store Constructor Options

[](#store-constructor-options)

```
// No special options (default)
$store = new Store(Store::NO_EXTRA);

// Append numbers to duplicate names
$store = new Store(Store::DUP_APPEND_NUM);

// Overwrite duplicate names
$store = new Store(Store::DUP_OVERWRITE);

// Strict mode: throw exceptions on invalid entries
$store = new Store(Store::STRICT);

// Combine options
$store = new Store(Store::DUP_APPEND_NUM | Store::STRICT);
```

Architecture
------------

[](#architecture)

### Core Components

[](#core-components)

- **Store** - Main interface for adding files and opening archives. Call `open()` at any point to snapshot the current entry list into an `OpenedStore`; the `Store` remains open for further additions.
- **OpenedStore** - Seekable read view over a point-in-time snapshot of a `Store`. Each call to `Store::open()` returns an independent instance with its own cursor position.
- **Entry** - Represents a single file in the archive
- **LocalHeader** - ZIP local file header structure
- **CentralDirectory** - ZIP central directory (file index)
- **EndOfCentralDirectory** - ZIP End of Central Directory record
- **ZipStoreEntryFile** - Interface for custom file sources

Examples
--------

[](#examples)

### Simple File Download Server

[](#simple-file-download-server)

```
