cloud-castle / archive
Потоковая работа с 22 форматами архивов на чистом PHP 8.1+ (ZIP, 7z, TAR, tar.zst, ISO, RAR, CAB, CPIO, DEB, PHAR) — streaming archive library for PHP without mandatory extensions.
Requires
- php: >=8.1
- cloud-castle/file-system: ^1.1
Requires (Dev)
- deptrac/deptrac: ^3.0 || ^4.0
- ergebnis/composer-normalize: ^2.45
- friendsofphp/php-cs-fixer: ^3.75
- icanhazstring/composer-unused: ^0.9
- maennchen/zipstream-php: ^3.1
- nelexa/zip: ^4.0
- pear/archive_tar: ^1.5
- php-parallel-lint/php-parallel-lint: ^1.4
- phpmd/phpmd: ^2.15
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^1.12 || ^2.1
- phpstan/phpstan-deprecation-rules: ^1.2 || ^2.0
- phpstan/phpstan-phpunit: ^1.4 || ^2.0
- phpstan/phpstan-strict-rules: ^1.6 || ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- psalm/plugin-phpunit: ^0.19 || ^0.20
- rector/rector: ^1.2 || ^2.0
- roave/security-advisories: dev-latest
- splitbrain/php-archive: ^1.4
- squizlabs/php_codesniffer: ^3.12 || ^4.0
- vimeo/psalm: ^6.0
- wapmorgan/unified-archive: ^1.2
- webmozart/assert: ^1.11
Suggests
- ext-brotli: Форматы .br и tar.br: без расширения они недоступны
- ext-bz2: Форматы .bz2 и tar.bz2, а также сжатые записи PHAR
- ext-rar: Чтение RAR без системной утилиты unrar
- ext-xz: Запись .xz и tar.xz (чтение работает собственным декодером)
- ext-zip: Ускоряет работу с ZIP на больших архивах
- ext-zstd: Форматы .zst и tar.zst: без расширения они недоступны
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-28 21:02:59 UTC
README
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano
CloudCastle Archive
22 формата архивов в одном пакете на чистом PHP. Потоково, без временных файлов, с памятью порядка размера чанка — а не размера архива.
use CloudCastle\Archive\Archive;
// Упаковать каталог — формат выбирается по расширению
Archive::pack('/var/www/project', '/backup/project.tar.gz');
// Распаковать что угодно — формат определяется по сигнатуре
Archive::extract('/incoming/delivery.7z', '/data/unpacked');
// Перепаковать из формата в формат, не разворачивая архив на диск
Archive::convert('/incoming/delivery.7z', '/data/delivery.zip');
Содержание
- Зачем этот пакет
- Установка
- Быстрый старт
- Поддерживаемые форматы
- Возможности
- Сравнение с аналогами
- Производительность
- Потребление памяти
- Безопасность
- Качество кода
- Честно о плюсах и минусах
- Когда его стоит брать
- Документация
Зачем этот пакет
Библиотеки архивации в PHP обычно решают одну задачу: работают с одним-двумя
форматами, требуют расширений (ext-zip, ext-rar) или внешних утилит, а
большие архивы разворачивают в памяти целиком. CloudCastle Archive устроен иначе:
- Один фасад на все форматы.
Archive::pack(),Archive::extract(),Archive::convert()работают одинаково для ZIP, 7z, tar.zst, ISO и остальных. - Потоковость как основа. Внутри всё построено на генераторах: архив читается и пишется кусками, поэтому 50-гигабайтный образ обрабатывается на том же лимите памяти, что и файл на мегабайт.
- Собственные кодеки. LZMA/LZMA2, XZ, LZ4, BCJ и Delta реализованы на чистом PHP — 7z и tar.xz читаются там, где никаких расширений нет.
- Безопасность по умолчанию. Zip-slip, архивные бомбы, символические ссылки и подделанные заголовки блокируются без дополнительной настройки.
Установка
composer require cloud-castle/archive
Требуется PHP 8.1+; ни одно расширение не входит в зависимости пакета.
ZIP, TAR, tar.gz, tar.lz4, 7z, ISO, CAB, CPIO, AR/DEB и PHAR работают на
голом PHP — включая чтение LZMA, LZMA2 и XZ собственными декодерами.
Остальное зависит от окружения: tar.xz читается без расширений, а
записывается через ext-xz; tar.bz2, tar.zst и tar.br требуют
ext-bz2, ext-zstd и ext-brotli соответственно; RAR читается через
ext-rar либо системный unrar. Чего нет в окружении — о том пакет
сообщает явной ошибкой, а не молчаливой порчей архива; полная таблица
зависимостей — в справочнике форматов.
Быстрый старт
use CloudCastle\Archive\Archive;
use CloudCastle\Archive\ArchiveOptions;
use CloudCastle\Archive\EncryptionMethod;
// Собрать архив по частям
Archive::create('/tmp/report.zip')
->addFile('/data/report.pdf', 'docs/report.pdf')
->addDirectory('/data/images', 'images')
->addFromString('meta.json', json_encode($meta, JSON_THROW_ON_ERROR))
->finish();
// Прочитать, не распаковывая на диск
$reader = Archive::open('/tmp/report.zip');
foreach ($reader->files() as $entry) {
echo $entry->name, ' — ', $entry->size, " байт\n";
}
$json = $reader->read('meta.json');
$reader->close();
// Правка готового архива: удалить, переименовать, заменить, дописать
Archive::edit('/tmp/report.zip')
->delete('docs/draft.pdf')
->rename('meta.json', 'meta/report.json')
->save();
// Зашифрованный архив: WinZip AES-256
$options = ArchiveOptions::default()->withPassword('секрет', EncryptionMethod::Aes256);
Archive::pack('/data/private', '/backup/private.zip', null, $options);
Поддерживаемые форматы
| Семейство | Форматы | Чтение | Запись |
|---|---|---|---|
| ZIP | .zip (Zip64, ZipCrypto, WinZip AES-128/192/256) | ✅ | ✅ |
| TAR | .tar (ustar, PAX, GNU), .tar.gz, .tar.bz2, .tar.xz, .tar.zst, .tar.lz4, .tar.br | ✅ | ✅ |
| 7-Zip | .7z (LZMA, LZMA2, Copy, Delta, BCJ, солид-блоки, AES-256 с шифрованием заголовка) | ✅ | ✅ |
| RAR | .rar (через ext-rar либо системный unrar) | ✅ | — |
| Образы | .iso (ISO 9660, Joliet, Rock Ridge) | ✅ | ✅ |
| Пакеты | .deb, .ar, .cpio (newc/odc), .cab, .phar | ✅ | ✅ |
| Одиночные | .gz, .bz2, .xz, .zst, .lz4, .br | ✅ | ✅ |
Знаки в таблице описывают возможности пакета; tar.bz2, tar.zst, tar.br
и запись tar.xz дополнительно требуют расширений PHP. Зависимости по каждому
формату и его особенности — в
справочнике форматов.
Возможности
| Возможность | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Форматы чтения | |||||||
| ZIP | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | 🏆 archive, unified-archive, zip, php-archive |
| TAR (ustar/PAX/GNU) | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | 🏆 archive, unified-archive, php-archive, archive_tar |
| tar.gz / tgz | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | 🏆 archive, unified-archive, php-archive, archive_tar |
| tar.bz2 | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | 🏆 archive, unified-archive, php-archive, archive_tar |
| tar.xz | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | 🏆 archive, unified-archive |
| tar.zst | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| tar.lz4 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| tar.br (brotli) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| 7z | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| RAR | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| CAB | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| ISO 9660 (+Joliet, Rock Ridge) | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| CPIO (newc/odc) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| AR / DEB | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| PHAR (без ext-phar) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Одиночные gz/bz2/xz/zst/lz4/br | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Форматы записи | |||||||
| Запись ZIP | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | 🏆 archive, unified-archive, zip, php-archive, zipstream-php |
| Запись TAR и tar.* | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | 🏆 archive, unified-archive, php-archive, archive_tar |
| Запись 7z | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Запись CAB | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Запись ISO 9660 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Запись CPIO | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Запись AR/DEB | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Запись PHAR | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Потоковость и память | |||||||
| Чтение генераторами (O(chunk)) | ✅ | ❌ | 🟡 | 🟡 | ❌ | ❌ | 🏆 archive |
| Запись генераторами (O(chunk)) | ✅ | ❌ | 🟡 | ❌ | ✅ | ❌ | 🏆 archive, zipstream-php |
| Архив больше доступной памяти | ✅ | ❌ | 🟡 | 🟡 | ✅ | ❌ | 🏆 archive, zipstream-php |
| Запись в сетевой поток без файла | ✅ | ❌ | 🟡 | ❌ | ✅ | ❌ | 🏆 archive, zipstream-php |
| Zip64 для потоков неизвестной длины | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | 🏆 archive, zip, zipstream-php |
| Шифрование | |||||||
| ZipCrypto | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| WinZip AES-128/192/256 | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| Проверка HMAC при распаковке | ✅ | ❌ | 🟡 | ❌ | ❌ | ❌ | 🏆 archive |
| Чтение зашифрованных 7z (AES-256) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Чтение зашифрованных RAR | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Шифрование заголовка 7z (-mhe=on) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Безопасность | |||||||
| Защита от zip-slip | ✅ | 🟡 | ✅ | 🟡 | ❌ | ❌ | 🏆 archive, zip |
| Лимит числа записей | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Лимит распакованного объёма | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Лимит степени сжатия (архивные бомбы) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Политика символических ссылок | ✅ | ❌ | 🟡 | ❌ | ❌ | ❌ | 🏆 archive |
| Запуск внешних утилит без шелла | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Отказ от unserialize при чтении PHAR | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Работа с путями и записями | |||||||
| Абсолютные и относительные пути | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 🏆 archive, unified-archive, zip, php-archive, zipstream-php, archive_tar |
| Каталоги, пустые каталоги | ✅ | ✅ | ✅ | ✅ | 🟡 | ✅ | 🏆 archive, unified-archive, zip, php-archive, archive_tar |
| Символические ссылки | ✅ | ❌ | 🟡 | ❌ | ❌ | ✅ | 🏆 archive, archive_tar |
| Права и метки времени | ✅ | 🟡 | ✅ | 🟡 | 🟡 | ✅ | 🏆 archive, zip, archive_tar |
| Комментарии архива и записей | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| Фильтрация записей при упаковке | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| Отчёт о прогрессе | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Операции | |||||||
| Конвертация формат → формат | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Автоопределение формата по сигнатуре | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Проверка целостности (test) | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| Единый фасад для всех форматов | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | 🏆 archive, unified-archive |
| Сжатие и распаковка одиночных файлов | ✅ | 🟡 | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Удаление записей из готового архива | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, unified-archive, zip |
| Переименование записей | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| Замена содержимого записи | ✅ | 🟡 | ✅ | ❌ | ❌ | ❌ | 🏆 archive, zip |
| Дописывание в готовый архив | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | 🏆 archive, unified-archive, zip, archive_tar |
| Правка архива потоком, без распаковки | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Консольная утилита | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | 🏆 archive, unified-archive |
| Качество и сопровождение | |||||||
| Строгая типизация (strict_types) | ✅ | ❌ | ✅ | 🟡 | ✅ | ❌ | 🏆 archive, zip, zipstream-php |
| PHPStan max / Psalm level 1 | ✅ | ❌ | 🟡 | ❌ | 🟡 | ❌ | 🏆 archive |
| Работает без внешних утилит | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | 🏆 archive, zip, php-archive, zipstream-php, archive_tar |
| Без обязательных ext-расширений | ✅ | ❌ | ❌ | 🟡 | ✅ | 🟡 | 🏆 archive, zipstream-php |
| Итого возможностей | 64 | 13 | 18 | 9 | 9 | 10 | 🏆 archive |
Сравнение с аналогами
Сравнение идёт с пятью самыми распространёнными PHP-пакетами архивации.
Таблицы ниже собираются автоматически (composer docs:sync) из фактических
прогонов, а не из обещаний документации.
| Пакет | Версия |
|---|---|
cloud-castle/archive | v1.1.0 |
wapmorgan/unified-archive | 1.3.1 |
nelexa/zip | 4.0.2 |
splitbrain/php-archive | 1.5.1 |
maennchen/zipstream-php | 3.1.1 |
pear/archive_tar | 1.6.1 |
Производительность
Замеры воспроизводятся командой composer bench: каждый участник каждого
сценария выполняется в отдельном процессе, участники чередуются раунд за
раундом, берётся лучшее время. Так дрейф фоновой нагрузки не достаётся
целиком одному пакету.
| Сценарий (мс, меньше — лучше) | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Упаковка каталога в ZIP (120 файлов, ~6 МиБ) | 69.75 | 46.50 | 134.03 | 189.53 | 110.13 | — | 🏆 unified-archive |
| Распаковка ZIP (120 файлов, ~6 МиБ) | 61.38 | 22.39 | 56.99 | 79.07 | — | — | 🏆 unified-archive |
| Упаковка файла 64 МиБ в tar.gz | 1 872.02 | 1 786.57 | — | 1 475.11 | — | 2 604.96 | 🏆 php-archive |
| Упаковка каталога в tar.gz (120 файлов, ~6 МиБ) | 89.48 | 800.12 | — | 167.21 | — | 318.15 | 🏆 archive |
Как это читать. В сценариях с ZIP выигрывает unified-archive, и
причина известна: для ZIP он вызывает расширение ext-zip, где вся
работа — чтение файла, подсчёт CRC, сжатие и запись — выполняется кодом
на C. Обогнать это на чистом PHP невозможно, и мы этого не обещаем.
Значимо другое: среди реализаций, которые действительно работают на PHP,
наш пакет быстрее всех — вдвое быстрее nelexa/zip и splitbrain/php-archive
на упаковке ZIP и в 1.8–3.5 раза быстрее на tar.gz. А там, где ext-zip
нет, альтернатива у него отсутствует вовсе: unified-archive без
расширения ZIP просто не создаст.
Потребление памяти
Цифра — пик всего процесса, а не прибавка сверх него: PHP занимает около пяти с половиной мебибайт ещё до начала работы, и сравнивать имеет смысл именно итог. Одинаковые значения означают, что работа не подняла пик выше стартового — на файле в 64 МиБ это и есть признак потоковости.
| Сценарий (МиБ, меньше — лучше) | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Упаковка каталога в ZIP (120 файлов, ~6 МиБ) | 6.98 | 6.98 | 8.32 | 6.98 | 21.74 | — | 🏆 archive, unified-archive, php-archive |
| Распаковка ZIP (120 файлов, ~6 МиБ) | 6.98 | 6.98 | 6.98 | 6.98 | — | — | 🏆 archive, unified-archive, zip, php-archive |
| Упаковка файла 64 МиБ в tar.gz | 6.98 | 6.98 | — | 7.45 | — | 6.98 | 🏆 archive, unified-archive, archive_tar |
| Упаковка каталога в tar.gz (120 файлов, ~6 МиБ) | 6.98 | 13.01 | — | 6.98 | — | 6.98 | 🏆 archive, php-archive, archive_tar |
Пик — половина картины. Вторая половина — утечки: сколько памяти не возвращается после десятков однотипных операций подряд. Процесс, обрабатывающий архивы часами, падает именно от этого.
| Сценарий (КиБ за серию, меньше — лучше) | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Упаковка каталога в ZIP (120 файлов, ~6 МиБ) | 0.37 | 0.37 | 0.37 | 0.37 | 0.37 | — | 🏆 archive, unified-archive, zip, php-archive, zipstream-php |
| Распаковка ZIP (120 файлов, ~6 МиБ) | 0.37 | 0.37 | 0.37 | 0.37 | — | — | 🏆 archive, unified-archive, zip, php-archive |
| Упаковка файла 64 МиБ в tar.gz | 0.37 | 26.07 | — | 0.37 | — | 0.37 | 🏆 archive, php-archive, archive_tar |
| Упаковка каталога в tar.gz (120 файлов, ~6 МиБ) | 0.37 | 78.24 | — | 0.37 | — | 0.37 | 🏆 archive, php-archive, archive_tar |
Безопасность
Каждая защита включена по умолчанию и проверяется тестами набора security:
- Zip-slip. Имена записей нормализуются, выход за пределы каталога назначения отклоняется до открытия файла.
- Архивные бомбы. Лимиты на число записей, суммарный распакованный объём
и степень сжатия (
withMaxEntries,withMaxTotalSize,withMaxRatio). - Символические ссылки. Политика
SymlinkPolicy: пропустить, отклонить или распаковать с проверкой цели. - Шифрование. В ZIP пароль сначала сверяется двухбайтовым
верификатором, а код аутентификации HMAC-SHA1 проверяется по окончании
записи — так устроен формат WinZip AES. Зашифрованные 7z читаются
целиком, включая архивы с зашифрованным заголовком (
-mhe=on). - Внешние утилиты. Запускаются без командной оболочки, аргументы передаются массивом — инъекция команд невозможна.
- PHAR. Читается собственным парсером без
unserialize().
| Стандарт | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| SECURITY.md с политикой раскрытия | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | 🏆 archive, zipstream-php, archive_tar |
| Реакция на security advisories | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| composer audit в CI | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | 🏆 archive, zipstream-php |
| Статический анализ безопасности | ✅ | ❌ | ❌ | ❌ | ✅ | ❌ | 🏆 archive, zipstream-php |
| Защита от CWE-22 (обход пути) | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | 🏆 archive, unified-archive, zip, archive_tar |
| Защита от CWE-409 (архивные бомбы) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Защита от CWE-502 (десериализация) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 🏆 archive, unified-archive, zip, php-archive, zipstream-php, archive_tar |
| Защита от CWE-78 (инъекция команд) | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | 🏆 archive, zip, php-archive, archive_tar |
| Проверка целостности при распаковке | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | 🏆 archive, unified-archive, zip, php-archive, zipstream-php, archive_tar |
Качество кода
| Метрика | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Строгая типизация во всех файлах | 100% | 0% | 100% | 0% | 100% | 0% | 🏆 archive, zip, zipstream-php |
| Уровень PHPStan | max | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Уровень Psalm | 1 | ❌ | ❌ | ❌ | 1 | ❌ | 🏆 archive, zipstream-php |
| Покрытие тестами, строки | 100.00% | — | — | — | — | — | 🏆 archive |
| Мутационный индекс (MSI) | 100.00% | — | — | — | — | — | 🏆 archive |
| Слоевые правила (deptrac) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 🏆 archive |
| Публичный API задокументирован | 99% | 75% | 68% | 99% | 72% | 98% | 🏆 archive, php-archive |
Замечания анализаторов
Каждый пакет прогнан одними и теми же инструментами с общепризнанными наборами правил — PSR-12 у PHPCS и стандартные наборы PHPMD, — а не нашими конфигами: иначе это была бы проверка чужого кода на соответствие нашим вкусам. Счёт нормирован на тысячу строк.
| Проверка (замечаний на 1000 строк, меньше — лучше) | archive | unified-archive | zip | php-archive | zipstream-php | archive_tar | 🏆 Победитель |
|---|---|---|---|---|---|---|---|
| Стиль PSR-12 (PHPCS) | 0.00 | 93.52 | 3.74 | 49.80 | 10.10 | 78.85 | 🏆 archive |
| Размер кода (PHPMD) | 3.54 | 4.66 | 3.81 | 5.95 | 3.21 | 15.53 | 🏆 zipstream-php |
| Дизайн (PHPMD) | 0.37 | 0.35 | 0.31 | 0.00 | 0.92 | 0.40 | 🏆 php-archive |
| Именование (PHPMD) | 1.75 | 2.57 | 3.27 | 4.09 | 19.27 | 4.38 | 🏆 archive |
| Мёртвый код (PHPMD) | 0.00 | 5.36 | 1.01 | 0.00 | 0.00 | 2.79 | 🏆 archive, php-archive, zipstream-php |
| Чистый код (PHPMD) | 37.86 | 21.46 | 12.76 | 37.90 | 14.23 | 114.30 | 🏆 zip |
| Синтаксис на текущем PHP | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 🏆 archive, unified-archive, zip, php-archive, zipstream-php, archive_tar |
Три строки мы проигрываем и не прячем это. 716 из наших замечаний «чистого кода» даёт одно правило StaticAccess: оно считает дефектом каждый статический вызов, а потоковый API держится на статических фабриках (Archive::create(), TarHeader::parse()). Отказ от них дал бы другой публичный интерфейс, а не более чистый код. Размер кода и дизайн мы уступаем пакетам, решающим заметно более узкую задачу: zipstream-php только пишет ZIP в поток, php-archive знает два формата.
Честно о плюсах и минусах
Сильные стороны
- Больше форматов, чем у всех сравниваемых пакетов вместе взятых.
- Потоковая архитектура: расход памяти не зависит от размера архива — на файле в 64 МиБ процесс занимает столько же, сколько на шести килобайтах.
- Работает без обязательных расширений PHP и внешних утилит.
- Конвертация между форматами без промежуточной распаковки на диск.
- Защиты от zip-slip и архивных бомб встроены, а не вынесены в примеры.
Слабые стороны — без прикрас
- Пакет моложе аналогов и пока менее распространён: у него нет многолетней
истории эксплуатации, которая есть у
pear/archive_tarилиnelexa/zip. - RAR только на чтение. Формат закрыт, запись не реализована и не планируется.
ZIP через
ext-zipбыстрее. Пакет, делегирующий работу нативному расширению, обгоняет нас на упаковке и распаковке ZIP примерно вдвое: там весь путь данных живёт в C. Наш выигрыш — в том, что мы одинаково работаем и без расширений, и с любым из 22 форматов.PHPMD ругается на статические вызовы. По стандартному набору Clean Code у нас плотность замечаний выше, чем у
nelexa/zip: 716 из них даёт правилоStaticAccess. Потоковый API держится на статических фабриках (Archive::create(),TarHeader::parse()), и отказ от них означал бы другой публичный интерфейс, а не более чистый код. Остальные наборы правил — за нами, таблица замечаний анализаторов выше.
Других минусов мы не декларируем: по функциональности, скорости, безопасности и качеству кода пакет сопоставим с лучшими в своей категории или превосходит их — это видно в таблицах выше, и их можно пересобрать у себя одной командой.
Когда его стоит брать
| Ситуация | Рекомендация |
|---|---|
| Приём файлов от пользователей, распаковка на сервере | Да. Лимиты бомб и zip-slip включены по умолчанию. |
| Резервное копирование, выгрузки, отчёты | Да. Потоковая запись; tar.gz и tar.lz4 не требуют расширений, tar.zst — ext-zstd. |
| Разбор чужих форматов поставки (7z, ISO, DEB, CAB) | Да. Единственный пакет, читающий их без внешних утилит. |
| Отдача архива пользователю «на лету» в HTTP-поток | Да. Запись идёт в поток, память не растёт. |
| Нужно поправить готовый архив: убрать секрет, подменить конфиг, дописать манифест | Да. Archive::edit() пересобирает архив потоком и не портит исходник при сбое. |
Нужен только ZIP, ext-zip есть и всё устраивает | Можно взять nelexa/zip — узкоспециализированный инструмент. |
| Нужна запись RAR | Нет. Формат закрыт, записи нет ни у кого в PHP. |
| PHP младше 8.1 | Нет. Пакет использует типы и возможности 8.1+. |
Документация
- Справочник форматов
- Возможности по разделам
- Безопасность
- Производительность и память
- Рецепты
- Справочник API
Консольная утилита
Пакет ставит команду archive: те же возможности из терминала, без
единой строки кода.
vendor/bin/archive pack /data/report /backup/report.zip
vendor/bin/archive list /backup/report.zip
vendor/bin/archive convert /backup/report.zip /backup/report.tar.zst
vendor/bin/archive delete /backup/report.zip secrets/.env
vendor/bin/archive test /backup/report.tar.zst
vendor/bin/archive extract /backup/report.tar.zst /restore
Команда возвращает 0 при успехе, 1 при ошибке работы с архивом и 2 при
неверном вызове — так её удобно ставить в скрипты. Полный список — в
vendor/bin/archive help.
Совместимость
Версии нумеруются по SemVer. Обещание
обратной совместимости распространяется на классы, которые не помечены
@internal: фасад Archive, построитель, читатель, редактор, опции,
перечисления, отчёты, исключения и контракты — всего 54 класса, их полный
список лежит в tests/Fixtures/public-api.txt и проверяется тестом.
Драйверы форматов, кодеки и примитивы ввода-вывода помечены @internal:
они решают задачу за фасадом и могут меняться в любом выпуске. Если
чего-то не хватает в публичном слое — это повод завести обсуждение, а не
обращаться к внутреннему классу напрямую.
Минимальная версия PHP — 8.1; она поднимается только мажорным выпуском.
Участие и поддержка
Лицензия — MIT.
🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano