PHP: полный мануал с примерами, функциями и ООП
Практический мануал PHP: от переменных и читаемого кода до безопасных форм, интеграций, базы данных и ООП на примере магазина. Учебный маршрут, поиск функций, подробные примеры, разбор ошибок и исходники для скачивания.

Дерево руководства
Глава 106 · С нуля → полный справочник
ZIP: документы в одном архиве и полный справочник
Создание, чтение, безопасное извлечение, кодеки, метаданные, откат и полный переход со старого API; все официальные узлы book.zip.
Первый полезный результат: чек в одном ZIP
Чек и памятка становятся одним ZIP-файлом
ZIP хранит несколько именованных записей. Подготовка записи и успешное сохранение готового архива — разные шаги.
- 1receipt.txt и guide.txt↓
Два исходных документа должны попасть в посылку клиенту.
- 2ZipArchive::open↓
Именно true подтверждает открытие: числовой код ошибки не считается успехом.
- 3Добавить записи↓
addFromString/addFile формируют состав; файл-источник может понадобиться до close.
- 4Проверить close
Только успешное завершение подтверждает сохранение, затем получатель открывает записи по именам.
Нулевой файл от tempnam не является готовым пустым ZIP. setPassword само по себе не включает шифрование, а извлечение чужого архива требует ограничений пути и ресурсов.
Магазину нужно передать клиенту чек и памятку одним файлом. ZIP — контейнер записей: у каждой есть имя, байты и метаданные. Он может сжимать данные, но не обязан. Один ZIP-файл на диске и файлы внутри него — разные сущности. Начнём с одного текстового чека, затем научимся выбирать документы, читать без распаковки и обрабатывать отказ сохранения.
Если переменные и вызовы пока незнакомы: переменная и вывод, вызов функции, объект и метод, локальные файлы. Здесь каждый новый ZIP-шаг объясняется на месте; ссылки нужны для общего синтаксиса.
- Строка paid:42 — содержимое чека
- Внутреннее имя order.txt — подпись записи
- Объект $zip — управление открытым контейнером
- close() → lesson.zip на диске
- Повторное open() → чтение order.txt
| Синтаксис | Зачем он в первом примере |
|---|---|
| $path = __DIR__ . "/lesson.zip" | Переменная хранит путь. __DIR__ — папка PHP-файла; . соединяет строки. Пример запускают в отдельной своей пустой папке. |
| new ZipArchive() | $zip становится объектом; это ещё не открытый архив. |
| $zip->open(...) | -> вызывает метод именно этого объекта. Имена в скобках — аргументы в указанном порядке. |
| ZipArchive::CREATE | ZipArchive::EXCL | :: берёт именованную константу класса; | сочетает создание с запретом заменять существующий файл. |
| !== true | Неудача open может быть числовым кодом, поэтому требуется строгое сравнение со значением true. |
| if (...) { throw new RuntimeException(...); } | При отказе прекращаем пример понятным исключением, вместо работы с неоткрытым архивом. |
| echo ..., " "; | Вывод результата и перевод строки. Точка с запятой завершает инструкцию. |
| unlink($path) | Удаляет только созданный этим примером ZIP после проверки. Для сохранения результата уберите заключительную уборку. |
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Чек не добавлен');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$receipt = $zip->getFromName('order.txt');
if ($receipt === false) throw new RuntimeException('Чек не прочитан');
echo $receipt, "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Новый файл создаётся без перезаписи существующего. Сначала проверяется сохранение, потом читается сохранённая версия. Папка процесса имеет значение для относительных имён; __DIR__ привязывает ZIP к файлу урока.
Аналогия с коробкой объясняет подписи и содержимое, но не обещает мгновенную запись: пока архив открыт, часть действий только подготовлена. Закрытие может потребовать временного файла и свободного места рядом с архивом. Даже при успешном добавлении итоговый close() ещё может отказать.
Установка, версии и проверка возможностей
ZipArchive относится к расширению zip, которое использует libzip. PHP CLI и PHP веб-сервера могут загружать разные php.ini; проверяйте тот исполнитель, где будет работать приложение. Уроки исполнялись в PHP 8.5.11 x64 с ext-zip 1.22.8 и libzip 1.11.4; это проверенное окружение, а не обязательные значения на любом компьютере.
- Выбрать нужный php.exe
- php --ini показывает его конфигурацию
- Проверить extension_loaded("zip")
- Проверить нужный метод и поддержку кодека
<?php
declare(strict_types=1);
if (!extension_loaded('zip')) throw new RuntimeException('Нужно расширение zip');
echo class_exists(ZipArchive::class) ? "ZipArchive доступен\n" : "Нет класса\n";
echo is_string(ZipArchive::LIBZIP_VERSION) ? "Версия libzip доступна\n" : "Нет версии\n";
Ожидаемый результат
ZipArchive доступен
Версия libzip доступна
Номер версии не зашит в ожидаемый результат. ::class даёт имя класса; class_exists проверяет доступность. Этот пример требует zip, как и остальные исполняемые примеры главы.
| Окружение | Что именно требуется |
|---|---|
| Windows, PHP 8.2+ | Нужно подключить соответствующую сборке php_zip.dll через extension=zip в нужном php.ini; в старых Windows PHP ZIP был встроен. DLL должна совпадать с PHP по архитектуре, версии/ABI и TS/NTS. Не скачивайте случайную DLL. |
| Unix: сборка PHP | В текущем исходном PHP применяется --with-zip и системная libzip. Для пакетов ОС используйте пакет расширения под вашу версию PHP. Это настройки сборки, не команды в PHP-файле. |
| История установки | До PHP 7.4 использовалось --enable-zip; внешняя libzip выбиралась --with-libzip=DIR; отключение встроенной — --without-libzip. В PHP 7.3 встроенная libzip объявлена deprecated; встроенная версия 1.1.2 поставлялась до PHP 7.3. |
| Библиотека | Страница требований указывает libzip не ниже 0.11 и рекомендует новую. Шифрование требует libzip 1.2+, progress callback 1.3+, cancel callback 1.6+. Конкретные новые методы/константы имеют собственные минимумы. |
| Настройки | В официальном дереве ZIP нет страницы специальных runtime INI-директив; загрузка расширения и общие ограничения PHP/файловой системы действуют отдельно. |
| Обновление расширения | PECL zip — отдельный выпуск расширения; версия PECL/ext-zip не равна PHP и не равна libzip. Проверяйте совместимость конкретной сборки. |
php --ini
php -d extension=zip --ri zip
Команды PowerShell/терминала, mode=fragment: php уже должен находиться в PATH либо замените его полным путём к нужному php.exe. extension_dir должен указывать на совместимую DLL/so. Не добавляйте extension=zip повторно, если расширение уже загружено. Это не изменение PATH или службы.
Объект ZipArchive, индексы и readonly-свойства
Объект хранит состояние открытого архива. Один и тот же номер записи может значить другое после сохранения и повторного открытия. Для устойчивой бизнес-связи обычно используют проверенное имя; индекс полезен для обхода текущего снимка. Класс реализует Countable: count($zip) вызывает count(). Читать readonly-свойство можно, присваивать ему новое значение нельзя.
- new → объект ещё без архива
- open===true → разрешены операции
- Изменения подготовлены в памяти/источниках
- close → успех либо отказ; архив закрыт
- Новый open → новый набор индексов
| Readonly-свойство | Договор |
|---|---|
| lastId:int | Индекс последнего добавленного файла/каталога; PHP 8.0 / PECL 1.18. |
| status:int | Код libzip ER_*. С PHP 8.0 / PECL 1.18 доступен и после close(). |
| statusSys:int | Системный код соответствующего отказа; не всегда errno одного вида, трактуется вместе с ZIP-ошибкой. После close() также PHP 8.0 / PECL 1.18. |
| numFiles:int | Число записей открытого архива, включая каталоги. |
| filename:string | Путь открытого ZIP, не имя текущей записи. |
| comment:string | Комментарий всего архива. Для изменения есть setArchiveComment(). |
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->numFiles, " запись\n";
echo basename($zip->filename), "\n";
$zip->addFromString("note.txt", "ok");
echo $zip->lastId, "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
1 запись
lesson.zip
1
Свойства читают состояние объекта; basename выводит только известное имя нашего архива. lastId относится к последнему добавлению.
Методы, кроме статических проверок возможностей и специальных методов диагностики, требуют действующий архив; PHP 8.5.11 бросает ValueError для неинициализированного/закрытого состояния. Не рассчитывайте сериализовать/клонировать открытый дескриптор для передачи другому процессу: передавайте путь с проверенной политикой доступа и открывайте там заново.
Имена, байты, Unicode и переносимость
ZIP не перекодирует текст документов. В UTF-8 строке размер измеряется байтами; strlen не считает видимые буквы. Имя записи — отдельная строка со своей кодировкой. FL_ENC_UTF_8 сообщает библиотеке кодировку имени, но не меняет Windows-кодировку пути на диске и не исправляет уже повреждённые байты.
- Имя: чек.txt (UTF-8)
- Содержимое: оплачен (UTF-8)
- FL_ENC_UTF_8 относится к имени
- getFromName возвращает исходное содержимое
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString("чек.txt", "оплачен", ZipArchive::FL_ENC_UTF_8);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getNameIndex(0), ":", $zip->getFromName("чек.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
чек.txt:оплачен
Файл урока сохранён в UTF-8. В другом терминале вывод может отображаться неверно даже при корректных байтах: это отдельная настройка отображения.
При интеграции с чужим архиватором сначала договоритесь о UTF-8. Не заменяйте русские имена транслитерацией автоматически: это может создавать коллизии. Содержимое CSV/JSON декодируется своим соответствующим инструментом после чтения ZIP.
От одного чека к пакету и обёртке zip://
Официальные примеры показывают создание ZIP, просмотр записей, чтение отдельных файлов через zip:// и старый ресурсный обход. Ниже — такой же путь на собственном маленьком пакете: собираем два документа внутри функции, затем считаем только содержимое выбранной записи. zip:// — локальная обёртка потока; часть после # обозначает запись архива, а не URL-фрагмент сайта.
- buildOrderBundle(path,42) получает место и заказ
- Записывает order.txt и README.txt
- Проверяет close и возвращает управление
- zip://...#order.txt читает один документ
<?php
declare(strict_types=1);
function buildOrderBundle(string $path, int $orderId): void {
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не создан пакет');
}
if (!$zip->addFromString('order.txt', 'paid:' . $orderId)
|| !$zip->addFromString('README.txt', 'Сохраните чек.')) {
$zip->unchangeAll();
$zip->close();
throw new RuntimeException('Документы не добавлены');
}
if (!$zip->close()) throw new RuntimeException('Пакет не сохранён');
}
$path = __DIR__ . '/bundle.zip';
buildOrderBundle($path, 42);
$body = file_get_contents('zip://' . $path . '#order.txt');
if ($body === false) throw new RuntimeException('Нет чека');
echo $body, "\n";
unlink($path);
Ожидаемый результат
paid:42
Параметр $path получает конкретный путь, $orderId — 42; тело добавляет оба документа, void возвращает управление без значения. || останавливает проверку после первого отказа. Ошибка добавления отменяет подготовленное перед закрытием.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString("meta.xml", '<order id="42"/>');
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$stream = fopen('zip://' . $path . '#meta.xml', 'rb');
if ($stream === false) throw new RuntimeException('Нет метаданных');
$xml = stream_get_contents($stream, 128);
fclose($stream);
if ($xml === false) throw new RuntimeException('Не прочитано');
echo $xml, "\n";
unlink($path);
Ожидаемый результат
<order id="42"/>
Это чтение XML-байтов без парсинга, не проверка XML-схемы. Так устроен доступ к частям OpenDocument (например ODT с meta.xml) и OOXML-контейнера: для интерпретации XML используйте отдельный XML-парсер с собственной политикой внешних сущностей. Не include/require содержимое недоверенного ZIP.
Следующая ступень — разобрать XML, а не только получить строку. XMLReader читает узлы последовательно: read() передвигается к следующему, nodeType отличает элемент, localName и namespaceURI выбирают нужное поле, readString() получает его текст. Это отдельное расширение xmlreader, уже загруженное в проверенном окружении. Для своего мини-примера создадим ZIP с meta.xml в стиле OpenDocument; это не полноценный ODT-документ.
- meta.xml содержит dc:title
- XMLReader открывает zip://...#meta.xml
- read() идёт по узлам
- Элемент title в Dublin Core → readString()
- Получаем «Заказ 42»
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$xml = '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" '
. 'xmlns:dc="http://purl.org/dc/elements/1.1/">'
. '<office:meta><dc:title>Заказ 42</dc:title></office:meta></office:document-meta>';
$zip->addFromString('meta.xml', $xml);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$reader = new XMLReader();
if (!$reader->open('zip://' . $path . '#meta.xml', null, LIBXML_NONET)) {
throw new RuntimeException('Не открыты метаданные');
}
$reader->setParserProperty(XMLReader::LOADDTD, false);
$reader->setParserProperty(XMLReader::SUBST_ENTITIES, false);
$title = null;
try {
while ($reader->read()) {
if ($reader->nodeType === XMLReader::ELEMENT
&& $reader->localName === 'title'
&& $reader->namespaceURI === 'http://purl.org/dc/elements/1.1/') {
$title = $reader->readString();
break;
}
}
} finally { $reader->close(); }
if ($title === null) throw new RuntimeException('Нет названия');
echo $title, "\n";
unlink($path);
Ожидаемый результат
Заказ 42
Namespace URI здесь идентификатор словаря, а не сетевой запрос. Не включены загрузка DTD и подстановка сущностей; LIBXML_NONET запрещает сетевую загрузку libxml. Для внешних документов дополнительно ограничивают ZIP/XML-размеры и обрабатывают ошибки XML. Код читает только собственные маленькие метаданные.
Безопасный импорт: имена, лимиты, перезаписи
Импортёр не должен угадывать, какие пути хотел создать автор архива. Для конкретного обмена проще принимать только точные ожидаемые имена и читать их потоком в память/свой выбранный файл, не распаковывая всё дерево. Так имена из ZIP вообще не становятся путями назначения. PHP 8.5.11 нормализует пути extractTo, но политика приложения всё равно должна предотвращать перезаписи, коллизии и неожиданную структуру.
- Разрешено только order.txt
- Проверить число и размер записей
- Прочитать не более лимита+1 байтов
- Отказать при превышении
- Использовать текст как данные, не исполнять
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
function readOrderReceipt(ZipArchive $zip): string {
if ($zip->count() !== 1 || $zip->getNameIndex(0) !== 'order.txt') {
throw new RuntimeException('Неожиданный состав');
}
$info = $zip->statIndex(0);
if ($info === false || $info['size'] > 1024) throw new RuntimeException('Размер');
$stream = $zip->getStreamIndex(0);
if ($stream === false) throw new RuntimeException('Не прочитать');
try { $body = stream_get_contents($stream, 1025); }
finally { fclose($stream); }
if ($body === false || strlen($body) > 1024) throw new RuntimeException('Лимит');
return $body;
}
echo readOrderReceipt($zip), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Имя не используется как путь назначения. Даже если метаданные размера недостоверны, само чтение ограничено. Квоты времени/CPU, размер загруженного ZIP и параллелизм настраиваются дополнительно; этот маленький пример не является общим антивирусом.
| Риск при распаковке дерева | Политика приложения |
|---|---|
| Zip Slip / path traversal | Отклонять абсолютные пути, буквы дисков/UNC, NUL, сегменты .., обратные слеши и неожиданные компоненты. Не «лечить» плохой путь basename: разные имена могут превратиться в одно. |
| Коллизии и перезапись | Новая приватная пустая директория вне web root; разрешённый список имён; учёт регистра/Unicode-нормализации/конечных точек и Windows reserved names. Не извлекать поверх пользовательских файлов. |
| Символьные ссылки и внешние атрибуты | Проверять тип записи и разрешать только ожидаемые обычные файлы/каталоги. Не восстанавливать присланные права и не следовать существующим ссылкам в каталоге назначения. |
| Архивная бомба | Ограничить входной размер, число записей, заявленный и реально прочитанный объём, время/CPU и глубину; не распаковывать вложенные архивы рекурсивно без отдельных лимитов. Один коэффициент сжатия недостаточен. |
| Частичный отказ | extractTo не транзакция. Собирать в отдельной staging-папке, проверять все результаты; только после успеха предоставлять пакет. Убирать только собственные созданные файлы. |
| Недоверенные данные | Не исполнять PHP из ZIP, не публиковать активный HTML без политики; антивирус/проверка формата/доступ применяются по назначению системы. CRC не подтверждает автора. |
Старые ресурсы, современные объекты и миграция
У старого API два разных ресурса: zip_open возвращает ресурс каталога архива, zip_read — ресурс отдельной записи. Обычный поток от getStream — третий вид ресурса, который закрывают fclose. Эти значения не взаимозаменяемы. Все 10 процедурных ZIP-функций deprecated с PHP 8.0; ниже они сохранены полностью для понимания старых проектов и миграции.
- zip_open → new ZipArchive + open
- zip_read → обход индексов / locateName
- zip_entry_read → getFromName или getStream
- zip_entry_close → fclose для современного потока
- zip_close → проверенный ZipArchive::close
| Старая задача | Современный путь |
|---|---|
| Имя, размер, метод сжатия | getNameIndex + statIndex/statName |
| Небольшой документ | getFromName с проверкой === false |
| Крупный документ | getStream + ограниченное чтение + fclose |
| Извлечь выбранные документы | Политика имён/размеров → extractTo или управляемая потоковая запись |
Все константы: флаги, алгоритмы, ошибки и системы
Именованная константа заменяет непонятное число и показывает намерение: ZipArchive::CREATE. Но разные семейства нельзя смешивать. Флаги open(), flags конкретного метода, алгоритм CM_* и ошибка ER_* решают разные задачи. Наличие константы в классе не обещает поддержку кодека или любого сочетания флагов.
- CREATE|EXCL → как открыть lesson.zip
- CM_DEFLATE → как сжать order.txt
- ER_NOENT → почему поиск missing.txt не удался
Режимы открытия
| Константа | Значение для читателя |
|---|---|
| ZipArchive::CREATE | Создать при отсутствии, не очищая существующий ZIP. |
| ZipArchive::OVERWRITE | Считать прежнее содержимое пустым; уничтожение старых записей при сохранении. |
| ZipArchive::EXCL | Отказать, если файл уже существует. |
| ZipArchive::RDONLY | Открыть для чтения. PHP 7.4.3 / PECL 1.17.1; libzip 1.0+. |
| ZipArchive::CHECKCONS | Дополнительно проверить согласованность структуры при открытии. |
Общие признаки (PHP 8.3 / PECL 1.22, libzip 1.10+)
| Константа | Значение для читателя |
|---|---|
| ZipArchive::AFL_RDONLY | Архив только для чтения. Режим от open(RDONLY) снять нельзя; вручную установленный флаг libzip позволяет снять обратно. |
| ZipArchive::AFL_IS_TORRENTZIP | Наблюдаемый признак уже существующего формата TorrentZip. |
| ZipArchive::AFL_WANT_TORRENTZIP | Запросить запись в формате TorrentZip. |
| ZipArchive::AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE | Сохранить файл ZIP даже при отсутствии записей. |
Флаги операций — только там, где разрешены сигнатурой/договором
| Константа | Значение для читателя |
|---|---|
| ZipArchive::FL_NOCASE | Игнорировать регистр имени при поиске. |
| ZipArchive::FL_NODIR | Не учитывать каталог при поиске имени. |
| ZipArchive::FL_COMPRESSED | Получить сжатые байты вместо распаковки. |
| ZipArchive::FL_UNCHANGED | Обратиться к исходному состоянию при open(), не отменяя подготовленное. |
| ZipArchive::FL_RECOMPRESS | Принудительное повторное сжатие; PHP 8.0 / PECL 1.18, deprecated PHP 8.3 / PECL 1.22.1; будущая libzip может убрать. |
| ZipArchive::FL_ENCRYPTED | Получить шифрованные байты; подразумевает FL_COMPRESSED. PHP 8.0 / PECL 1.18. |
| ZipArchive::FL_OVERWRITE | Разрешить замену одноимённой записи. PHP 8.0 / PECL 1.18. |
| ZipArchive::FL_LOCAL | Обращение к локальному заголовку, только для поддерживающей это операции. PHP 8.0 / PECL 1.18. |
| ZipArchive::FL_CENTRAL | Обращение к центральному каталогу, только для поддерживающей это операции. PHP 8.0 / PECL 1.18. |
| ZipArchive::FL_ENC_GUESS | Определить кодировку строк (0, стандартно); PHP 7.0.8. |
| ZipArchive::FL_ENC_RAW | Вернуть исходные байты строки без преобразования; PHP 7.0.8. |
| ZipArchive::FL_ENC_STRICT | Следовать правилам формата для кодировки строго; PHP 7.0.8. |
| ZipArchive::FL_ENC_UTF_8 | Строка имени задана в UTF-8; PHP 7.0.8. |
| ZipArchive::FL_ENC_CP437 | Строка имени задана в CP437; PHP 7.0.8. |
| ZipArchive::FL_OPEN_FILE_NOW | Открыть добавляемый файл сразу, расходуя дескриптор; PHP 8.3 / PECL 1.22.1. |
Способы сжатия
| Константа | Значение для читателя |
|---|---|
| ZipArchive::CM_DEFAULT | Выбор libzip: PHP описывает лучший из deflate/store; текущая документация libzip — deflate с игнорированием flags. Для точного метода выбирайте его явно. |
| ZipArchive::CM_STORE | Без сжатия. |
| ZipArchive::CM_SHRINK | Исторический Shrink. |
| ZipArchive::CM_REDUCE_1 | Исторический Reduce, коэффициент 1. |
| ZipArchive::CM_REDUCE_2 | Reduce, коэффициент 2. |
| ZipArchive::CM_REDUCE_3 | Reduce, коэффициент 3. |
| ZipArchive::CM_REDUCE_4 | Reduce, коэффициент 4. |
| ZipArchive::CM_IMPLODE | Исторический Implode. |
| ZipArchive::CM_DEFLATE | Распространённый Deflate. |
| ZipArchive::CM_DEFLATE64 | Deflate64, отдельный алгоритм; не заменяет Deflate автоматически. |
| ZipArchive::CM_PKWARE_IMPLODE | PKWARE DCL Implode. |
| ZipArchive::CM_BZIP2 | Bzip2. |
| ZipArchive::CM_LZMA | LZMA. |
| ZipArchive::CM_LZMA2 | LZMA2; PHP 7.4.3 / PECL 1.16.0; libzip 1.6+. |
| ZipArchive::CM_ZSTD | Zstandard; PHP 8.0 / PECL 1.19.1; libzip 1.8+. |
| ZipArchive::CM_XZ | XZ; PHP 7.4.3 / PECL 1.16.1; libzip 1.6+. |
| ZipArchive::CM_TERSE | Идентификатор TERSE (существование не обещает поддержку). |
| ZipArchive::CM_LZ77 | Идентификатор LZ77. |
| ZipArchive::CM_WAVPACK | Идентификатор WavPack. |
| ZipArchive::CM_PPMD | Идентификатор PPMd. |
Коды ошибок
| Константа | Значение для читателя |
|---|---|
| ZipArchive::ER_OK | Отказа нет. |
| ZipArchive::ER_MULTIDISK | Многотомный ZIP не поддерживается. |
| ZipArchive::ER_RENAME | Не получилось переименовать временный файл. |
| ZipArchive::ER_CLOSE | Не получилось закрыть ZIP. |
| ZipArchive::ER_SEEK | Ошибка перемещения позиции чтения. |
| ZipArchive::ER_READ | Ошибка чтения. |
| ZipArchive::ER_WRITE | Ошибка записи. |
| ZipArchive::ER_CRC | Не совпала контрольная сумма CRC. |
| ZipArchive::ER_ZIPCLOSED | Содержащий запись архив уже закрыт. |
| ZipArchive::ER_NOENT | Файл/запись не найдены. |
| ZipArchive::ER_EXISTS | Имя уже существует. |
| ZipArchive::ER_OPEN | Не удалось открыть файл. |
| ZipArchive::ER_TMPOPEN | Не удалось создать временный файл для записи ZIP. |
| ZipArchive::ER_ZLIB | Ошибка библиотеки zlib. |
| ZipArchive::ER_MEMORY | Не удалось выделить память. |
| ZipArchive::ER_CHANGED | Требуются данные записи, которая изменена. |
| ZipArchive::ER_COMPNOTSUPP | Способ сжатия не поддерживается. |
| ZipArchive::ER_EOF | Преждевременный конец данных. |
| ZipArchive::ER_INVAL | Некорректный аргумент libzip. |
| ZipArchive::ER_NOZIP | Данные не являются ZIP. |
| ZipArchive::ER_INTERNAL | Внутренняя ошибка. |
| ZipArchive::ER_INCONS | Структура ZIP несогласованна. |
| ZipArchive::ER_REMOVE | Не удалось удалить файл. |
| ZipArchive::ER_DELETED | Запись помечена удалённой. |
| ZipArchive::ER_ENCRNOTSUPP | Шифрование не поддерживается. |
| ZipArchive::ER_RDONLY | Попытка изменения read-only архива. |
| ZipArchive::ER_NOPASSWD | Для чтения не предоставлен пароль. |
| ZipArchive::ER_WRONGPASSWD | Пароль не подошёл. |
| ZipArchive::ER_OPNOTSUPP | Операция не поддерживается. |
| ZipArchive::ER_INUSE | Ресурс всё ещё используется. |
| ZipArchive::ER_TELL | Не удалось узнать позицию. |
| ZipArchive::ER_COMPRESSED_DATA | Некорректные сжатые данные. |
| ZipArchive::ER_CANCELLED | Операция отменена callback. |
| ZipArchive::ER_DATA_LENGTH | Размер данных изменился вопреки договору. |
| ZipArchive::ER_NOT_ALLOWED | Операция несовместима с TorrentZip. |
| ZipArchive::ER_TRUNCATED_ZIP | ZIP возможно обрезан или повреждён. |
Способы шифрования
| Константа | Значение для читателя |
|---|---|
| ZipArchive::EM_NONE | Без шифрования; PHP 7.2 / PECL 1.14. |
| ZipArchive::EM_TRAD_PKWARE | Традиционное слабое PKWARE; PHP 8.0 / PECL 1.19. |
| ZipArchive::EM_AES_128 | AES-128; PHP 7.2 / PECL 1.14; libzip 1.2+. |
| ZipArchive::EM_AES_192 | AES-192; PHP 7.2 / PECL 1.14; libzip 1.2+. |
| ZipArchive::EM_AES_256 | AES-256; PHP 7.2 / PECL 1.14; libzip 1.2+. |
| ZipArchive::EM_UNKNOWN | Неизвестный алгоритм, не выбор для нового шифрования; PHP 8.0 / PECL 1.19. |
Длина и версия библиотеки
| Константа | Значение для читателя |
|---|---|
| ZipArchive::LENGTH_TO_END | 0: фиксировать доступный размер источника; рост игнорируется, уменьшение — ER_DATA_LENGTH. PHP 8.3 / PECL 1.22.2. |
| ZipArchive::LENGTH_UNCHECKED | Прочитать все доступные данные источника с указанного start. PHP 8.3 / PECL 1.22.2; libzip 1.10.1+. |
| ZipArchive::LIBZIP_VERSION | Строковая версия связанной libzip; PHP 7.4.3 / PECL 1.16.0. Остальные перечисленные константы имеют тип int. |
Происхождение внешних атрибутов (PECL 1.12.4+)
| Константа | Значение для читателя |
|---|---|
| ZipArchive::OPSYS_DOS | DOS |
| ZipArchive::OPSYS_AMIGA | Amiga |
| ZipArchive::OPSYS_OPENVMS | OpenVMS |
| ZipArchive::OPSYS_UNIX | UNIX |
| ZipArchive::OPSYS_VM_CMS | VM/CMS |
| ZipArchive::OPSYS_ATARI_ST | Atari ST |
| ZipArchive::OPSYS_OS_2 | OS/2 |
| ZipArchive::OPSYS_MACINTOSH | классическая Macintosh |
| ZipArchive::OPSYS_Z_SYSTEM | Z-System |
| ZipArchive::OPSYS_CPM | CP/M |
| ZipArchive::OPSYS_WINDOWS_NTFS | Windows NTFS |
| ZipArchive::OPSYS_MVS | MVS |
| ZipArchive::OPSYS_VSE | VSE |
| ZipArchive::OPSYS_ACORN_RISC | Acorn RISC |
| ZipArchive::OPSYS_VFAT | VFAT |
| ZipArchive::OPSYS_ALTERNATE_MVS | альтернативный MVS |
| ZipArchive::OPSYS_BEOS | BeOS |
| ZipArchive::OPSYS_TANDEM | Tandem |
| ZipArchive::OPSYS_OS_400 | OS/400 |
| ZipArchive::OPSYS_OS_X | OS X |
| ZipArchive::OPSYS_DEFAULT | система по умолчанию в сборке |
Версии новых ошибок: ER_ENCRNOTSUPP, ER_RDONLY, ER_NOPASSWD, ER_WRONGPASSWD — PHP 7.4.3 / PECL 1.16.1. ER_OPNOTSUPP, ER_INUSE, ER_TELL дополнительно libzip 1.0+. ER_COMPRESSED_DATA и ER_CANCELLED — libzip 1.6+. ER_DATA_LENGTH и ER_NOT_ALLOWED — PHP 8.3 / PECL 1.22, libzip 1.10+. ER_TRUNCATED_ZIP — PHP 8.4 / PECL 1.22.4, libzip 1.11.1+. Старые ошибки перечислены без искусственного обещания точной версии появления.
PHP-страница кратко говорит, что AFL_RDONLY нельзя снять. Уточнение libzip: нельзя снять read-only от open(RDONLY); вручную установленный setArchiveFlag флаг можно снять. AFL_IS_TORRENTZIP доступен только для наблюдения. OPSYS_* — формат трактовки сохранённых атрибутов, не команда поменять ОС и не проверка текущей ОС.
<?php
declare(strict_types=1);
$flags = ZipArchive::CREATE | ZipArchive::EXCL;
echo ($flags & ZipArchive::CREATE) !== 0 ? "Создание разрешено\n" : "Нет\n";
echo ZipArchive::ER_OK === 0 ? "Код успеха 0\n" : "Другой код\n";
Ожидаемый результат
Создание разрешено
Код успеха 0
| объединяет биты флагов, & проверяет их наличие. ER_OK — значение статуса; успешный open всё равно сравнивают с true, не с ER_OK.
Практика, стоимость и следующий шаг
Упражнение: получатель требует только order.txt, но в вашем текущем пакете ещё есть notes.txt. До сохранения удалите notes.txt, смените комментарий архива на «Выпуск 42», закройте с проверкой и убедитесь, что остался один документ. Не меняйте исходные файлы на диске.
- Добавлены order.txt и notes.txt
- Удалена запись notes.txt
- Комментарий стал «Выпуск 42»
- close/open → один документ и комментарий
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->addFromString('notes.txt', 'Внутренняя заметка');
if (!$zip->deleteName('notes.txt')) throw new RuntimeException('Не удалено');
if (!$zip->setArchiveComment('Выпуск 42')) throw new RuntimeException('Нет комментария');
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->count(), ":", $zip->getNameIndex(0), "\n", $zip->getArchiveComment(), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
1:order.txt
Выпуск 42
Удаление относится к записи, не к файлу notes.txt на компьютере. Для усложнения: при отказе добавления второго документа отмените всю партию через unchangeAll().
Для больших поставок addFile уменьшает необходимость держать всё содержимое строками; потоки ограничивают память чтения. При изменении существующего архива может потребоваться переписать его в новый временный файл. Измеряйте время, свободное место и дескрипторы на реальном наборе данных; «ZIP всегда меньше/быстрее» неверно.
Дальше: выбор файлов, шифрование отдельных записей, отмена долгой записи.
Полный каталог методов и исторических функций
Карточки ниже сохраняют всё официальное дерево ZIP. Name-методы выбирают по имени, Index-методы — по индексу текущего открытого архива. У каждого вызова есть договор, модель, два самостоятельных примера и точная проверка результата. Устаревшие функции выделены версией deprecated; они не предлагаются для нового кода.
Функции и методы этой темы
Откройте карточку, чтобы увидеть договор функции, примеры, ограничения и связанные инструменты.
ZipArchive::openСобрать чек и памятку в один файл или открыть готовую поставку.
PHP 5.2+, PECL zip 1.1+; RDONLY: PHP 7.4.3 / PECL 1.17.1, libzip 1.0+ · zip
open(string $filename, int $flags = 0): bool|intСобрать чек и памятку в один файл или открыть готовую поставку.
Синтаксис: open(string $filename, int $flags = 0): bool|int. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| filename | Путь ZIP в файловой системе; это не имя одного файла внутри ZIP. Непустой локальный путь. |
| flags | 0 открывает существующий ZIP; CREATE создаёт отсутствующий, сохраняя существующий; OVERWRITE отбрасывает старое содержимое; CREATE|OVERWRITE допускает новый или существующий. CREATE|EXCL запрещает заменить существующий. RDONLY — чтение, CHECKCONS — дополнительные проверки структуры. |
Результат: Именно true означает успех. Целочисленный ER_* (в том числе ненулевой и потому truthy) или false означает отказ.
Отказ: Пустое имя — ValueError; доступ/путь могут дать false и warning; ошибки libzip — код ER_EXISTS, ER_INCONS, ER_INVAL, ER_MEMORY, ER_NOENT, ER_NOZIP, ER_OPEN, ER_READ, ER_SEEK. Проверяйте результат, try/catch один не заменяет проверку.
- lesson.zip ещё нет
- CREATE|EXCL открывает новый архив без разрешения замены
- order.txt добавлен
- close() записывает архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
echo "Подготовлен чек\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Подготовлен чек
new создаёт объект управления, -> вызывает его метод; :: обращается к именованному флагу класса. Проверка !== true нужна из-за целочисленных ошибок.
<?php
declare(strict_types=1);
$zip = new ZipArchive();
$result = $zip->open(__DIR__ . '/missing.zip', ZipArchive::RDONLY);
echo $result === ZipArchive::ER_NOENT ? "Нет поставки\n" : "Другой результат\n";
Ожидаемый результат
Нет поставки
Проверяется конкретный код; отсутствующий ZIP не создаётся.
Нулевой файл от tempnam() не является пустым корректным ZIP: libzip 1.6+ его отвергает; PHP 8.5.11 сохраняет deprecated-совместимость для открытия на запись без OVERWRITE. Для собственного уже выделенного пустого файла применяют OVERWRITE, понимая уничтожение его содержимого. Новый архив создаётся при close(), а не обязательно при open(). Повторный open() того же объекта сначала закрывает предыдущий архив: предпочтительнее явный проверенный close().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::close, ZipArchive::getStatusString.
ZipArchive::closeПодтвердить, что подготовленная выгрузка действительно сохранена.
PHP 5.2+; PECL zip · zip
close(): boolПодтвердить, что подготовленная выгрузка действительно сохранена.
Синтаксис: close(): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| Нет аргументов | Скобки () обязательны. |
Результат: true — закрытие успешно; false — сохранить не удалось. Объект после попытки close() больше не держит открытый архив.
Отказ: Ошибка записи, чтения добавленного источника, временного файла, переименования или отмена callback: warning и false; диагностический status доступен после закрытия (PHP 8.0+).
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Создать lesson.zip
- Добавить order.txt
- Проверить close()
- Повторно открыть и прочитать paid:42
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
В подготовке close() уже проверен, затем открыт сохранённый файл. После второго close() удаляется только учебный ZIP.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
echo file_exists($path) ? "есть\n" : "нет записей — нет файла\n";
Ожидаемый результат
нет записей — нет файла
Не добавили ни одной записи: обычная политика libzip удаляет пустой архив. Для намеренно пустого ZIP нужен AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE.
Завершение скрипта также закрывает объект, но тогда пропускается удобная проверка результата. В PHP 8.5.11 неудачный close() отбрасывает подготовленные изменения и освобождает архив; повторять close() на нём нельзя. Источники addFile()/replaceFile() должны жить до завершения записи. Не удаляйте их после одного true от addFile().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::open, ZipArchive::setArchiveFlag, ZipArchive::registerCancelCallback.
ZipArchive::addEmptyDirПередать получателю пустую папку для будущих актов.
PHP 5.2+, PECL 1.8+; flags PHP 8.0 / PECL 1.18+ · zip
addEmptyDir(string $dirname, int $flags = 0): boolПередать получателю пустую папку для будущих актов.
Синтаксис: addEmptyDir(string $dirname, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| dirname | Имя папки внутри ZIP, например acts; метод создаёт запись каталога с конечным /. |
| flags | FL_ENC_GUESS (0: определить кодировку), FL_ENC_UTF_8 или FL_ENC_CP437 задают кодировку имени записи. Это не перекодировка содержимого файла. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при конфликте/отказе libzip или пустом имени (PHP 8.5.11).
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- lesson.zip открыт
- acts становится acts/
- Это запись каталога, не mkdir на компьютере
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addEmptyDir("acts");
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
acts/
Внешняя папка acts не создаётся: меняется только структура архива.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addEmptyDir("Акты", ZipArchive::FL_ENC_UTF_8);
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Акты/
Явно указан UTF-8 для имени; содержимого у пустой папки нет.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::addFile, ZipArchive::getNameIndex.
ZipArchive::addFromStringДобавить сформированный в PHP чек без промежуточного файла.
PHP 5.2+, PECL 1.1+; flags PHP 8.0 / PECL 1.18+ · zip
addFromString(string $name, string $content, int $flags = ZipArchive::FL_OVERWRITE): boolДобавить сформированный в PHP чек без промежуточного файла.
Синтаксис: addFromString(string $name, string $content, int $flags = ZipArchive::FL_OVERWRITE): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Имя записи внутри ZIP. |
| content | Готовые байты, включая NUL; функция не кодирует JSON/текст сама. |
| flags | FL_OVERWRITE разрешает замену одноимённой записи; 0 запрещает. FL_ENC_GUESS (0: определить кодировку), FL_ENC_UTF_8 или FL_ENC_CP437 задают кодировку имени записи. Это не перекодировка содержимого файла. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при конфликте без FL_OVERWRITE или ошибке libzip. PHP 8.5.11 / libzip 1.11.4 допускает даже пустое имя здесь: приложение должно само требовать непустое безопасное имя, не рассчитывая на ValueError.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- paid:42 — строка в памяти
- order.txt — имя в ZIP
- addFromString связывает имя и байты
- После close()/open() строка читается
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Перед чтением повторно открываем сохранённую версию.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->addFromString("order.txt", "cancelled:42");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
cancelled:42
Значение flags по умолчанию допускает замену. Для запрета дубликата передайте 0 и проверьте false.
Вся строка уже находится в памяти; большой диск-файл выгоднее передать addFile(), а не читать его целиком ради этой функции. Наличие записи после добавления не обещает чтение её новых байтов до close()/open(). Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::addFile, ZipArchive::getFromName.
ZipArchive::addFileВключить готовый прайс-лист с диска в поставку.
PHP 5.2 / PECL 1.1+; flags PHP 8.0 / PECL 1.18+ · zip
addFile(string $filepath, string $entryname = "", int $start = 0, int $length = ZipArchive::LENGTH_TO_END, int $flags = ZipArchive::FL_OVERWRITE): boolВключить готовый прайс-лист с диска в поставку.
Синтаксис: addFile(string $filepath, string $entryname = "", int $start = 0, int $length = ZipArchive::LENGTH_TO_END, int $flags = ZipArchive::FL_OVERWRITE): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| filepath | Существующий читаемый файл на диске; сохраните его до close(). |
| entryname | Имя в ZIP; пустое использует filepath, поэтому лучше задать короткое переносимое имя. |
| start | Смещение в байтах от начала файла. |
| length | 0 / LENGTH_TO_END — размер на момент добавления: последующий рост игнорируется, уменьшение вызывает ошибку при записи. LENGTH_UNCHECKED — все доступные байты с start (PHP 8.3 / PECL 1.22.2, libzip 1.10.1). |
| flags | FL_OVERWRITE разрешает замену; FL_ENC_GUESS (0: определить кодировку), FL_ENC_UTF_8 или FL_ENC_CP437 задают кодировку имени записи. Это не перекодировка содержимого файла. FL_OPEN_FILE_NOW открывает источник сразу (8.3 / 1.22.1). |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при недоступном файле/индексе/ошибке; пустой filepath — ValueError, отрицательный index replaceFile — ValueError. Поздняя ошибка чтения может возникнуть только на close().
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- source.csv содержит SKU;42
- Файл остаётся на диске до close()
- Байты попадают в price.csv
- Повторное открытие проверяет результат
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFile(__DIR__ . "/source.csv", "price.csv");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("price.csv"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
SKU;42
Файл-источник и имя записи — разные вещи. Входной source.csv дан рядом с примером.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFile(__DIR__ . "/slice.txt", "number.txt", 7, 2);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
42
Первые 7 ASCII-байтов prefix: пропускаются; длина 2 оставляет 42. Для UTF-8 байтовый разрез может повредить символ.
PHP удерживает источник до закрытия архива. FL_OPEN_FILE_NOW позволяет раньше обнаружить отказ открытия, но при множестве файлов расходует дескрипторы; он не делает файл неизменным. Не меняйте источник параллельно. Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::close, ZipArchive::addFromString.
ZipArchive::replaceFileЗаменить байты прайс-листа, сохранив его имя в ZIP.
PHP 8.0 / PECL 1.18+ · zip
replaceFile(string $filepath, int $index, int $start = 0, int $length = ZipArchive::LENGTH_TO_END, int $flags = 0): boolЗаменить байты прайс-листа, сохранив его имя в ZIP.
Синтаксис: replaceFile(string $filepath, int $index, int $start = 0, int $length = ZipArchive::LENGTH_TO_END, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| filepath | Существующий читаемый файл на диске; сохраните его до close(). |
| index | Индекс существующей записи; имя не меняется. |
| start | Смещение в байтах от начала файла. |
| length | 0 / LENGTH_TO_END — размер на момент добавления: последующий рост игнорируется, уменьшение вызывает ошибку при записи. LENGTH_UNCHECKED — все доступные байты с start (PHP 8.3 / PECL 1.22.2, libzip 1.10.1). |
| flags | Допустимы FL_ENC_GUESS, FL_ENC_UTF_8, FL_ENC_CP437 и FL_OPEN_FILE_NOW. Последний открывает источник сразу (PHP 8.3 / PECL 1.22.1); замена не меняет имя записи. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при недоступном файле/индексе/ошибке; пустой filepath — ValueError, отрицательный index replaceFile — ValueError. Поздняя ошибка чтения может возникнуть только на close().
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- source.csv содержит SKU;42
- Файл остаётся на диске до close()
- Байты попадают в order.txt
- Повторное открытие проверяет результат
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->replaceFile(__DIR__ . "/source.csv", 0);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
SKU;42
Файл-источник и имя записи — разные вещи. Входной source.csv дан рядом с примером.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->replaceFile(__DIR__ . "/slice.txt", 0, 7, 2);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
42
Первые 7 ASCII-байтов prefix: пропускаются; длина 2 оставляет 42. Для UTF-8 байтовый разрез может повредить символ.
PHP удерживает источник до закрытия архива. FL_OPEN_FILE_NOW позволяет раньше обнаружить отказ открытия, но при множестве файлов расходует дескрипторы; он не делает файл неизменным. Не меняйте источник параллельно. Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::close, ZipArchive::addFromString.
ZipArchive::addGlobСобрать выбранные файлы каталога в одну поставку без ручного addFile для каждого.
PHP 5.3 / PECL zip 1.9+ · zip
addGlob(string $pattern, int $flags = 0, array $options = []): array|falseСобрать выбранные файлы каталога в одну поставку без ручного addFile для каждого.
Синтаксис: addGlob(string $pattern, int $flags = 0, array $options = []): array|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| pattern | Маска glob для пути, например input/*.csv; это не регулярное выражение. |
| flags | Флаги glob(), например GLOB_NOSORT; это НЕ FL_* ZipArchive. |
| options: пути | remove_path удаляет заданный префикс; remove_all_path=true оставляет basename; add_path добавляется после удаления, например prices/. |
| options: запись | flags — ZIP-флаги замены/кодировки/раннего открытия (PHP 8.0 / PECL 1.18). |
| options: кодеки | comp_method, comp_flags задают сжатие; enc_method, enc_password — шифрование (PHP 8.0 / PECL 1.18.1). Пароль не передавайте в логи. |
Результат: Массив имён добавленных исходных файлов или false; [] означает отсутствие совпадений, а не true.
Отказ: false при отказе поиска/добавления; ошибки PCRE/файлов могут сопровождаться warning. Пустой pattern — ValueError; неправильный тип опций — TypeError/ValueError. Частичное добавление до ошибки возможно: используйте unchangeAll() для отказа от партии.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- input/a.csv подходит маске
- input/a.txt не подходит
- Исходный путь сокращается
- В ZIP получается prices/a.csv
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
chdir(__DIR__);
$added = $zip->addGlob("input/*.csv", 0, ["remove_path" => "input/", "add_path" => "prices/"]);
if ($added === false) throw new RuntimeException("Пакет не собран");
echo count($added), ":", $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
1:prices/a.csv
remove_path/remove_all_path меняют имя в ZIP, не перемещают исходные файлы. Папки и файлы fixtures должны существовать перед запуском.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
chdir(__DIR__);
$added = $zip->addGlob("input/*.txt", 0, ["remove_all_path" => true]);
echo $added === [] ? "Нет документов\n" : "Другая ветка\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
Ожидаемый результат
Нет документов
Пустая выборка обработана отдельно от false. Пустой ZIP после close() не остаётся.
Эти вызовы не являются рекурсивным архиватором дерева. Каталог проекта и путь архивного имени разделяйте; не начинайте add_path с /. При одинаковых basename можно перезаписать запись: определите политику дубликатов. Для отдельного выбранного файла проще addFile().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::addFile, ZipArchive::unchangeAll.
ZipArchive::addPatternСобрать выбранные файлы каталога в одну поставку без ручного addFile для каждого.
PHP 5.3 / PECL zip 1.9+ · zip
addPattern(string $pattern, string $path = ".", array $options = []): array|falseСобрать выбранные файлы каталога в одну поставку без ручного addFile для каждого.
Синтаксис: addPattern(string $pattern, string $path = ".", array $options = []): array|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| pattern | PCRE с разделителями, например /\.csv$/; проверяет только имя файла, не полный путь. |
| path | Каталог поиска, по умолчанию текущий рабочий каталог. Не рекурсивно. |
| options: пути | remove_path удаляет заданный префикс; remove_all_path=true оставляет basename; add_path добавляется после удаления, например prices/. |
| options: запись | flags — ZIP-флаги замены/кодировки/раннего открытия (PHP 8.0 / PECL 1.18). |
| options: кодеки | comp_method, comp_flags задают сжатие; enc_method, enc_password — шифрование (PHP 8.0 / PECL 1.18.1). Пароль не передавайте в логи. |
Результат: Массив имён добавленных исходных файлов или false; [] означает отсутствие совпадений, а не true.
Отказ: false при отказе поиска/добавления; ошибки PCRE/файлов могут сопровождаться warning. Пустой pattern — ValueError; неправильный тип опций — TypeError/ValueError. Частичное добавление до ошибки возможно: используйте unchangeAll() для отказа от партии.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- input/a.csv подходит маске
- input/a.txt не подходит
- Исходный путь сокращается
- В ZIP получается prices/a.csv
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
chdir(__DIR__);
$added = $zip->addPattern("/\.csv$/", "input", ["remove_all_path" => true, "add_path" => "prices/"]);
if ($added === false) throw new RuntimeException("Пакет не собран");
echo count($added), ":", $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
1:prices/a.csv
remove_path/remove_all_path меняют имя в ZIP, не перемещают исходные файлы. Папки и файлы fixtures должны существовать перед запуском.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
chdir(__DIR__);
$added = $zip->addPattern("/^invoice-.*\.txt$/", "input", ["remove_all_path" => true]);
echo $added === [] ? "Нет документов\n" : "Другая ветка\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
Ожидаемый результат
Нет документов
Пустая выборка обработана отдельно от false. Пустой ZIP после close() не остаётся.
Эти вызовы не являются рекурсивным архиватором дерева. Каталог проекта и путь архивного имени разделяйте; не начинайте add_path с /. При одинаковых basename можно перезаписать запись: определите политику дубликатов. Для отдельного выбранного файла проще addFile().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::addFile, ZipArchive::unchangeAll.
ZipArchive::countПроверить, что поставка содержит ожидаемое число записей.
PHP 7.2 / PECL 1.15+ · zip
count(): intПроверить, что поставка содержит ожидаемое число записей.
Синтаксис: count(): int. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| Нет аргументов | Скобки () обязательны. |
Результат: Число записей в открытом архиве, включая записи каталогов; метод также вызывается count($zip), поскольку класс реализует Countable.
Отказ: Неоткрытый объект — ValueError. Это не число обычных файлов и не объём распакованных байтов.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt — единственная запись
- count() спрашивает число записей
- Результат 1 используется для проверки поставки
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->count(), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
1
В подготовленном архиве один чек.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->addEmptyDir("acts");
echo count($zip), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
2
Countable позволяет общую функцию count(). После удаления индексы могут иметь пропуски: количество не доказывает доступность каждого номера.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex, ZipArchive::getNameIndex.
ZipArchive::locateNameНайти номер записи по известному имени перед точечным изменением.
PHP 5.2 / PECL 1.5+ · zip
locateName(string $name, int $flags = 0): int|falseНайти номер записи по известному имени перед точечным изменением.
Синтаксис: locateName(string $name, int $flags = 0): int|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Имя записи в ZIP. |
| flags | 0 — точное имя; FL_NOCASE — без учёта регистра; FL_NODIR — сравнивать без каталогов. Флаги можно объединить |. |
Результат: Индекс найденного элемента, начиная с 0; false — совпадения нет.
Отказ: Пустое name в PHP 8.5.11 даёт false; false также при отказе поиска. Не используйте if ($index): нулевой индекс корректен.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Ищем order.txt
- Первый элемент имеет индекс 0
- Проверяем !== false
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$index = $zip->locateName("order.txt");
echo $index !== false ? "Индекс: $index\n" : "Нет\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Индекс: 0
Строгое сравнение различает false и 0.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->locateName("ORDER.TXT", ZipArchive::FL_NOCASE), "\n";
var_export($zip->locateName("missing.txt")); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
0
false
FL_NOCASE удобен для поиска, но не решает конфликты нескольких подходящих имён. В импорте лучше требовать однозначное точное имя.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getNameIndex, ZipArchive::renameIndex.
ZipArchive::getNameIndexПоказать содержимое поставки без распаковки.
PHP 5.2 / PECL 1.5+ · zip
getNameIndex(int $index, int $flags = 0): string|falseПоказать содержимое поставки без распаковки.
Синтаксис: getNameIndex(int $index, int $flags = 0): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Номер записи, начиная с 0. |
| flags | FL_UNCHANGED возвращает исходное имя до подготовленных изменений. |
Результат: Строка имени записи или false для отсутствующего/удалённого индекса.
Отказ: Неверный индекс возвращает false; прочитайте статус при диагностике.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Архив содержит order.txt
- Номер 0 → getNameIndex(0)
- Получаем имя без чтения содержимого
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Имя записи не является безопасным HTML: при выводе в веб-страницу нужно htmlspecialchars().
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameIndex(0, "receipt.txt");
echo $zip->getNameIndex(0), "\n", $zip->getNameIndex(0, ZipArchive::FL_UNCHANGED), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
receipt.txt
order.txt
UNCHANGED обращается к состоянию, открытому с диска, а не отменяет изменение.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::locateName, ZipArchive::statIndex.
ZipArchive::getFromNameПрочитать небольшой чек из ZIP без записи на диск.
PHP 5.2 / PECL 1.1+ · zip
getFromName(string $name, int $len = 0, int $flags = 0): string|falseПрочитать небольшой чек из ZIP без записи на диск.
Синтаксис: getFromName(string $name, int $len = 0, int $flags = 0): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Точное имя записи. |
| len | Максимальное число байтов результата; 0 читает запись целиком. Для предсказуемого договора используйте 0 или положительное значение. |
| flags | FL_UNCHANGED читает прежнюю версию; FL_COMPRESSED выдаёт сжатые байты. FL_NOCASE позволяет поиск без учёта регистра. |
Результат: Байтовая строка; пустая запись даёт "", отсутствие/отказ — false.
Отказ: false при отсутствии записи, недоступных новых данных, пароле/декомпрессии; повреждённые данные могут дать warning. name="" — ValueError. Полное чтение выделяет память под данные.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt хранит paid:42
- Вызов выбирает запись
- В строке PHP оказываются 7 байтов
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Это байты содержимого, а не имя и не распакованный файл на диске.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt", 4), "\n";
var_export($zip->getFromName("missing.txt")); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid
false
Первые 4 байта подходят для ASCII-маркера. Ограниченный префикс не доказывает целостность всего содержимого; UTF-8 можно разрезать посередине символа.
Большой документ читайте потоком; ни расширение имени, ни успешная декомпрессия не делают содержимое доверенным. FL_COMPRESSED не выдаёт готовый самостоятельный ZIP-файл. Новые/заменённые данные сначала сохраните и откройте повторно.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getStream, ZipArchive::statName.
ZipArchive::getFromIndexПрочитать небольшой чек из ZIP без записи на диск.
PHP 5.2 / PECL 1.1+ · zip
getFromIndex(int $index, int $len = 0, int $flags = 0): string|falseПрочитать небольшой чек из ZIP без записи на диск.
Синтаксис: getFromIndex(int $index, int $len = 0, int $flags = 0): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс записи, начиная с 0. |
| len | Максимальное число байтов результата; 0 читает запись целиком. Для предсказуемого договора используйте 0 или положительное значение. |
| flags | FL_UNCHANGED читает прежнюю версию; FL_COMPRESSED выдаёт сжатые байты. |
Результат: Байтовая строка; пустая запись даёт "", отсутствие/отказ — false.
Отказ: false при отсутствии записи, недоступных новых данных, пароле/декомпрессии; повреждённые данные могут дать warning. name="" — ValueError. Полное чтение выделяет память под данные.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt хранит paid:42
- Вызов выбирает запись
- В строке PHP оказываются 7 байтов
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Это байты содержимого, а не имя и не распакованный файл на диске.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromIndex(0, 4), "\n";
var_export($zip->getFromIndex(9)); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid
false
Первые 4 байта подходят для ASCII-маркера. Ограниченный префикс не доказывает целостность всего содержимого; UTF-8 можно разрезать посередине символа.
Большой документ читайте потоком; ни расширение имени, ни успешная декомпрессия не делают содержимое доверенным. FL_COMPRESSED не выдаёт готовый самостоятельный ZIP-файл. Новые/заменённые данные сначала сохраните и откройте повторно.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getStream, ZipArchive::statName.
ZipArchive::statNameУзнать размер и способ сжатия документа до выделения памяти.
PHP 5.2 / PECL 1.5+ · zip
statName(string $name, int $flags = 0): array|falseУзнать размер и способ сжатия документа до выделения памяти.
Синтаксис: statName(string $name, int $flags = 0): array|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Имя записи. |
| flags | FL_UNCHANGED — исходные сведения. FL_NOCASE и FL_NODIR меняют поиск. |
Результат: Ассоциативный массив: name, index, crc, size (байты после распаковки), mtime (Unix timestamp), comp_size (сжатые байты), comp_method (CM_*), encryption_method (EM_*). PHP добавляет доступные поля libzip; не полагайтесь на порядок ключей.
Отказ: false при неизвестной записи/отказе; пустое name — ValueError. Для ещё не записанного источника некоторые сведения могут быть недоступны.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt найден
- size=7 описывает распакованные байты
- Приложение сравнивает размер со своим лимитом
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$info = $zip->statName("order.txt");
if ($info === false) throw new RuntimeException("Нет записи");
echo $info["name"], ":", $info["size"], "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt:7
size и comp_size различаются по смыслу; коэффициент сжатия не является гарантией безопасности.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$info = $zip->statName("order.txt");
if ($info === false) throw new RuntimeException("Нет записи");
echo $info["size"] <= 1024 ? "В пределах 1 KiB\n" : "Слишком большой\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
В пределах 1 KiB
Это только предварительная проверка метаданных; при потоковом чтении дополнительно считайте реально полученные байты и ограничивайте время/число записей.
CRC — контроль случайной порчи, не криптографическое доказательство автора. mtime зависит от точности ZIP/временной зоны; не используйте его как уникальную версию. После извлечения права автоматически не восстанавливаются.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getFromName, ZipArchive::getExternalAttributesName.
ZipArchive::statIndexУзнать размер и способ сжатия документа до выделения памяти.
PHP 5.2 / PECL 1.1+ · zip
statIndex(int $index, int $flags = 0): array|falseУзнать размер и способ сжатия документа до выделения памяти.
Синтаксис: statIndex(int $index, int $flags = 0): array|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс записи. |
| flags | FL_UNCHANGED — исходные сведения. |
Результат: Ассоциативный массив: name, index, crc, size (байты после распаковки), mtime (Unix timestamp), comp_size (сжатые байты), comp_method (CM_*), encryption_method (EM_*). PHP добавляет доступные поля libzip; не полагайтесь на порядок ключей.
Отказ: false при неизвестной записи/отказе; пустое name — ValueError. Для ещё не записанного источника некоторые сведения могут быть недоступны.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt найден
- size=7 описывает распакованные байты
- Приложение сравнивает размер со своим лимитом
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$info = $zip->statIndex(0);
if ($info === false) throw new RuntimeException("Нет записи");
echo $info["name"], ":", $info["size"], "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt:7
size и comp_size различаются по смыслу; коэффициент сжатия не является гарантией безопасности.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$info = $zip->statIndex(0);
if ($info === false) throw new RuntimeException("Нет записи");
echo $info["size"] <= 1024 ? "В пределах 1 KiB\n" : "Слишком большой\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
В пределах 1 KiB
Это только предварительная проверка метаданных; при потоковом чтении дополнительно считайте реально полученные байты и ограничивайте время/число записей.
CRC — контроль случайной порчи, не криптографическое доказательство автора. mtime зависит от точности ZIP/временной зоны; не используйте его как уникальную версию. После извлечения права автоматически не восстанавливаются.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getFromName, ZipArchive::getExternalAttributesName.
ZipArchive::getStreamЧитать документ небольшими порциями, не помещая его целиком в память.
PHP 5.2 / PECL 1.1+ · zip
getStream(string $name): resource|falseЧитать документ небольшими порциями, не помещая его целиком в память.
Синтаксис: getStream(string $name): resource|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Имя записи. |
Результат: Открытый поток только для чтения или false. Для потока работают fread(), stream_get_contents(), fclose(); это не объект ZipArchive.
Отказ: false при недоступной записи/данных/пароле; имя не может быть пустым. Обрабатывайте false и от операций чтения. Открытый архив и поток имеют отдельное время жизни.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt → поток
- fread(...,4) → paid
- Закрываем поток
- Затем закрываем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$stream = $zip->getStream("order.txt");
if ($stream === false) throw new RuntimeException("Нет потока");
echo fread($stream, 4), "\n";
fclose($stream);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid
resource — дескриптор открытого потока; fclose закрывает именно его. Поток создан для чтения, fwrite здесь не подходит.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$stream = $zip->getStream("order.txt");
if ($stream === false) throw new RuntimeException("Нет потока");
try {
$body = stream_get_contents($stream, 9);
if ($body === false || strlen($body) > 8) throw new RuntimeException("Лимит");
echo $body, "\n";
} finally {
fclose($stream);
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Читаем лимит+1, чтобы обнаружить превышение; finally освобождает поток и при исключении. В большом импорте обрабатывайте порции и суммарный счётчик.
Не обещайте произвольный seek или запись. Закрывайте потоки до архива, не меняйте читаемую запись одновременно. Содержимое новых записей может быть недоступно до close()/open().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getFromName, ZipArchive::close.
ZipArchive::getStreamNameЧитать документ небольшими порциями, не помещая его целиком в память.
PHP 8.2 / PECL 1.20+ · zip
getStreamName(string $name, int $flags = 0): resource|falseЧитать документ небольшими порциями, не помещая его целиком в память.
Синтаксис: getStreamName(string $name, int $flags = 0): resource|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Имя записи. |
| flags | FL_UNCHANGED — исходная версия записи. |
Результат: Открытый поток только для чтения или false. Для потока работают fread(), stream_get_contents(), fclose(); это не объект ZipArchive.
Отказ: false при недоступной записи/данных/пароле; имя не может быть пустым. Обрабатывайте false и от операций чтения. Открытый архив и поток имеют отдельное время жизни.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt → поток
- fread(...,4) → paid
- Закрываем поток
- Затем закрываем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$stream = $zip->getStreamName("order.txt");
if ($stream === false) throw new RuntimeException("Нет потока");
echo fread($stream, 4), "\n";
fclose($stream);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid
resource — дескриптор открытого потока; fclose закрывает именно его. Поток создан для чтения, fwrite здесь не подходит.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$stream = $zip->getStreamName("order.txt");
if ($stream === false) throw new RuntimeException("Нет потока");
try {
$body = stream_get_contents($stream, 9);
if ($body === false || strlen($body) > 8) throw new RuntimeException("Лимит");
echo $body, "\n";
} finally {
fclose($stream);
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Читаем лимит+1, чтобы обнаружить превышение; finally освобождает поток и при исключении. В большом импорте обрабатывайте порции и суммарный счётчик.
Не обещайте произвольный seek или запись. Закрывайте потоки до архива, не меняйте читаемую запись одновременно. Содержимое новых записей может быть недоступно до close()/open().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getFromName, ZipArchive::close.
ZipArchive::getStreamIndexЧитать документ небольшими порциями, не помещая его целиком в память.
PHP 8.2 / PECL 1.20+ · zip
getStreamIndex(int $index, int $flags = 0): resource|falseЧитать документ небольшими порциями, не помещая его целиком в память.
Синтаксис: getStreamIndex(int $index, int $flags = 0): resource|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Номер записи от 0. |
| flags | FL_UNCHANGED — исходная версия записи. |
Результат: Открытый поток только для чтения или false. Для потока работают fread(), stream_get_contents(), fclose(); это не объект ZipArchive.
Отказ: false при недоступной записи/данных/пароле; имя не может быть пустым. Обрабатывайте false и от операций чтения. Открытый архив и поток имеют отдельное время жизни.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt → поток
- fread(...,4) → paid
- Закрываем поток
- Затем закрываем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$stream = $zip->getStreamIndex(0);
if ($stream === false) throw new RuntimeException("Нет потока");
echo fread($stream, 4), "\n";
fclose($stream);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid
resource — дескриптор открытого потока; fclose закрывает именно его. Поток создан для чтения, fwrite здесь не подходит.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$stream = $zip->getStreamIndex(0);
if ($stream === false) throw new RuntimeException("Нет потока");
try {
$body = stream_get_contents($stream, 9);
if ($body === false || strlen($body) > 8) throw new RuntimeException("Лимит");
echo $body, "\n";
} finally {
fclose($stream);
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Читаем лимит+1, чтобы обнаружить превышение; finally освобождает поток и при исключении. В большом импорте обрабатывайте порции и суммарный счётчик.
Не обещайте произвольный seek или запись. Закрывайте потоки до архива, не меняйте читаемую запись одновременно. Содержимое новых записей может быть недоступно до close()/open().
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getFromName, ZipArchive::close.
ZipArchive::getStatusStringПолучить понятную диагностику внутреннего отказа ZIP.
PHP 5.2.7+; после close() PHP 8.0 / PECL 1.18+ · zip
getStatusString(): stringПолучить понятную диагностику внутреннего отказа ZIP.
Синтаксис: getStatusString(): string. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| Нет аргументов | Скобки () обязательны. |
Результат: Текст текущей ошибки ZIP/системы; с PHP 8.0 возвращает только string и доступен после close().
Отказ: Текст зависит от libzip/ОС: не сравнивайте его целиком для бизнес-ветвления; используйте status и ER_*.
- Не найден missing.txt
- Статус фиксирует отказ
- Текст подходит для закрытого технического журнала
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->locateName("missing.txt");
echo $zip->status === ZipArchive::ER_NOENT ? "Нет записи\n" : "Иной код\n";
echo $zip->getStatusString() !== "" ? "Есть описание\n" : "Пусто\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Нет записи
Есть описание
Журнал может содержать чувствительные пути: не отдавайте его клиенту целиком.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->locateName("missing.txt");
$zip->clearError();
echo $zip->status === ZipArchive::ER_OK ? "OK\n" : "Ошибка\n";
echo $zip->getStatusString() !== "" ? "Есть описание состояния\n" : "Пусто\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
OK
Есть описание состояния
Текст существует и для нормального состояния, поэтому непустая строка сама по себе не признак ошибки.
open() возвращает собственный код отказа: сохраняйте его сразу. Не рассчитывайте, что всякий успешный следующий вызов обязательно очистил прошлую ошибку.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::clearError, ZipArchive::open.
ZipArchive::clearErrorОтделить уже обработанный отказ от новой операции.
PHP 8.2 / PECL 1.20+ · zip
clearError(): voidОтделить уже обработанный отказ от новой операции.
Синтаксис: clearError(): void. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| Нет аргументов | Скобки () обязательны. |
Результат: Ничего не возвращает; очищает ZIP- и системную часть ошибки. Это не отмена изменений и не исправление файла.
Отказ: Доступен и после close(); сброс не доказывает успешность предыдущей операции.
- locateName не нашёл missing.txt
- Приложение обработало отсутствие
- clearError сбрасывает status в ER_OK
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->locateName("missing.txt");
$zip->clearError();
echo $zip->status === ZipArchive::ER_OK ? "Сброшено\n" : "Ошибка\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Сброшено
Не скрывайте необработанный отказ простым сбросом.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$zip->clearError();
echo $zip->status, ":", $zip->statusSys, "\n";
unlink($path);
Ожидаемый результат
0:0
Метод работает с сохранёнными кодами закрытого объекта; другие операции над записями всё ещё требуют open().
Для отката изменений есть unchangeAll(). Сброс ошибки не аналог отката и не повтор операции.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getStatusString, ZipArchive::unchangeAll.
ZipArchive::extractToВыдать проверенные документы из архива в отдельную рабочую папку.
PHP 5.2+; PECL zip · zip
extractTo(string $pathto, array|string|null $files = null): boolВыдать проверенные документы из архива в отдельную рабочую папку.
Синтаксис: extractTo(string $pathto, array|string|null $files = null): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| pathto | Каталог назначения; отсутствующий каталог может быть создан рекурсивно. |
| files | null — все записи; string — одно имя; список строк с индексами 0..n-1 — выбранные имена. [] в PHP 8.5.11 возвращает false; это не «ничего успешно». |
Результат: true при успешной выбранной распаковке; false при отказе. Уже извлечённые до ошибки файлы могут остаться.
Отказ: Права, недопустимые имена, повреждённые данные, пароль и нехватка места могут дать warning/false. Это не транзакция.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- В ZIP один проверенный order.txt
- Создаём отдельную пустую папку unpack
- Извлекаем только order.txt
- Читаем paid:42
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$dest = __DIR__ . "/unpack";
mkdir($dest, 0700);
if (!$zip->extractTo($dest, "order.txt")) throw new RuntimeException("Не извлечён");
echo file_get_contents($dest . "/order.txt"), "\n";
unlink($dest . "/order.txt");
rmdir($dest);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Своя новая папка исключает случайную перезапись существующего пользовательского документа. Пример получает собственный доверенный ZIP.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$allowed = ["order.txt"];
foreach ($allowed as $name) {
if ($zip->locateName($name) === false) throw new RuntimeException("Неполный пакет");
}
$dest = __DIR__ . "/unpack";
mkdir($dest, 0700);
if (!$zip->extractTo($dest, $allowed)) throw new RuntimeException("Ошибка распаковки");
echo count($allowed), " документ\n";
unlink($dest . "/order.txt");
rmdir($dest);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
1 документ
Список имён — политика импорта; он не разрешает остальные записи архива.
Для недоверенных архивов сначала ограничьте число/суммарный размер/имена, запрещайте абсолютные пути, .., коллизии и нежелательные типы; подробнее в отдельном уроке. PHP 8.5.11 сам нормализует пути при extractTo(), поэтому не утверждаем, что любой ../ обязательно выйдет наружу, но молчаливая нормализация также может создать коллизию. Извлечение может перезаписывать файлы. Исходные UNIX-права не восстанавливаются: используются максимально разрешённые права с umask. В Windows <|>*?": и конечные точки могут вызвать отказ, без автоматического безопасного переименования.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex, ZipArchive::getStream, ZipArchive::getExternalAttributesIndex.
ZipArchive::setArchiveCommentСнабдить всю поставку пояснением.
PHP 5.2 / PECL 1.4+ · zip
setArchiveComment(string $comment): boolСнабдить всю поставку пояснением.
Синтаксис: setArchiveComment(string $comment): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| comment | Строка комментария; "" удаляет комментарий. Максимум 65535 байтов, не Unicode-символов. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: Комментарий длиннее 65535 байтов — ValueError; отсутствующая запись/отказ libzip — false.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt уже сохранён
- Комментарий «Поставка 42» записан архиву
- Получатель читает пояснение
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveComment("Поставка 42");
echo $zip->getArchiveComment(), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Поставка 42
Комментарий — метаданные ZIP, не дополнительный текстовый файл; он не шифруется вместе с содержимым записи.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveComment("Поставка 42");
$zip->setArchiveComment("");
var_export($zip->getArchiveComment() === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
true
Пустой комментарий — успешный результат; false имеет другой смысл. FL_UNCHANGED не делает откат.
Не храните секреты в комментариях и не выводите их в HTML без экранирования. Сохранение требует close(). Общий комментарий виден также в readonly-свойстве comment; комментарии отдельных записей читаются отдельными методами.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getArchiveComment, ZipArchive::close.
ZipArchive::getArchiveCommentПрочитать пояснение ко всей поставке.
PHP 5.2 / PECL 1.1+ · zip
getArchiveComment(int $flags = 0): string|falseПрочитать пояснение ко всей поставке.
Синтаксис: getArchiveComment(int $flags = 0): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| flags | FL_UNCHANGED читает первоначальный комментарий до текущих изменений. |
Результат: Строка, включая "" при отсутствии комментария, либо false при отказе.
Отказ: false при недоступной записи/ошибке; пустое имя записи — ValueError.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt уже сохранён
- Комментарий «Поставка 42» записан архиву
- Получатель читает пояснение
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveComment("Поставка 42");
echo $zip->getArchiveComment(), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Поставка 42
Комментарий — метаданные ZIP, не дополнительный текстовый файл; он не шифруется вместе с содержимым записи.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveComment("Черновик");
echo $zip->getArchiveComment(), "\n";
var_export($zip->getArchiveComment(ZipArchive::FL_UNCHANGED) === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Черновик
true
Пустой комментарий — успешный результат; false имеет другой смысл. FL_UNCHANGED не делает откат.
Не храните секреты в комментариях и не выводите их в HTML без экранирования. Сохранение требует close(). Общий комментарий виден также в readonly-свойстве comment; комментарии отдельных записей читаются отдельными методами.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setArchiveComment, ZipArchive::close.
ZipArchive::setCommentIndexСнабдить отдельный документ пояснением.
PHP 5.2 / PECL 1.4+ · zip
setCommentIndex(int $index, string $comment): boolСнабдить отдельный документ пояснением.
Синтаксис: setCommentIndex(int $index, string $comment): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс записи от 0. |
| comment | Строка комментария; "" удаляет комментарий. Максимум 65535 байтов, не Unicode-символов. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: Комментарий длиннее 65535 байтов — ValueError; отсутствующая запись/отказ libzip — false.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt уже сохранён
- Комментарий «Поставка 42» записан записи
- Получатель читает пояснение
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentIndex(0, "Поставка 42");
echo $zip->getCommentIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Поставка 42
Комментарий — метаданные ZIP, не дополнительный текстовый файл; он не шифруется вместе с содержимым записи.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentIndex(0, "Поставка 42");
$zip->setCommentIndex(0, "");
var_export($zip->getCommentIndex(0) === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
true
Пустой комментарий — успешный результат; false имеет другой смысл. FL_UNCHANGED не делает откат.
Не храните секреты в комментариях и не выводите их в HTML без экранирования. Сохранение требует close(). Общий комментарий виден также в readonly-свойстве comment; комментарии отдельных записей читаются отдельными методами.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getCommentIndex, ZipArchive::close.
ZipArchive::getCommentIndexПрочитать пояснение к конкретному документу.
PHP 5.2 / PECL 1.4+ · zip
getCommentIndex(int $index, int $flags = 0): string|falseПрочитать пояснение к конкретному документу.
Синтаксис: getCommentIndex(int $index, int $flags = 0): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс записи от 0. |
| flags | FL_UNCHANGED читает первоначальный комментарий до текущих изменений. |
Результат: Строка, включая "" при отсутствии комментария, либо false при отказе.
Отказ: false при недоступной записи/ошибке; пустое имя записи — ValueError.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt уже сохранён
- Комментарий «Поставка 42» записан записи
- Получатель читает пояснение
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentIndex(0, "Поставка 42");
echo $zip->getCommentIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Поставка 42
Комментарий — метаданные ZIP, не дополнительный текстовый файл; он не шифруется вместе с содержимым записи.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentIndex(0, "Черновик");
echo $zip->getCommentIndex(0), "\n";
var_export($zip->getCommentIndex(0, ZipArchive::FL_UNCHANGED) === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Черновик
true
Пустой комментарий — успешный результат; false имеет другой смысл. FL_UNCHANGED не делает откат.
Не храните секреты в комментариях и не выводите их в HTML без экранирования. Сохранение требует close(). Общий комментарий виден также в readonly-свойстве comment; комментарии отдельных записей читаются отдельными методами.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setCommentIndex, ZipArchive::close.
ZipArchive::setCommentNameСнабдить отдельный документ пояснением.
PHP 5.2 / PECL 1.4+ · zip
setCommentName(string $name, string $comment): boolСнабдить отдельный документ пояснением.
Синтаксис: setCommentName(string $name, string $comment): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Точное имя записи. |
| comment | Строка комментария; "" удаляет комментарий. Максимум 65535 байтов, не Unicode-символов. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: Комментарий длиннее 65535 байтов — ValueError; отсутствующая запись/отказ libzip — false.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt уже сохранён
- Комментарий «Поставка 42» записан записи
- Получатель читает пояснение
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentName("order.txt", "Поставка 42");
echo $zip->getCommentName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Поставка 42
Комментарий — метаданные ZIP, не дополнительный текстовый файл; он не шифруется вместе с содержимым записи.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentName("order.txt", "Поставка 42");
$zip->setCommentName("order.txt", "");
var_export($zip->getCommentName("order.txt") === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
true
Пустой комментарий — успешный результат; false имеет другой смысл. FL_UNCHANGED не делает откат.
Не храните секреты в комментариях и не выводите их в HTML без экранирования. Сохранение требует close(). Общий комментарий виден также в readonly-свойстве comment; комментарии отдельных записей читаются отдельными методами.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getCommentName, ZipArchive::close.
ZipArchive::getCommentNameПрочитать пояснение к конкретному документу.
PHP 5.2 / PECL 1.4+ · zip
getCommentName(string $name, int $flags = 0): string|falseПрочитать пояснение к конкретному документу.
Синтаксис: getCommentName(string $name, int $flags = 0): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Точное имя записи. |
| flags | FL_UNCHANGED читает первоначальный комментарий до текущих изменений. |
Результат: Строка, включая "" при отсутствии комментария, либо false при отказе.
Отказ: false при недоступной записи/ошибке; пустое имя записи — ValueError.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt уже сохранён
- Комментарий «Поставка 42» записан записи
- Получатель читает пояснение
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentName("order.txt", "Поставка 42");
echo $zip->getCommentName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Поставка 42
Комментарий — метаданные ZIP, не дополнительный текстовый файл; он не шифруется вместе с содержимым записи.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setCommentName("order.txt", "Черновик");
echo $zip->getCommentName("order.txt"), "\n";
var_export($zip->getCommentName("order.txt", ZipArchive::FL_UNCHANGED) === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Черновик
true
Пустой комментарий — успешный результат; false имеет другой смысл. FL_UNCHANGED не делает откат.
Не храните секреты в комментариях и не выводите их в HTML без экранирования. Сохранение требует close(). Общий комментарий виден также в readonly-свойстве comment; комментарии отдельных записей читаются отдельными методами.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setCommentName, ZipArchive::close.
ZipArchive::setExternalAttributesIndexПометить документ переносимыми UNIX-атрибутами для архиватора получателя.
PHP 5.6 / PECL 1.12.4+ · zip
setExternalAttributesIndex(int $index, int $opsys, int $attr, int $flags = 0): boolПометить документ переносимыми UNIX-атрибутами для архиватора получателя.
Синтаксис: setExternalAttributesIndex(int $index, int $opsys, int $attr, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс записи от 0. |
| opsys | OPSYS_* обозначает систему, чьим правилам соответствуют атрибуты. |
| attr | Битовое поле внешних атрибутов; смысл зависит от opsys. Для UNIX верхние 16 бит содержат тип и права. |
| flags | В setter не используется; передавайте 0. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неизвестной записи/ошибке libzip; пустое имя — ValueError. PHP-тип/ссылочность аргументов также проверяются.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt — обычный файл
- 0100644: тип regular + права rw-r--r--
- Сдвиг <<16 помещает поле в ZIP
- Чтение возвращает 100644 в восьмеричном виде
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesIndex(0, ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesIndex(0, $system, $attributes)) throw new RuntimeException("Нет атрибутов");
echo $system === ZipArchive::OPSYS_UNIX ? "UNIX\n" : "Другое\n";
echo decoct(($attributes >> 16) & 0xffff), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
UNIX
100644
Начальный 0 в 0100644 — восьмеричная запись; << и >> сдвигают биты, & оставляет нужное поле. Это меняет метаданные ZIP, а не chmod локального файла.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesIndex(0, ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesIndex(0, $system, $attributes)) throw new RuntimeException("Нет атрибутов");
$isRegular = $system === ZipArchive::OPSYS_UNIX && (($attributes >> 16) & 0170000) === 0100000;
echo $isRegular ? "Обычный файл\n" : "Нужна другая политика\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Обычный файл
Маска 0170000 выделяет тип. Если система не UNIX, эти биты нельзя трактовать по UNIX-правилам; консервативный импорт должен выбрать явную политику.
Атрибуты прислал автор архива; они не делают содержимое безопасным. extractTo() не восстанавливает исходные UNIX-права автоматически. Не применяйте сохранённые права вслепую, особенно исполняемые/setuid-биты.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::extractTo, ZipArchive::statIndex.
ZipArchive::getExternalAttributesIndexПроверить тип/права записи по метаданным создавшей её системы.
PHP 5.6 / PECL 1.12.4+ · zip
getExternalAttributesIndex(int $index, int &$opsys, int &$attr, int $flags = 0): boolПроверить тип/права записи по метаданным создавшей её системы.
Синтаксис: getExternalAttributesIndex(int $index, int &$opsys, int &$attr, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс записи от 0. |
| opsys | OPSYS_* обозначает систему, чьим правилам соответствуют атрибуты. Выходной параметр по ссылке &, записывается при успехе. |
| attr | Битовое поле внешних атрибутов; смысл зависит от opsys. Для UNIX верхние 16 бит содержат тип и права. Выходной параметр по ссылке &. |
| flags | FL_UNCHANGED — исходные атрибуты. |
Результат: true и два выходных значения при успехе; false при отказе. Не используйте выходные переменные после false.
Отказ: false при неизвестной записи/ошибке libzip; пустое имя — ValueError. PHP-тип/ссылочность аргументов также проверяются.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt — обычный файл
- 0100644: тип regular + права rw-r--r--
- Сдвиг <<16 помещает поле в ZIP
- Чтение возвращает 100644 в восьмеричном виде
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesIndex(0, ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesIndex(0, $system, $attributes)) throw new RuntimeException("Нет атрибутов");
echo $system === ZipArchive::OPSYS_UNIX ? "UNIX\n" : "Другое\n";
echo decoct(($attributes >> 16) & 0xffff), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
UNIX
100644
Начальный 0 в 0100644 — восьмеричная запись; << и >> сдвигают биты, & оставляет нужное поле. Это меняет метаданные ZIP, а не chmod локального файла.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesIndex(0, ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesIndex(0, $system, $attributes)) throw new RuntimeException("Нет атрибутов");
$isRegular = $system === ZipArchive::OPSYS_UNIX && (($attributes >> 16) & 0170000) === 0100000;
echo $isRegular ? "Обычный файл\n" : "Нужна другая политика\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Обычный файл
Маска 0170000 выделяет тип. Если система не UNIX, эти биты нельзя трактовать по UNIX-правилам; консервативный импорт должен выбрать явную политику.
Атрибуты прислал автор архива; они не делают содержимое безопасным. extractTo() не восстанавливает исходные UNIX-права автоматически. Не применяйте сохранённые права вслепую, особенно исполняемые/setuid-биты.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::extractTo, ZipArchive::statIndex.
ZipArchive::setMtimeIndexСохранить время изменения документа при формировании архивной поставки.
PHP 8.0 / PECL 1.16+, libzip 1.0+ · zip
setMtimeIndex(int $index, int $timestamp, int $flags = 0): boolСохранить время изменения документа при формировании архивной поставки.
Синтаксис: setMtimeIndex(int $index, int $timestamp, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс либо точное имя существующей записи. |
| timestamp | Unix timestamp в секундах; это не миллисекунды JavaScript. |
| flags | Пока не используется, передавайте 0. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неизвестной записи/ошибке libzip; пустое имя — ValueError. Доступность метода требует подходящей libzip.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- 2024-01-01 00:00:00 UTC → 1704067200
- Устанавливаем секунды для order.txt
- Сохраняем и открываем ZIP
- stat показывает выбранное время
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
date_default_timezone_set("UTC");
$zip->setMtimeIndex(0, 1704067200);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo gmdate("Y-m-d H:i:s", $zip->statIndex(0)["mtime"]), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
2024-01-01 00:00:00
Время фиксировано и зона UTC задана явно; архивный формат может округлять точность, поэтому здесь выбрана чётная секунда.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
date_default_timezone_set("UTC");
$zip->addFromString("note.txt", "ok");
$zip->setMtimeIndex(0, 1704067200);
$zip->setMtimeIndex(1, 1704067200);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->statIndex(0)["mtime"] === $zip->statIndex(1)["mtime"] ? "Один выпуск\n" : "Разные даты\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Один выпуск
Единая метка полезна для выпуска, но сама по себе не делает ZIP побайтово воспроизводимым: есть порядок, кодеки, прочие метаданные.
Базовые DOS-поля ZIP имеют ограниченный диапазон и двухсекундную точность; дополнительные поля и поведение libzip могут отличаться. Не используйте mtime для доказательства авторства или идентичности файла.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex, ZipArchive::addFile.
ZipArchive::setExternalAttributesNameПометить документ переносимыми UNIX-атрибутами для архиватора получателя.
PHP 5.6 / PECL 1.12.4+ · zip
setExternalAttributesName(string $name, int $opsys, int $attr, int $flags = 0): boolПометить документ переносимыми UNIX-атрибутами для архиватора получателя.
Синтаксис: setExternalAttributesName(string $name, int $opsys, int $attr, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Точное имя записи. |
| opsys | OPSYS_* обозначает систему, чьим правилам соответствуют атрибуты. |
| attr | Битовое поле внешних атрибутов; смысл зависит от opsys. Для UNIX верхние 16 бит содержат тип и права. |
| flags | В setter не используется; передавайте 0. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неизвестной записи/ошибке libzip; пустое имя — ValueError. PHP-тип/ссылочность аргументов также проверяются.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt — обычный файл
- 0100644: тип regular + права rw-r--r--
- Сдвиг <<16 помещает поле в ZIP
- Чтение возвращает 100644 в восьмеричном виде
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesName("order.txt", ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesName("order.txt", $system, $attributes)) throw new RuntimeException("Нет атрибутов");
echo $system === ZipArchive::OPSYS_UNIX ? "UNIX\n" : "Другое\n";
echo decoct(($attributes >> 16) & 0xffff), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
UNIX
100644
Начальный 0 в 0100644 — восьмеричная запись; << и >> сдвигают биты, & оставляет нужное поле. Это меняет метаданные ZIP, а не chmod локального файла.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesName("order.txt", ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesName("order.txt", $system, $attributes)) throw new RuntimeException("Нет атрибутов");
$isRegular = $system === ZipArchive::OPSYS_UNIX && (($attributes >> 16) & 0170000) === 0100000;
echo $isRegular ? "Обычный файл\n" : "Нужна другая политика\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Обычный файл
Маска 0170000 выделяет тип. Если система не UNIX, эти биты нельзя трактовать по UNIX-правилам; консервативный импорт должен выбрать явную политику.
Атрибуты прислал автор архива; они не делают содержимое безопасным. extractTo() не восстанавливает исходные UNIX-права автоматически. Не применяйте сохранённые права вслепую, особенно исполняемые/setuid-биты.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::extractTo, ZipArchive::statIndex.
ZipArchive::getExternalAttributesNameПроверить тип/права записи по метаданным создавшей её системы.
PHP 5.6 / PECL 1.12.4+ · zip
getExternalAttributesName(string $name, int &$opsys, int &$attr, int $flags = 0): boolПроверить тип/права записи по метаданным создавшей её системы.
Синтаксис: getExternalAttributesName(string $name, int &$opsys, int &$attr, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Точное имя записи. |
| opsys | OPSYS_* обозначает систему, чьим правилам соответствуют атрибуты. Выходной параметр по ссылке &, записывается при успехе. |
| attr | Битовое поле внешних атрибутов; смысл зависит от opsys. Для UNIX верхние 16 бит содержат тип и права. Выходной параметр по ссылке &. |
| flags | FL_UNCHANGED — исходные атрибуты. |
Результат: true и два выходных значения при успехе; false при отказе. Не используйте выходные переменные после false.
Отказ: false при неизвестной записи/ошибке libzip; пустое имя — ValueError. PHP-тип/ссылочность аргументов также проверяются.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt — обычный файл
- 0100644: тип regular + права rw-r--r--
- Сдвиг <<16 помещает поле в ZIP
- Чтение возвращает 100644 в восьмеричном виде
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesName("order.txt", ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesName("order.txt", $system, $attributes)) throw new RuntimeException("Нет атрибутов");
echo $system === ZipArchive::OPSYS_UNIX ? "UNIX\n" : "Другое\n";
echo decoct(($attributes >> 16) & 0xffff), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
UNIX
100644
Начальный 0 в 0100644 — восьмеричная запись; << и >> сдвигают биты, & оставляет нужное поле. Это меняет метаданные ZIP, а не chmod локального файла.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setExternalAttributesName("order.txt", ZipArchive::OPSYS_UNIX, 0100644 << 16);
$system = 0; $attributes = 0;
if (!$zip->getExternalAttributesName("order.txt", $system, $attributes)) throw new RuntimeException("Нет атрибутов");
$isRegular = $system === ZipArchive::OPSYS_UNIX && (($attributes >> 16) & 0170000) === 0100000;
echo $isRegular ? "Обычный файл\n" : "Нужна другая политика\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Обычный файл
Маска 0170000 выделяет тип. Если система не UNIX, эти биты нельзя трактовать по UNIX-правилам; консервативный импорт должен выбрать явную политику.
Атрибуты прислал автор архива; они не делают содержимое безопасным. extractTo() не восстанавливает исходные UNIX-права автоматически. Не применяйте сохранённые права вслепую, особенно исполняемые/setuid-биты.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::extractTo, ZipArchive::statIndex.
ZipArchive::setMtimeNameСохранить время изменения документа при формировании архивной поставки.
PHP 8.0 / PECL 1.16+, libzip 1.0+ · zip
setMtimeName(string $name, int $timestamp, int $flags = 0): boolСохранить время изменения документа при формировании архивной поставки.
Синтаксис: setMtimeName(string $name, int $timestamp, int $flags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Индекс либо точное имя существующей записи. |
| timestamp | Unix timestamp в секундах; это не миллисекунды JavaScript. |
| flags | Пока не используется, передавайте 0. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неизвестной записи/ошибке libzip; пустое имя — ValueError. Доступность метода требует подходящей libzip.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- 2024-01-01 00:00:00 UTC → 1704067200
- Устанавливаем секунды для order.txt
- Сохраняем и открываем ZIP
- stat показывает выбранное время
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
date_default_timezone_set("UTC");
$zip->setMtimeName("order.txt", 1704067200);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo gmdate("Y-m-d H:i:s", $zip->statIndex(0)["mtime"]), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
2024-01-01 00:00:00
Время фиксировано и зона UTC задана явно; архивный формат может округлять точность, поэтому здесь выбрана чётная секунда.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
date_default_timezone_set("UTC");
$zip->addFromString("note.txt", "ok");
$zip->setMtimeName("order.txt", 1704067200);
$zip->setMtimeName("note.txt", 1704067200);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->statIndex(0)["mtime"] === $zip->statIndex(1)["mtime"] ? "Один выпуск\n" : "Разные даты\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Один выпуск
Единая метка полезна для выпуска, но сама по себе не делает ZIP побайтово воспроизводимым: есть порядок, кодеки, прочие метаданные.
Базовые DOS-поля ZIP имеют ограниченный диапазон и двухсекундную точность; дополнительные поля и поведение libzip могут отличаться. Не используйте mtime для доказательства авторства или идентичности файла.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex, ZipArchive::addFile.
ZipArchive::setArchiveFlagСохранить намеренно пустой архив и управлять общими признаками ZIP.
PHP 8.3 / PECL 1.22+, libzip 1.10+ · zip
setArchiveFlag(int $flag, int $value): boolСохранить намеренно пустой архив и управлять общими признаками ZIP.
Синтаксис: setArchiveFlag(int $flag, int $value): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| flag | Для изменения: AFL_WANT_TORRENTZIP, AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE, вручную устанавливаемый AFL_RDONLY; AFL_IS_TORRENTZIP только читается. |
| value | Ноль выключает, ненулевое значение включает. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при недопустимом/неизменяемом флаге или ошибке.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Новый ZIP без записей
- Включаем KEEP_FILE_FOR_EMPTY_ARCHIVE
- getArchiveFlag даёт 1
- close сохраняет пустой ZIP
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->setArchiveFlag(ZipArchive::AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE, 1);
echo $zip->getArchiveFlag(ZipArchive::AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
echo is_file($path) ? "ZIP сохранён\n" : "Нет\n";
unlink($path);
Ожидаемый результат
1
ZIP сохранён
Возможность требует PHP 8.3 / PECL 1.22 и libzip 1.10; это не то же самое, что нулевой файл.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveFlag(ZipArchive::AFL_WANT_TORRENTZIP, 1);
echo $zip->getArchiveFlag(ZipArchive::AFL_WANT_TORRENTZIP) === 1 ? "Запрошен TorrentZip\n" : "Нет\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Запрошен TorrentZip
AFL_RDONLY от open(RDONLY) нельзя снять; вручную установленный через setArchiveFlag можно снять обратно (уточнение libzip к краткому тексту PHP.net). AFL_IS_TORRENTZIP — наблюдаемый признак. WANT_TORRENTZIP запрашивает формат для записи и не доказывает, что несохранённые изменения уже применены.
Эти AFL_* отличаются от flags аргумента open() и от FL_* операций над записями. Не передавайте их взаимозаменяемо. TorrentZip задаёт специальное стандартизованное представление архива и может менять метаданные.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::close, ZipArchive::open.
ZipArchive::getArchiveFlagПроверить общий признак архива, не перепутав ошибку -1 с true.
PHP 8.3 / PECL 1.22+, libzip 1.10+ · zip
getArchiveFlag(int $flag, int $flags = 0): intПроверить общий признак архива, не перепутав ошибку -1 с true.
Синтаксис: getArchiveFlag(int $flag, int $flags = 0): int. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| flag | Для изменения: AFL_WANT_TORRENTZIP, AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE, вручную устанавливаемый AFL_RDONLY; AFL_IS_TORRENTZIP только читается. |
| flags | FL_UNCHANGED читает значение, с которым архив был открыт. |
Результат: 1 — установлен, 0 — не установлен, -1 — ошибка. Используйте === 1, а не приведение к bool.
Отказ: -1 при ошибке флага; это целое truthy-значение.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Новый ZIP без записей
- Включаем KEEP_FILE_FOR_EMPTY_ARCHIVE
- getArchiveFlag даёт 1
- close сохраняет пустой ZIP
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->setArchiveFlag(ZipArchive::AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE, 1);
echo $zip->getArchiveFlag(ZipArchive::AFL_CREATE_OR_KEEP_FILE_FOR_EMPTY_ARCHIVE), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
echo is_file($path) ? "ZIP сохранён\n" : "Нет\n";
unlink($path);
Ожидаемый результат
1
ZIP сохранён
Возможность требует PHP 8.3 / PECL 1.22 и libzip 1.10; это не то же самое, что нулевой файл.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path, ZipArchive::RDONLY) !== true) throw new RuntimeException("Нет ZIP");
echo $zip->getArchiveFlag(ZipArchive::AFL_RDONLY) === 1 ? "Только чтение\n" : "Другое\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Только чтение
AFL_RDONLY от open(RDONLY) нельзя снять; вручную установленный через setArchiveFlag можно снять обратно (уточнение libzip к краткому тексту PHP.net). AFL_IS_TORRENTZIP — наблюдаемый признак. WANT_TORRENTZIP запрашивает формат для записи и не доказывает, что несохранённые изменения уже применены.
Эти AFL_* отличаются от flags аргумента open() и от FL_* операций над записями. Не передавайте их взаимозаменяемо. TorrentZip задаёт специальное стандартизованное представление архива и может менять метаданные.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::close, ZipArchive::open.
ZipArchive::deleteIndexИсключить устаревший документ из поставки.
PHP 5.2 / PECL 1.5+ · zip
deleteIndex(int $index): boolИсключить устаревший документ из поставки.
Синтаксис: deleteIndex(int $index): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Текущий индекс записи от 0. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отсутствии записи/конфликте имени/отказе libzip. deleteName/unchangeName с пустым name возвращают false; renameName с пустым name и rename с пустым new_name бросают ValueError. Откат может отказать, если прежнее имя теперь занято другой записью.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt открыт с диска
- Запись помечается удалённой
- Изменение видно в открытом объекте; close фиксирует оставшееся
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->deleteIndex(0);
var_export($zip->locateName("order.txt")); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
false
Операция меняет запись ZIP, не удаляет/переименовывает исходный файл на компьютере.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->deleteIndex(0);
$zip->unchangeIndex(0);
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Для отката по имени после rename используйте новое текущее имя. Удалённую запись удобно восстановить по сохранённому индексу.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться. unchange* возвращает состояние на момент последнего open(), а не произвольную историю версий и не уже сохранённую предыдущим close() редакцию. После удаления последней записи close() по умолчанию удаляет пустой ZIP.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeAll, ZipArchive::close.
ZipArchive::deleteNameИсключить устаревший документ из поставки.
PHP 5.2 / PECL 1.5+ · zip
deleteName(string $name): boolИсключить устаревший документ из поставки.
Синтаксис: deleteName(string $name): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Текущее имя записи, включая путь внутри ZIP. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отсутствии записи/конфликте имени/отказе libzip. deleteName/unchangeName с пустым name возвращают false; renameName с пустым name и rename с пустым new_name бросают ValueError. Откат может отказать, если прежнее имя теперь занято другой записью.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt открыт с диска
- Запись помечается удалённой
- Изменение видно в открытом объекте; close фиксирует оставшееся
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->deleteName("order.txt");
var_export($zip->locateName("order.txt")); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
false
Операция меняет запись ZIP, не удаляет/переименовывает исходный файл на компьютере.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->deleteName("order.txt");
$zip->unchangeIndex(0);
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Для отката по имени после rename используйте новое текущее имя. Удалённую запись удобно восстановить по сохранённому индексу.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться. unchange* возвращает состояние на момент последнего open(), а не произвольную историю версий и не уже сохранённую предыдущим close() редакцию. После удаления последней записи close() по умолчанию удаляет пустой ZIP.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeAll, ZipArchive::close.
ZipArchive::renameIndexПереименовать документ внутри ZIP, сохранив его содержимое.
PHP 5.2 / PECL 1.5+ · zip
renameIndex(int $index, string $new_name): boolПереименовать документ внутри ZIP, сохранив его содержимое.
Синтаксис: renameIndex(int $index, string $new_name): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Текущий индекс записи от 0. |
| new_name | Новое непустое имя внутри ZIP. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отсутствии записи/конфликте имени/отказе libzip. deleteName/unchangeName с пустым name возвращают false; renameName с пустым name и rename с пустым new_name бросают ValueError. Откат может отказать, если прежнее имя теперь занято другой записью.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt открыт с диска
- Текущее имя становится receipt.txt
- Изменение видно в открытом объекте; close фиксирует оставшееся
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameIndex(0, "receipt.txt");
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
receipt.txt
Операция меняет запись ZIP, не удаляет/переименовывает исходный файл на компьютере.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameIndex(0, "receipt.txt");
echo $zip->getNameIndex(0, ZipArchive::FL_UNCHANGED), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Для отката по имени после rename используйте новое текущее имя. Удалённую запись удобно восстановить по сохранённому индексу.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться. unchange* возвращает состояние на момент последнего open(), а не произвольную историю версий и не уже сохранённую предыдущим close() редакцию. После удаления последней записи close() по умолчанию удаляет пустой ZIP.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeAll, ZipArchive::close.
ZipArchive::renameNameПереименовать документ внутри ZIP, сохранив его содержимое.
PHP 5.2 / PECL 1.5+ · zip
renameName(string $name, string $new_name): boolПереименовать документ внутри ZIP, сохранив его содержимое.
Синтаксис: renameName(string $name, string $new_name): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Текущее имя записи, включая путь внутри ZIP. |
| new_name | Новое непустое имя внутри ZIP. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отсутствии записи/конфликте имени/отказе libzip. deleteName/unchangeName с пустым name возвращают false; renameName с пустым name и rename с пустым new_name бросают ValueError. Откат может отказать, если прежнее имя теперь занято другой записью.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt открыт с диска
- Текущее имя становится receipt.txt
- Изменение видно в открытом объекте; close фиксирует оставшееся
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameName("order.txt", "receipt.txt");
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
receipt.txt
Операция меняет запись ZIP, не удаляет/переименовывает исходный файл на компьютере.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameName("order.txt", "receipt.txt");
echo $zip->getNameIndex(0, ZipArchive::FL_UNCHANGED), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Для отката по имени после rename используйте новое текущее имя. Удалённую запись удобно восстановить по сохранённому индексу.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться. unchange* возвращает состояние на момент последнего open(), а не произвольную историю версий и не уже сохранённую предыдущим close() редакцию. После удаления последней записи close() по умолчанию удаляет пустой ZIP.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeAll, ZipArchive::close.
ZipArchive::unchangeIndexОтменить подготовленное изменение одной записи до сохранения.
PHP 5.2 / PECL 1.1+ · zip
unchangeIndex(int $index): boolОтменить подготовленное изменение одной записи до сохранения.
Синтаксис: unchangeIndex(int $index): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Текущий индекс записи от 0. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отсутствии записи/конфликте имени/отказе libzip. deleteName/unchangeName с пустым name возвращают false; renameName с пустым name и rename с пустым new_name бросают ValueError. Откат может отказать, если прежнее имя теперь занято другой записью.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt открыт с диска
- Готовится замена paid:42 → cancelled:42, затем отменяется
- Изменение видно в открытом объекте; close фиксирует оставшееся
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->addFromString("order.txt", "cancelled:42");
$zip->unchangeIndex(0);
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Операция меняет запись ZIP, не удаляет/переименовывает исходный файл на компьютере.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameIndex(0, "receipt.txt");
$zip->unchangeIndex(0);
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Для отката по имени после rename используйте новое текущее имя. Удалённую запись удобно восстановить по сохранённому индексу.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться. unchange* возвращает состояние на момент последнего open(), а не произвольную историю версий и не уже сохранённую предыдущим close() редакцию. После удаления последней записи close() по умолчанию удаляет пустой ZIP.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeAll, ZipArchive::close.
ZipArchive::unchangeNameОтменить подготовленное изменение одной записи до сохранения.
PHP 5.2 / PECL 1.5+ · zip
unchangeName(string $name): boolОтменить подготовленное изменение одной записи до сохранения.
Синтаксис: unchangeName(string $name): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Текущее имя записи, включая путь внутри ZIP. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отсутствии записи/конфликте имени/отказе libzip. deleteName/unchangeName с пустым name возвращают false; renameName с пустым name и rename с пустым new_name бросают ValueError. Откат может отказать, если прежнее имя теперь занято другой записью.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt открыт с диска
- Готовится замена paid:42 → cancelled:42, затем отменяется
- Изменение видно в открытом объекте; close фиксирует оставшееся
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->addFromString("order.txt", "cancelled:42");
$zip->unchangeName("order.txt");
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Операция меняет запись ZIP, не удаляет/переименовывает исходный файл на компьютере.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->renameIndex(0, "receipt.txt");
$zip->unchangeName("receipt.txt");
echo $zip->getNameIndex(0), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
Для отката по имени после rename используйте новое текущее имя. Удалённую запись удобно восстановить по сохранённому индексу.
Имена внутри ZIP используют / даже на Windows. Они не должны автоматически становиться путями на сервере; правила извлечения разобраны в разделе безопасности. Индекс начинается с 0; после удаления в открытом архиве могут оставаться пропуски. После закрытия и открытия индексы могут измениться. unchange* возвращает состояние на момент последнего open(), а не произвольную историю версий и не уже сохранённую предыдущим close() редакцию. После удаления последней записи close() по умолчанию удаляет пустой ZIP.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeAll, ZipArchive::close.
ZipArchive::unchangeAllОтменить всю подготовленную партию изменений перед закрытием.
PHP 5.2 / PECL 1.1+ · zip
unchangeAll(): boolОтменить всю подготовленную партию изменений перед закрытием.
Синтаксис: unchangeAll(): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| Нет аргументов | Скобки () обязательны. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отказе libzip; открытый архив обязателен. Это не откат внешних файлов приложения.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Комментарий «Черновик» и новое имя receipt.txt подготовлены
- unchangeAll отменяет все изменения
- Приложение проверяет имя и комментарий
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveComment("Черновик");
$zip->renameIndex(0, "receipt.txt");
$zip->unchangeAll();
echo $zip->getNameIndex(0), "\n";
var_export($zip->getArchiveComment() === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
order.txt
true
Комментарий всего архива относится к общим данным; имя записи — к конкретному документу.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->addFromString("order.txt", "cancelled:42");
$zip->unchangeAll();
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Сравнение показывает, почему unchangeArchive не заменяет unchangeAll при отказе импорта. Проверяется уже сохранённое содержимое.
Исходная точка — состояние при open(). Для unchangeArchive официальная страница называет общие изменения, прежде всего комментарий; не рассчитывайте этим вызовом отменить изменения отдельных записей. Нельзя вернуть изменения после успешного close() без отдельной резервной версии.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeIndex, ZipArchive::close.
ZipArchive::unchangeArchiveОтменить только общие изменения архива, оставив изменения документов.
PHP 5.2 / PECL 1.1+ · zip
unchangeArchive(): boolОтменить только общие изменения архива, оставив изменения документов.
Синтаксис: unchangeArchive(): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| Нет аргументов | Скобки () обязательны. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при отказе libzip; открытый архив обязателен. Это не откат внешних файлов приложения.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Комментарий «Черновик» и новое имя receipt.txt подготовлены
- unchangeArchive отменяет только общие метаданные
- Приложение проверяет имя и комментарий
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setArchiveComment("Черновик");
$zip->renameIndex(0, "receipt.txt");
$zip->unchangeArchive();
echo $zip->getNameIndex(0), "\n";
var_export($zip->getArchiveComment() === ""); echo "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
receipt.txt
true
Комментарий всего архива относится к общим данным; имя записи — к конкретному документу.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->addFromString("order.txt", "cancelled:42");
$zip->unchangeArchive();
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
cancelled:42
Сравнение показывает, почему unchangeArchive не заменяет unchangeAll при отказе импорта. Проверяется уже сохранённое содержимое.
Исходная точка — состояние при open(). Для unchangeArchive официальная страница называет общие изменения, прежде всего комментарий; не рассчитывайте этим вызовом отменить изменения отдельных записей. Нельзя вернуть изменения после успешного close() без отдельной резервной версии.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::unchangeIndex, ZipArchive::close.
ZipArchive::isCompressionMethodSupportedПроверить отдельно запись и чтение выбранного способа сжатия.
PHP 8.0 / PECL 1.19+, libzip 1.7+ · zip
isCompressionMethodSupported(int $method, bool $enc = true): boolПроверить отдельно запись и чтение выбранного способа сжатия.
Синтаксис: isCompressionMethodSupported(int $method, bool $enc = true): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| method | Одна константа CM_* сжатия. Это значение, не набор флагов. |
| enc | true — создание (шифрование/сжатие); false — чтение (расшифровка/распаковка). |
Результат: true если конкретное направление поддерживается данной сборкой libzip; false если нет. Статический метод: экземпляр/открытый архив не нужен.
Отказ: Неизвестный/неподдерживаемый метод даёт false; неверный PHP-тип нарушает договор. Сам метод доступен с libzip 1.7.
- CM_DEFLATE — требование приложения
- Проверяется enc=true
- Только при поддержке включаем соответствующий кодек
<?php
declare(strict_types=1);
$method = ZipArchive::CM_DEFLATE;
$available = ZipArchive::isCompressionMethodSupported($method, true);
echo $available ? "Можно создать выбранный формат\n" : "Отказать: нужного кодека нет\n";
Ожидаемый результат
Можно создать выбранный формат
Ожидаемый вывод относится к проверенной сборке главы, где AES-256/DEFLATE поддерживаются. На другой сборке честная ветка отказа запрещает молча выдать документ без требуемой защиты/формата.
<?php
declare(strict_types=1);
$method = ZipArchive::CM_DEFLATE;
$canWrite = ZipArchive::isCompressionMethodSupported($method, true);
$canRead = ZipArchive::isCompressionMethodSupported($method, false);
if ($canWrite && $canRead) {
echo "Сервер может принять и выдать этот формат\n";
} else {
echo "Нужна другая сборка или согласованный формат\n";
}
Ожидаемый результат
Сервер может принять и выдать этот формат
Способность прочитать формат не обязана означать способность создать его; обе проверки влияют на допуск сервера к обмену. Вывод указан для проверенной сборки, возможности клиента проверяются отдельно.
Наличие CM_* / EM_* в классе не доказывает реализацию алгоритма. Поддержка здесь относится к серверной сборке, а не к архиватору получателя. Согласуйте формат с получателем и откажите явно, если обязательное шифрование недоступно.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setCompressionName.
ZipArchive::isEncryptionMethodSupportedВыбрать шифрование, которое умеет установленная libzip.
PHP 8.0 / PECL 1.19+, libzip 1.7+ · zip
isEncryptionMethodSupported(int $method, bool $enc = true): boolВыбрать шифрование, которое умеет установленная libzip.
Синтаксис: isEncryptionMethodSupported(int $method, bool $enc = true): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| method | Одна константа EM_* шифрования. |
| enc | true — создание (шифрование/сжатие); false — чтение (расшифровка/распаковка). |
Результат: true если конкретное направление поддерживается данной сборкой libzip; false если нет. Статический метод: экземпляр/открытый архив не нужен.
Отказ: Неизвестный/неподдерживаемый метод даёт false; неверный PHP-тип нарушает договор. Сам метод доступен с libzip 1.7.
- EM_AES_256 — требование приложения
- Проверяется enc=true
- Только при поддержке включаем соответствующий кодек
<?php
declare(strict_types=1);
$method = ZipArchive::EM_AES_256;
$available = ZipArchive::isEncryptionMethodSupported($method, true);
echo $available ? "Можно создать выбранный формат\n" : "Отказать: нужного кодека нет\n";
Ожидаемый результат
Можно создать выбранный формат
Ожидаемый вывод относится к проверенной сборке главы, где AES-256/DEFLATE поддерживаются. На другой сборке честная ветка отказа запрещает молча выдать документ без требуемой защиты/формата.
<?php
declare(strict_types=1);
$method = ZipArchive::EM_AES_256;
$canWrite = ZipArchive::isEncryptionMethodSupported($method, true);
$canRead = ZipArchive::isEncryptionMethodSupported($method, false);
if ($canWrite && $canRead) {
echo "Сервер может принять и выдать этот формат\n";
} else {
echo "Нужна другая сборка или согласованный формат\n";
}
Ожидаемый результат
Сервер может принять и выдать этот формат
Способность прочитать формат не обязана означать способность создать его; обе проверки влияют на допуск сервера к обмену. Вывод указан для проверенной сборки, возможности клиента проверяются отдельно.
Наличие CM_* / EM_* в классе не доказывает реализацию алгоритма. Поддержка здесь относится к серверной сборке, а не к архиватору получателя. Согласуйте формат с получателем и откажите явно, если обязательное шифрование недоступно.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setEncryptionName.
ZipArchive::setCompressionIndexВыбрать степень сжатия текстового отчёта либо оставить уже сжатые данные без повторной работы.
PHP 7.0 / PECL 1.13+ · zip
setCompressionIndex(int $index, int $method, int $compflags = 0): boolВыбрать степень сжатия текстового отчёта либо оставить уже сжатые данные без повторной работы.
Синтаксис: setCompressionIndex(int $index, int $method, int $compflags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс/имя уже добавленной записи. |
| method | CM_STORE — без сжатия; CM_DEFLATE — deflate; CM_DEFAULT — выбор библиотеки. Прочие методы зависят от libzip. |
| compflags | Параметры зависят от метода. Для DEFLATE: 1..9 — уровень, 0 — стандартный уровень, НЕ «без сжатия». Для STORE уровень не нужен; CM_DEFAULT игнорирует flags. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неподдерживаемом методе, неверной записи/комбинации, read-only архиве. Пустое имя — ValueError.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt содержит paid:42
- CM_STORE выбирает хранение без сжатия
- close применяет выбор
- stat показывает comp_method=CM_STORE
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!$zip->setCompressionIndex(0, ZipArchive::CM_STORE)) throw new RuntimeException("Нет STORE");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->statIndex(0)["comp_method"] === ZipArchive::CM_STORE ? "Без сжатия\n" : "Другой метод\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Без сжатия
Не печатаем размеры сжатых байтов как константу: они зависят от кодека и его версии.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isCompressionMethodSupported(ZipArchive::CM_DEFLATE, true)) throw new RuntimeException("Нужен DEFLATE");
if (!$zip->setCompressionIndex(0, ZipArchive::CM_DEFLATE, 6)) throw new RuntimeException("Не настроено");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Проверяем восстановление содержимого, а не обещаем, что крошечная строка станет меньше: служебные данные могут перевесить выигрыш.
Для BZIP2/XZ уровни 1..9, 0 — по умолчанию; ZSTD имеет собственный диапазон. Современные libzip могут поддерживать больше методов, чем перечисляет краткая страница PHP. Не выбирайте уровень по абстрактному обещанию скорости: измерьте ваш корпус и учитывайте совместимость получателя.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::isCompressionMethodSupported, ZipArchive::statIndex.
ZipArchive::setEncryptionIndexЗащитить содержимое выбранного документа паролем перед отправкой.
PHP 7.2 / PECL 1.14+, libzip 1.2+; nullable password PHP 8.0+ · zip
setEncryptionIndex(int $index, int $method, ?string $password = null): boolЗащитить содержимое выбранного документа паролем перед отправкой.
Синтаксис: setEncryptionIndex(int $index, int $method, ?string $password = null): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| index | Индекс/имя записи, которую требуется шифровать. |
| method | EM_AES_128, EM_AES_192, EM_AES_256; EM_NONE — убрать шифрование. Доступность проверяется отдельно. EM_TRAD_PKWARE — устаревший слабый вариант совместимости. |
| password | Явный пароль записи либо null: взять default password от setPassword(). SensitiveParameter скрывает аргумент в некоторых трассировках, но не защищает логи/память/исходный код. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неподдерживаемом алгоритме/записи/настройке; ошибка может проявиться при close(). Некорректный пароль чтения проверяется при чтении данных, а не обязательно open().
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt содержит paid:42
- AES-256 + учебный пароль назначены записи
- close сохраняет шифрованные байты
- Открываем снова, задаём пароль и читаем
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isEncryptionMethodSupported(ZipArchive::EM_AES_256, true)) throw new RuntimeException("Нужен AES-256");
if (!$zip->setEncryptionIndex(0, ZipArchive::EM_AES_256, "lesson-only-password")) throw new RuntimeException("Не зашифровано");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setPassword("lesson-only-password");
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Это явно учебный пароль. В рабочем сервисе секрет поступает из защищённого источника и не попадает в репозиторий/журнал. Требуется AES-поддержка сборки.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isEncryptionMethodSupported(ZipArchive::EM_AES_256, true)) throw new RuntimeException("Нужен AES-256");
$zip->setPassword("lesson-only-password");
if (!$zip->setEncryptionIndex(0, ZipArchive::EM_AES_256)) throw new RuntimeException("Не настроено");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setPassword("lesson-only-password");
echo $zip->statIndex(0)["encryption_method"] === ZipArchive::EM_AES_256 ? "AES-256\n" : "Нет\n";
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
AES-256
paid:42
setPassword задаёт default, а setEncryption* выбирает шифрование конкретной записи. Пропуск второго шага оставит её открытой.
ZIP обычно раскрывает имена и комментарии: шифрование содержимого не означает сокрытия всей структуры. Не понижайте незаметно AES до слабого алгоритма. Надёжность зависит и от пароля/канала его передачи, и от поддержки получателя; шифрование архива не заменяет контроль доступа сервиса.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setPassword, ZipArchive::isEncryptionMethodSupported.
ZipArchive::setCompressionNameВыбрать степень сжатия текстового отчёта либо оставить уже сжатые данные без повторной работы.
PHP 7.0 / PECL 1.13+ · zip
setCompressionName(string $name, int $method, int $compflags = 0): boolВыбрать степень сжатия текстового отчёта либо оставить уже сжатые данные без повторной работы.
Синтаксис: setCompressionName(string $name, int $method, int $compflags = 0): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Индекс/имя уже добавленной записи. |
| method | CM_STORE — без сжатия; CM_DEFLATE — deflate; CM_DEFAULT — выбор библиотеки. Прочие методы зависят от libzip. |
| compflags | Параметры зависят от метода. Для DEFLATE: 1..9 — уровень, 0 — стандартный уровень, НЕ «без сжатия». Для STORE уровень не нужен; CM_DEFAULT игнорирует flags. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неподдерживаемом методе, неверной записи/комбинации, read-only архиве. Пустое имя — ValueError.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt содержит paid:42
- CM_STORE выбирает хранение без сжатия
- close применяет выбор
- stat показывает comp_method=CM_STORE
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!$zip->setCompressionName("order.txt", ZipArchive::CM_STORE)) throw new RuntimeException("Нет STORE");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->statIndex(0)["comp_method"] === ZipArchive::CM_STORE ? "Без сжатия\n" : "Другой метод\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Без сжатия
Не печатаем размеры сжатых байтов как константу: они зависят от кодека и его версии.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isCompressionMethodSupported(ZipArchive::CM_DEFLATE, true)) throw new RuntimeException("Нужен DEFLATE");
if (!$zip->setCompressionName("order.txt", ZipArchive::CM_DEFLATE, 6)) throw new RuntimeException("Не настроено");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Проверяем восстановление содержимого, а не обещаем, что крошечная строка станет меньше: служебные данные могут перевесить выигрыш.
Для BZIP2/XZ уровни 1..9, 0 — по умолчанию; ZSTD имеет собственный диапазон. Современные libzip могут поддерживать больше методов, чем перечисляет краткая страница PHP. Не выбирайте уровень по абстрактному обещанию скорости: измерьте ваш корпус и учитывайте совместимость получателя.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::isCompressionMethodSupported, ZipArchive::statIndex.
ZipArchive::setEncryptionNameЗащитить содержимое выбранного документа паролем перед отправкой.
PHP 7.2 / PECL 1.14+, libzip 1.2+; nullable password PHP 8.0+ · zip
setEncryptionName(string $name, int $method, ?string $password = null): boolЗащитить содержимое выбранного документа паролем перед отправкой.
Синтаксис: setEncryptionName(string $name, int $method, ?string $password = null): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| name | Индекс/имя записи, которую требуется шифровать. |
| method | EM_AES_128, EM_AES_192, EM_AES_256; EM_NONE — убрать шифрование. Доступность проверяется отдельно. EM_TRAD_PKWARE — устаревший слабый вариант совместимости. |
| password | Явный пароль записи либо null: взять default password от setPassword(). SensitiveParameter скрывает аргумент в некоторых трассировках, но не защищает логи/память/исходный код. |
Результат: true при принятой операции, false при отказе. Изменения записываются на диск только успешным close(); true отдельного изменения ещё не подтверждает сохранение.
Отказ: false при неподдерживаемом алгоритме/записи/настройке; ошибка может проявиться при close(). Некорректный пароль чтения проверяется при чтении данных, а не обязательно open().
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt содержит paid:42
- AES-256 + учебный пароль назначены записи
- close сохраняет шифрованные байты
- Открываем снова, задаём пароль и читаем
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isEncryptionMethodSupported(ZipArchive::EM_AES_256, true)) throw new RuntimeException("Нужен AES-256");
if (!$zip->setEncryptionName("order.txt", ZipArchive::EM_AES_256, "lesson-only-password")) throw new RuntimeException("Не зашифровано");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setPassword("lesson-only-password");
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Это явно учебный пароль. В рабочем сервисе секрет поступает из защищённого источника и не попадает в репозиторий/журнал. Требуется AES-поддержка сборки.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isEncryptionMethodSupported(ZipArchive::EM_AES_256, true)) throw new RuntimeException("Нужен AES-256");
$zip->setPassword("lesson-only-password");
if (!$zip->setEncryptionName("order.txt", ZipArchive::EM_AES_256)) throw new RuntimeException("Не настроено");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setPassword("lesson-only-password");
echo $zip->statIndex(0)["encryption_method"] === ZipArchive::EM_AES_256 ? "AES-256\n" : "Нет\n";
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
AES-256
paid:42
setPassword задаёт default, а setEncryption* выбирает шифрование конкретной записи. Пропуск второго шага оставит её открытой.
ZIP обычно раскрывает имена и комментарии: шифрование содержимого не означает сокрытия всей структуры. Не понижайте незаметно AES до слабого алгоритма. Надёжность зависит и от пароля/канала его передачи, и от поддержки получателя; шифрование архива не заменяет контроль доступа сервиса.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setPassword, ZipArchive::isEncryptionMethodSupported.
ZipArchive::setPasswordПередать пароль для чтения защищённых записей и default для их явного шифрования.
PHP 5.6 / PECL 1.12.4+; default для шифрования PHP 7.2 / libzip 1.2+ · zip
setPassword(string $password): boolПередать пароль для чтения защищённых записей и default для их явного шифрования.
Синтаксис: setPassword(string $password): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| password | Непустая строка; в сигнатуре PHP это SensitiveParameter. Пароль привязан к открытому архиву. |
Результат: true означает, что default password установлен; это НЕ проверка пароля по всем записям и НЕ включение шифрования.
Отказ: Пустой пароль в PHP 8.5.11 возвращает false; неоткрытый архив — ValueError. Неверный пароль может обнаружиться позже при чтении.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- order.txt ещё обычный текст
- setPassword устанавливает default
- Без setEncryption* запись остаётся EM_NONE
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
$zip->setPassword("lesson-only-password");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
echo $zip->statIndex(0)["encryption_method"] === ZipArchive::EM_NONE ? "Не зашифровано\n" : "Зашифровано\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
Не зашифровано
Это проверка распространённого ошибочного ожидания. Для защиты нужен setEncryptionName/Index.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
if (!$zip->addFromString('order.txt', 'paid:42')) {
throw new RuntimeException('Запись не добавлена');
}
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!ZipArchive::isEncryptionMethodSupported(ZipArchive::EM_AES_256, true)) throw new RuntimeException("Нужен AES");
$zip->setEncryptionName("order.txt", ZipArchive::EM_AES_256, "lesson-only-password");
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if ($zip->open($path) !== true) {
throw new RuntimeException('Архив не прочитан');
}
if (!$zip->setPassword("lesson-only-password")) throw new RuntimeException("Нет пароля");
echo $zip->getFromName("order.txt"), "\n";
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
if (is_file($path)) unlink($path);
Ожидаемый результат
paid:42
Пароль задаётся заново после повторного открытия; чтение доказывает, что он подходит к этой записи.
Не проверяйте правильность пароля только по bool setPassword(). Для разных паролей отдельных записей меняйте default перед чтением нужной записи. Не выводите пароль даже при диагностике отказа.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::setEncryptionName, ZipArchive::getFromName.
ZipArchive::registerProgressCallbackПоказать продвижение длительной сборки ZIP во время close().
PHP 8.0 / PECL 1.17+, libzip 1.3+ · zip
registerProgressCallback(float $rate, callable $callback): boolПоказать продвижение длительной сборки ZIP во время close().
Синтаксис: registerProgressCallback(float $rate, callable $callback): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| rate | Порог изменения доли прогресса между сообщениями, обычно 0.1 (10%). Используйте конечное значение от 0 до 1. |
| callback | Функция получает float $state в диапазоне 0..1; её результат игнорируется. Она вызывается библиотекой при close(), а не сразу при регистрации. |
Результат: true — callback зарегистрирован; false — отказ регистрации. Это не запуск фоновой задачи.
Отказ: Неверный callable — TypeError; архив должен быть открыт. Исключение callback не является штатным способом отмены; используйте отдельный cancel callback.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Добавлена строка отчёта
- Регистрируем функцию, сохраняющую долю
- close вызывает её
- Проверяем факт сообщения без обещания количества
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString("report.txt", str_repeat("order;42\n", 1000));
$seen = false;
$zip->registerProgressCallback(0.1, function (float $state) use (&$seen): void {
if ($state >= 0.0 && $state <= 1.0) $seen = true;
});
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
echo $seen ? "Прогресс получен\n" : "Нет сообщений\n";
unlink($path);
Ожидаемый результат
Прогресс получен
use (&$seen) даёт callback доступ к внешнему флагу по ссылке. Доля относится к работе libzip при закрытии, а не ко всему HTTP-запросу.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString("report.txt", str_repeat("line\n", 1000));
$last = 0.0;
$zip->registerProgressCallback(0.25, function (float $state) use (&$last): void { $last = $state; });
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
echo $last >= 0.0 && $last <= 1.0 ? "Доля в диапазоне\n" : "Ошибка\n";
unlink($path);
Ожидаемый результат
Доля в диапазоне
Не привязываемся к точному числу вызовов, времени или шагу. Для интерфейса задача обычно пишет прогресс в отдельное состояние, а не печатает в ZIP-ответ.
Callback выполняется синхронно; тяжёлая работа внутри замедлит архивирование. Не вызывайте рекурсивно close()/open()/изменение того же архива из callback. Уже открытый объект не делает код параллельным.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::registerCancelCallback, ZipArchive::close.
ZipArchive::registerCancelCallbackДать пользователю возможность отменить затратное сохранение архива.
PHP 8.0 / PECL 1.17+, libzip 1.6+ · zip
registerCancelCallback(callable $callback): boolДать пользователю возможность отменить затратное сохранение архива.
Синтаксис: registerCancelCallback(callable $callback): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| callback | Функция без параметров возвращает int: 0 продолжать, любое ненулевое значение отменить. Выбирайте явные 0/1. |
Результат: true — регистрация успешна. При отмене последующий close() даёт warning/false и status=ER_CANCELLED.
Отказ: Неверный callable — TypeError; неправильный возвращаемый тип может вызвать TypeError. Не выбрасывайте исключение как протокол отмены; PHP 8.5.11 рассматривает исключение callback как отказ.
Перед этим вызовом open() должен успешно вернуть именно true. В PHP 8.5.11 метод без действующего открытого архива бросает ValueError. После close() для следующего чтения нужен новый open().
- Создаётся отчёт
- Callback возвращает 0
- close сохраняет ZIP
- Вторая ситуация: callback возвращает 1 → отмена
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString("report.txt", "order;42");
$zip->registerCancelCallback(static fn(): int => 0);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
echo "Сохранено\n";
unlink($path);
Ожидаемый результат
Сохранено
Короткая стрелочная функция возвращает одно значение; static показывает, что ей не нужен $this.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString("report.txt", str_repeat("order;42\n", 1000));
$zip->registerCancelCallback(static fn(): int => 1);
$warning = false;
set_error_handler(function (int $level) use (&$warning): bool {
if ($level !== E_WARNING) return false;
$warning = true; return true;
});
try { $saved = $zip->close(); } finally { restore_error_handler(); }
echo !$saved && $warning && $zip->status === ZipArchive::ER_CANCELLED ? "Отменено\n" : "Другой результат\n";
if (is_file($path)) unlink($path);
Ожидаемый результат
Отменено
Перехват warning ограничен одним ожидаемым close(), затем восстановлен. Архив после этой попытки закрыт; повторный close() не нужен.
Проверки отмены происходят в точках работы libzip, это не принудительное завершение по точному таймеру. Для уже существующего ZIP неудачный commit должен оставить исходную версию; внешние побочные действия callback этим не откатываются.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::registerProgressCallback, ZipArchive::getStatusString.
zip_openРаспознать старый код, открывающий поставку ресурсом вместо объекта. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_open(string $filename): resource|int|falseРаспознать старый код, открывающий поставку ресурсом вместо объекта. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_open(string $filename): resource|int|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| filename | Путь существующего ZIP. Нет параметра flags и нет создания нового архива. |
Результат: Ресурс каталога ZIP; код ошибки int или false при отказе. Проверяйте is_resource(), а не truthiness.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- lesson.zip создан современным API
- zip_open(path) → ресурс архива
- is_resource подтверждает успех
- zip_close освобождает ресурс
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
echo is_resource($archive) ? "Ресурс ZIP\n" : "Нет\n";
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Ресурс ZIP
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$missing = zip_open(__DIR__ . "/missing.zip");
echo is_int($missing) ? "Код отказа\n" : "Иной результат\n";
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Код отказа
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::open.
zip_closeОсвободить ресурс архива после чтения старым API. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_close(resource $zip): voidОсвободить ресурс архива после чтения старым API. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_close(resource $zip): void. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip | Живой ресурс, ранее возвращённый zip_open(). Не ZipArchive и не ресурс отдельной записи. |
Результат: Ничего не возвращает; закрывает ресурс архива.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- lesson.zip открыт через zip_open
- zip_close(archive) освобождает его
- is_resource возвращает false
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
zip_close($archive);
echo is_resource($archive) ? "Открыт\n" : "Закрыт\n";
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Закрыт
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_name($entry), "\n";
zip_entry_close($entry);
zip_close($archive);echo "Оба ресурса освобождены\n";
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
order.txt
Оба ресурса освобождены
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::close.
zip_readПоследовательно получить записи в старом импортере. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_read(resource $zip): resource|falseПоследовательно получить записи в старом импортере. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_read(resource $zip): resource|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip | Живой ресурс архива; каждый успешный вызов двигает внутренний указатель к следующей записи. |
Результат: Ресурс следующей записи либо false на конце/при отказе. Хотя текст страницы PHP упоминает код ошибки, сигнатура и PHP 8.5.11 возвращают здесь resource|false, не int.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_read работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_name($entry), "\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
order.txt
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$names = [];
while (($entry = zip_read($archive)) !== false) {
$names[] = zip_entry_name($entry);
zip_entry_close($entry);
}
echo implode(",", $names), "\n";
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
order.txt
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getNameIndex.
zip_entry_openПравильно понять старую проверку открытия записи: её результат — bool. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_open(resource $zip_dp, resource $zip_entry, string $mode = "rb"): boolПравильно понять старую проверку открытия записи: её результат — bool. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_open(resource $zip_dp, resource $zip_entry, string $mode = "rb"): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_dp | Ресурс архива. |
| zip_entry | Ресурс, полученный zip_read(), который продолжат передавать в zip_entry_read(). |
| mode | Исторический аргумент; игнорируется, поддерживается чтение rb. Он не даёт запись в ZIP. |
Результат: true/false; не возвращает новый поток или ресурс.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_open работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
$opened = zip_entry_open($archive, $entry);
echo $opened ? "Готово к чтению\n" : "Отказ\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Готово к чтению
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
if (!zip_entry_open($archive, $entry, "rb")) throw new RuntimeException("Не открыт");
echo zip_entry_read($entry, 4), "\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
paid
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getStream.
zip_entry_closeОсвободить отдельную запись, сохранив возможность обхода архива. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_close(resource $zip_entry): boolОсвободить отдельную запись, сохранив возможность обхода архива. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_close(resource $zip_entry): bool. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_entry | Живой ресурс записи от zip_read(). |
Результат: true при закрытии. После закрытия этот ресурс нельзя читать повторно.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_close работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
var_export(zip_entry_close($entry)); echo "\n";
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
true
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$closed = 0;
while (($entry = zip_read($archive)) !== false) {
if (zip_entry_close($entry)) $closed++;
}
echo $closed, " освобождённая запись\n";
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
1 освобождённая запись
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getStream.
zip_entry_readПрочитать байты документа порциями в унаследованном обработчике. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_read(resource $zip_entry, int $len = 1024): string|falseПрочитать байты документа порциями в унаследованном обработчике. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_read(resource $zip_entry, int $len = 1024): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_entry | Ресурс записи, не bool от zip_entry_open(). |
| len | Запрошенное число распакованных байтов; по умолчанию 1024. PHP 8.5.11 также заменяет неположительное значение на 1024. |
Результат: Строка прочитанных байтов; "" на конце. В PHP 8.5.11 внутренний отрицательный результат чтения также превращается в "", поэтому этот API плохо различает EOF и повреждение; новый код использует ZipArchive.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_read работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_read($entry, 4), "\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
paid
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
$body = "";
while (($chunk = zip_entry_read($entry, 3)) !== "" && $chunk !== false) {
$body .= $chunk;
if (strlen($body) > 1024) throw new RuntimeException("Лимит");
}
echo $body, "\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
paid:42
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getStream.
zip_entry_nameПолучить имя найденного документа без чтения его содержимого. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_name(resource $zip_entry): string|falseПолучить имя найденного документа без чтения его содержимого. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_name(resource $zip_entry): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_entry | Ресурс записи от zip_read(); родительский архив ещё открыт. |
Результат: Имя записи в ZIP или false при недоступном состоянии.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_name работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_name($entry), "\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
order.txt
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
$name = zip_entry_name($entry);
echo $name === "order.txt" ? "Ожидаемый документ\n" : "Не импортировать\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Ожидаемый документ
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::getNameIndex.
zip_entry_filesizeОценить распакованный размер перед старым импортом. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_filesize(resource $zip_entry): int|falseОценить распакованный размер перед старым импортом. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_filesize(resource $zip_entry): int|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_entry | Ресурс записи от zip_read(). |
Результат: Размер распакованных данных в байтах либо false. 0 — корректный размер пустой записи.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_filesize работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_filesize($entry), " байтов\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
7 байтов
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
$size = zip_entry_filesize($entry);
echo $size !== false && $size <= 1024 ? "Предварительный лимит соблюдён\n" : "Отказ\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Предварительный лимит соблюдён
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex.
zip_entry_compressedsizeОтличить место внутри ZIP от объёма будущей распаковки. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_compressedsize(resource $zip_entry): int|falseОтличить место внутри ZIP от объёма будущей распаковки. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_compressedsize(resource $zip_entry): int|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_entry | Ресурс записи от zip_read(). |
Результат: Число сжатых байтов либо false. Это не размер всего ZIP с заголовками.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_compressedsize работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_compressedsize($entry), " байтов STORE\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
7 байтов STORE
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
$packed = zip_entry_compressedsize($entry);
$plain = zip_entry_filesize($entry);
echo $packed === $plain ? "Для STORE размеры совпали\n" : "Размеры различаются\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Для STORE размеры совпали
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex.
zip_entry_compressionmethodПрочитать историческое текстовое имя способа сжатия. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
PHP 4.1+, PHP 5.2+, PECL zip 1.0+; deprecated PHP 8.0+ · zip
zip_entry_compressionmethod(resource $zip_entry): string|falseПрочитать историческое текстовое имя способа сжатия. Функция deprecated с PHP 8.0; изучаем для миграции, новый код пишем на ZipArchive.
Синтаксис: zip_entry_compressionmethod(resource $zip_entry): string|false. Параметры перечислены в порядке передачи. Значение после = — значение по умолчанию; знак | между типами означает варианты результата, а между флагами в вызове — объединение битовых признаков.
| Аргумент | Договор |
|---|---|
| zip_entry | Ресурс записи от zip_read(). |
Результат: Историческая строка (stored, shrunk, reduced, imploded, tokenized, deflated, deflatedX, implodedX) или false для неизвестного метода/состояния. Это не CM_*.
Отказ: PHP 8+ сообщает E_DEPRECATED при каждом вызове. Неверный PHP-тип/закрытый или чужой ресурс — TypeError; отказ конкретной операции проверяйте по описанному результату. Для zip_open пустое имя — ValueError.
- В lesson.zip лежит order.txt с paid:42
- zip_open → ресурс архива
- zip_read → ресурс order.txt
- zip_entry_compressionmethod работает с этой записью
- Сначала закрывается запись, затем архив
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
echo zip_entry_compressionmethod($entry), "\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
stored
Подготовка создаёт собственный архив. Обработчик перехватывает только E_DEPRECATED и только внутри учебного старого API; остальные ошибки не скрываются.
<?php
declare(strict_types=1);
$path = __DIR__ . '/lesson.zip';
$zip = new ZipArchive();
if ($zip->open($path, ZipArchive::CREATE | ZipArchive::EXCL) !== true) {
throw new RuntimeException('Не удалось создать учебный архив');
}
$zip->addFromString('order.txt', 'paid:42');
$zip->setCompressionName('order.txt', ZipArchive::CM_STORE);
if (!$zip->close()) {
throw new RuntimeException('Архив не сохранён');
}
$deprecated = false;
set_error_handler(function (int $level) use (&$deprecated): bool {
if ($level !== E_DEPRECATED) return false;
$deprecated = true;
return true;
});
try {
$archive = zip_open($path);
if (!is_resource($archive)) throw new RuntimeException('Не открыт ZIP');
$entry = zip_read($archive);
if ($entry === false) throw new RuntimeException('Нет записи');
$method = zip_entry_compressionmethod($entry);
echo $method === "stored" ? "Байты не сжимались\n" : "Другой или неизвестный метод\n";
zip_entry_close($entry);
zip_close($archive);
} finally {
restore_error_handler();
}
unlink($path);
Ожидаемый результат
Байты не сжимались
Старые ресурсы не смешиваются с ZipArchive и обычными потоками. После этого разбора переходите к связанной современной карточке.
Оба примера сохраняют старый договор для понимания существующего приложения; не подавляйте deprecated глобальным @. При миграции меняется не только имя функции: архив становится объектом, запись выбирается именем/индексом, а поток получается getStream(). Закрывайте запись раньше архива. Метаданные и имена недоверенного ZIP всё равно требуют проверки.
Разбор общей подготовки и уборки: первый архив.
Продолжение: ZipArchive::statIndex.
Источники и обсуждения
Код и руководство с собой
Скачайте самостоятельные примеры с исходными данными, инструкциями и ожидаемыми результатами. Примеры HTTP и фрагменты для проекта помечены отдельно: им нужно указанное окружение.
Код не исполняется на сайте. Скачайте нужный пример и запускайте его в своём локальном окружении.
Материалы сверены 2026-10-12. Примеры и объяснения написаны для этого руководства; источники и обсуждения доступны в каждой главе.


