PHP code example of hanfy / batch-zip-stream

1. Go to this page and download the library: Download hanfy/batch-zip-stream library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

hanfy / batch-zip-stream example snippets






use BatchZipStream\BatchZipSession;

$session = new BatchZipSession('/path/to/state', '/path/to/output.zip');

$session->startSession('my-archive');
$session->addFileFromString('hello.txt', 'Hello, World!');
$session->addFileFromString('data/config.json', '{"key": "value"}');
$session->finalize();

use BatchZipStream\BatchZipSession;

// Batch 1: Start session and add files
$session = new BatchZipSession('/path/to/state', '/path/to/output.zip');
$session->startSession('unique-session-id');
$writer = $session->getWriter();
$writer->addFileFromString('file1.txt', 'Content 1');
$session->saveProgress();
$session->close();

// ... execution ends ...

// Batch 2: Resume and add more files
$session = new BatchZipSession('/path/to/state', '/path/to/output.zip');
$session->startSession('unique-session-id'); // Resumes existing session
$writer = $session->getWriter();
$writer->addFileFromString('file2.txt', 'Content 2');
$session->saveProgress();
$session->close();

// ... execution ends ...

// Final Batch: Finalize
$session = new BatchZipSession('/path/to/state', '/path/to/output.zip');
$session->startSession('unique-session-id');
$session->finalize();

use BatchZipStream\BatchZipSession;
use BatchZipStream\Streams\FileReadableStream;

$session = new BatchZipSession('/path/to/state', '/path/to/output.zip');
$session->startSession('large-archive');

// Stream a large file (never fully loaded into memory)
$source = new FileReadableStream('/path/to/large-file.bin');
$session->addFileFromStream('large-file.bin', $source);

$session->finalize();

use BatchZipStream\BatchZipSession;

$session = new BatchZipSession('/path/to/state', '/path/to/output.zip');
$session->startSession('backup-session-12345');

// Add files (can be 1 million+ files)
foreach ($filesToBackup as $file) {
    $session->addFile(
        $file->getArchivePath(),
        $file->getSourcePath()
    );
}

// Save progress (entries are already persisted, just saves state)
$session->saveProgress();

// In the final batch, finalize
$session->finalize('Backup completed');

use BatchZipStream\BatchZipSession;

// Stream factory receives bool $append parameter
$session = BatchZipSession::withStreamFactory(
    '/path/to/state',
    fn(bool $append) => new S3MultipartStream('bucket', 'key', $append)
);

$session->startSession('cloud-backup');
$writer = $session->getWriter();
$writer->addFileFromString('hello.txt', 'Hello from cloud!');
$session->finalize();

$stream = new MyCloudStream(...);

$session = BatchZipSession::withStream(
    '/path/to/state',
    $stream
);

$session->startSession('my-session');
$writer = $session->getWriter();
// ... add files ...
$session->finalize();

use BatchZipStream\BatchZipSession;
use BatchZipStream\Streams\MemoryWritableStream;

$memory = new MemoryWritableStream();

$session = BatchZipSession::withStream('/tmp/state', $memory);
$session->startSession('memory-test');
$writer = $session->getWriter();
$writer->addFileFromString('test.txt', 'In-memory content');
$session->finalize();

// Get raw ZIP bytes
$zipBytes = $memory->getBuffer();

// Send directly over HTTP
header('Content-Type: application/zip');
header('Content-Length: ' . strlen($zipBytes));
echo $zipBytes;

use BatchZipStream\Streams\StringReadableStream;

$session = new BatchZipSession($stateDir, $archivePath);
$session->startSession('stream-input');

// From a string stream
$content = new StringReadableStream('file content', 'virtual.txt');
$session->addFileFromStream('output.txt', $content);

// From an HTTP stream (custom implementation)
$httpSource = new HttpReadableStream('https://example.com/data.json');
$session->addFileFromStream('remote/data.json', $httpSource);

$session->finalize();

new FileEntry(
    filename: 'path/to/file.txt',     // Path in ZIP (UTF-8, forward slashes)
    crc32: 0x12345678,                // CRC-32 of uncompressed data
    compressedSize: 1000,             // Size after compression
    uncompressedSize: 2000,           // Original file size
    localHeaderOffset: 0,             // Byte offset of local header
    compressionMethod: 8,             // 0=store, 8=deflate
    dosTime: 0x5678ABCD,              // DOS timestamp
    generalPurposeBitFlag: 0x0800,    // Flags (e.g., UTF-8)
    versionNeeded: 0x14,              // Version needed to extract
    

// File-based output
$session = new BatchZipSession($stateDir, $archivePath);

// Custom stream factory
$session = BatchZipSession::withStreamFactory(
    $stateDir,
    fn(bool $append) => new MyStream($append)
);

// Pre-created stream
$session = BatchZipSession::withStream($stateDir, $stream);

// Custom persistence
$session = BatchZipSession::withPersistence($persistence, $archivePath);

$session->startSession($sessionId);       // Start or resume session
$writer = $session->getWriter();          // Get the BatchZipWriter instance
$session->addFile($path, $sourcePath, $compressionMethod, $encryptionMethod, $password); // Add file from filesystem
$session->addFileFromString($path, $content, $compressionMethod, $encryptionMethod, $password); // Add file from string
$session->addFileFromStream($path, $stream, $compressionMethod, $modificationTime); // Add file from stream
$session->addEmptyDirectory($path, $modificationTime); // Add empty directory
$session->saveProgress();                 // Persist state
$session->finalize($comment);             // Complete archive
$session->cleanup();                      // Remove state files and close
$session->abort($reason, $deleteArchive); // Mark as failed and close
$session->getStream();                    // Get output stream
$session->getState();                     // Get ArchiveState instance
$session->getStats();                     // Get session statistics
$session->exists($sessionId);             // Check if session exists
$session->cleanupOldSessions($maxAgeSeconds); // Clean up stale sessions
$session->listSessions();                 // List active session IDs
$session->close();                        // Close streams/locks without deleting state

use BatchZipStream\BatchZipWriter;
use BatchZipStream\State\ArchiveState;
use BatchZipStream\State\FileEntryStore;

$state = new ArchiveState('session-id');
$entryStore = new FileEntryStore('/path/to/session.entries');

$writer = new BatchZipWriter($stream, $state, $entryStore);

$writer->addFileFromString('file.txt', 'content');
$writer->addFile('data.bin', $sourceStream);

$writer->finalize('Archive comment');
$writer->close();

new BatchZipWriter(
    WritableStreamInterface $stream,    // Output stream
    ArchiveState $state,                // Archive state
    FileEntryStore $entryStore,         // Entry store
    int $compressionLevel = 6,          // Deflate level (0-9)
    int $chunkSize = 65536              // Read chunk size
);

use BatchZipStream\Persistence\FileStatePersistence;

$persistence = new FileStatePersistence('/path/to/states');

// Create session
$session = $persistence->create('session-id');
$state = $session['state'];
$entryStore = $session['entryStore'];

// Save state (tiny ~500 bytes)
$persistence->save('session-id', $state);

// Load session
$session = $persistence->load('session-id');

// Clean up all session files
$persistence->delete('session-id');

class RedisStatePersistence implements StatePersistenceInterface
{
    public function create(string $sessionId): array
    {
        $state = new ArchiveState($sessionId);
        $entryStore = new FileEntryStore($this->getEntryPath($sessionId));
        $entryStore->open(true);
        return ['state' => $state, 'entryStore' => $entryStore];
    }

    public function load(string $sessionId): ?array
    {
        $json = $this->redis->get("zip:state:$sessionId");
        if ($json === null) return null;
        
        $state = ArchiveState::fromJson($json);
        $entryStore = new FileEntryStore($this->getEntryPath($sessionId));
        $entryStore->open(false);
        return ['state' => $state, 'entryStore' => $entryStore];
    }
    
    public function save(string $sessionId, ArchiveState $state): void
    {
        $this->redis->set("zip:state:$sessionId", $state->toJson());
    }
    
    // ... other methods
}

try {
    $writer->addFile('file.txt', $source);
} catch (WriteFailureException $e) {
    // Archive is now invalid
    $state = $writer->getState();
    assert($state->isFailed());
    
    // Cleanup
    unlink($zipPath);
}

$session = new BatchZipSession($stateDir, $archivePath);
$session->startSession('large-archive');

// Add many files
for ($i = 0; $i < 70000; $i++) {
    $session->addFileFromString("file-$i.txt", "content");
}

// ZIP64 is automatically enabled
$state = $session->getState();
assert($state->

use BatchZipStream\BatchZipSession;
use BatchZipStream\Core\ZipFormat;

$globalPassword = 'my-global-secret';
$session = new BatchZipSession(
    $stateDir,
    $archivePath,
    6,            // Compression level
    65536,        // Chunk size
    null,         // Custom state persistence
    $globalPassword
);

$session->startSession('encrypted-archive');

// 1. Encrypt with WinZip AES-256 (recommended) using the global password
$session->addFileFromString(
    'secret.txt',
    'Top Secret Content',
    ZipFormat::COMPRESSION_DEFLATE,
    ZipFormat::ENC_AES_256
);

// 2. Encrypt with Traditional PKWARE encryption using the global password
$session->addFile(
    'legacy.txt',
    '/path/to/local-file.txt',
    ZipFormat::COMPRESSION_DEFLATE,
    ZipFormat::ENC_TRADITIONAL
);

// 3. Keep a file public (unencrypted) in the same archive
$session->addFileFromString(
    'public.txt',
    'This is readable by anyone',
    ZipFormat::COMPRESSION_DEFLATE,
    ZipFormat::ENC_NONE
);

$session->finalize();

// Encrypt using traditional PKWARE with a custom password instead of the global one
$session->addFileFromString(
    'override.txt',
    'Custom Password Protected Content',
    ZipFormat::COMPRESSION_DEFLATE,
    ZipFormat::ENC_TRADITIONAL,
    'file-specific-password'
);

// When using the writer directly:
$writer = $session->getWriter();
$writer->addFileFromString(
    'custom-aes.txt',
    'AES-256 with custom password',
    ZipFormat::COMPRESSION_DEFLATE,
    null, // modificationTime
    ZipFormat::ENC_AES_256,
    'custom-aes-password'
);

class S3MultipartStream implements WritableStreamInterface
{
    public function write(string $data): int
    {
        // Buffer and upload parts
        $this->buffer .= $data;
        
        if (strlen($this->buffer) >= 5 * 1024 * 1024) {
            $this->uploadPart($this->buffer);
            $this->buffer = '';
        }
        
        return strlen($data);
    }
    
    public function close(): void
    {
        if ($this->buffer !== '') {
            $this->uploadPart($this->buffer);
        }
        $this->completeMultipartUpload();
    }
}

use BatchZipStream\Streams\MemoryWritableStream;

$memory = new MemoryWritableStream();

$session = BatchZipSession::withStream('/state', $memory);
$session->startSession('test');
$session->addFileFromString('test.txt', 'Hello!');
$session->finalize();

// Access the buffer
$zipBytes = $memory->getBuffer();  // Raw ZIP bytes
$length = $memory->getLength();     // Total bytes written

// Reset for reuse
$memory->reset();

use BatchZipStream\Streams\FileWritableStream;

$stream = new FileWritableStream('/path/to/archive.zip');
$stream->write($data);
$stream->flush();
$stream->close();

use BatchZipStream\Streams\BufferedWritableStream;

$buffered = new BufferedWritableStream($innerStream, 65536);

use BatchZipStream\Streams\CallbackWritableStream;

$stream = new CallbackWritableStream(function(string $data) use ($s3) {
    $s3->appendToObject($data);
    return strlen($data);
});

class HttpReadableStream implements ReadableStreamInterface
{
    public function __construct(string $url)
    {
        $this->stream = fopen($url, 'rb');
    }
    
    public function read(int $length): string
    {
        return fread($this->stream, $length);
    }
    
    public function eof(): bool
    {
        return feof($this->stream);
    }
}

$session = new BatchZipSession(
    $stateDir,
    $archivePath,
    compressionLevel: 6,     // 0=fastest, 9=best compression
    chunkSize: 131072        // 128KB chunks for faster I/O
);

use BatchZipStream\Streams\BufferedWritableStream;

$inner = new FileWritableStream($path);
$buffered = new BufferedWritableStream($inner, 1048576); // 1MB buffer

$session = BatchZipSession::withStream($stateDir, $buffered);