Zip
Read and write ZIP archives without libzip or ZipArchive. Stored entries are pure PHP; Deflate entries use PHP's zlib functions. Entries stream one at a time, while ZIP metadata such as the central directory is still held in memory.
composer require wp-php-toolkit/zip
Common PHP ZIP workflows rely on the ZipArchive extension or shelling out to zip. Those are awkward in hosts without libzip, WebAssembly builds, and code paths that need to stream archive data through toolkit byte streams.
The Zip component reads and writes Stored and Deflate archives without ZipArchive. The decoder is pull-based for entry bodies, but ZipFilesystem indexes the central directory in memory and currently rejects archives whose central directory exceeds 2 MB. The encoder accepts any ByteWriteStream as a sink and writes one entry at a time.
Read a file out of a ZIP
ZipFilesystem implements this toolkit's Filesystem interface, so once you wrap the byte reader you can call get_contents(), ls(), and is_dir() just like the other read backends.
Try this: after Run, add a second append_file() call before $enc->close() for a notes.md entry, then call print_r( $zip->ls( '/' ) ) at the end. The directory listing reflects the new entry without re-reading the file.
Build an EPUB from scratch
An EPUB follows one strict ZIP rule: write the mimetype entry first and store it without compression. Deflate the rest of the archive normally.