php-archive
A pure-PHP library for reading, extracting, and creating TAR and ZIP archives with no native extensions required.
Repository Health
Technical Analysis
PHP-Archive gives PHP applications the ability to open, list, extract, and build TAR and ZIP archives without depending on the ext-zip, ext-tar, or other native archive extensions that are frequently missing or disabled on shared hosting. It ships two focused classes, Tar and Zip, both extending a shared abstract Archive base, so the same open/contents/extract/create/addFile/addData/close workflow applies to either format.
The TAR implementation understands POSIX ustar and GNU longlink formats for long path names, resolves PAX extended headers when reading, and supports gzip and bzip2 compression through PHP’s zlib and bz2 extensions when available. The ZIP implementation records and restores per-file character encoding so names round-trip correctly as UTF-8. A generator-based yieldContents() API lets callers stream large archives entry by entry instead of loading the full table of contents into memory at once, and a setCallback() hook reports progress during long add/extract operations.
It is maintained by Andreas Gohr, the author of DokuWiki, and is used inside DokuWiki itself for plugin and media archive handling, alongside general-purpose use in any PHP project that needs dependable archive support with minimal system requirements.
What You Get
- A shared
Archiveabstract base class defining a consistent open/contents/extract/create/addFile/addData/close API - A
Tarclass supporting POSIX ustar, GNU longlink long-path handling, and PAX extended headers on read - A
Zipclass with per-entry UTF-8 filename encoding and flagging - Gzip and bzip2 compression support for TAR archives via
setCompression() - A memory-efficient generator API (
yieldContents()/readCurrentEntry()) for streaming large archives - A
FileInfoclass for specifying or inspecting per-entry metadata (path, size, mode, owner, mtime) - Progress callbacks via
setCallback()fired on every file added or extracted
Common Use Cases
- Extracting plugin, theme, or media bundles distributed as .tar.gz or .zip on shared hosting without native archive extensions
- Building downloadable .tar.bz2 or .zip export bundles from application data on the fly, in memory or streamed to disk
- Reading the file listing of an uploaded archive before extracting it, to validate contents or reject unsafe entries
- Migrating or backing up file trees into a single portable archive format from a PHP CLI script or web job
- Powering plugin/package managers (as in DokuWiki) that need to unpack third-party .tar or .zip distributions safely
Under The Hood
Architecture
The library is organized around a small abstract Archive base class (src/Archive.php) that declares the shared contract — setCompression, open, contents, extract, create, addFile, addData, close, getArchive, save — implemented independently by Tar (src/Tar.php) and Zip (src/Zip.php). Each format class owns its own low-level byte-stream handling (readbytes/writebytes/skipbytes for Tar), header encoding/decoding, and compression stream selection (gzopen/bzopen/fopen), so the two formats share only the public contract, not implementation. Metadata about individual entries is carried in a separate FileInfo value object, decoupling per-file attributes (path, size, mode, owner, mtime) from the archive-format-specific reading and writing logic. This keeps the abstraction changeable per-format — extending the library to a third archive format would mean implementing the same Archive contract without touching Tar or Zip — while a caller using contents()/extract()/addFile() never needs to know which concrete class it holds.
Tech Stack
Pure PHP with no required runtime extensions beyond core; ext-zlib and ext-bz2 are optional and only needed if gzip/bzip2 compression is used, ext-iconv or ext-mbstring are suggested for filename encoding edge cases. Composer is the sole build/dependency tool (PSR-4 autoloading under the splitbrain\PHPArchive namespace), targeting PHP 7.0+. Development dependencies are phpunit/phpunit (^8) for testing and mikey179/vfsstream for a virtual filesystem in tests, plus ext-zip and ext-bz2 as dev-only requirements for exercising all code paths. No web framework, ORM, or database involved — this is a self-contained, dependency-minimal utility library by design, matching its goal of working on constrained hosting.
Code Quality
The repository has an active PHPUnit test suite (tests/TarTestCase.php, tests/ZipTestCase.php, tests/FileInfoTest.php) backed by real fixture archives (.tar, .tgz, .tbz, .zip files with PAX headers, long paths, symlinks, and Windows/WinRAR-produced archives for compatibility edge cases) plus a virtual filesystem via vfsStream to avoid touching disk for I/O assertions. Tests conditionally enable gzip/bzip2 coverage only when those extensions are loaded, and cover format edge cases like GNU longlink names, PAX global/local headers, and legacy UTF-8 path flags. A GitHub Actions workflow (.github/workflows/test.yml) runs CI on pushes. Error handling is explicit and typed: three dedicated exception classes (ArchiveIOException, ArchiveCorruptedException, ArchiveIllegalCompressionException, FileInfoException) are thrown for I/O failures, checksum mismatches, and invalid compression settings rather than silently failing or returning false. Method and property naming is consistent camelCase with docblocks throughout; the code favors defensive @-suppressed native calls paired with explicit exception throws on failure, a deliberate low-level-I/O pattern rather than an oversight.
What Makes It Unique
Unlike PHP’s native ZipArchive/PharData, which require the zip, phar, or bz2/zlib PHP extensions to be compiled in and enabled, PHP-Archive implements the TAR and ZIP binary formats itself, so it runs on any PHP 7+ install regardless of which optional extensions the host has enabled — a common constraint on cheap or locked-down shared hosting. Its generator-based yieldContents() streaming API is also a deliberate memory-efficiency choice over the array-returning contents(), letting callers process archives far larger than available memory would otherwise allow. The TAR reader’s support for GNU longlink and PAX extended headers (with global-header inheritance and per-entry override semantics) goes beyond what many minimal pure-PHP tar readers implement, aiming for compatibility with archives produced by modern GNU tar.