ZIP архивы в PHP: от новичка до профи

Раздел: Работа с файлами

Основные методы работы с ZIP архивами в PHP

Наиболее эффективный способ: класс ZipArchive

Класс ZipArchive является встроенным в PHP (требуется расширение ext-zip) и предоставляет полный набор функций для создания, чтения и изменения ZIP-архивов. Он поддерживает шифрование, комментарии, потоки и работу с большими файлами.


// Создание нового архива и добавление файла
$zip = new ZipArchive();
$zipName = 'example.zip';
if ($zip->open($zipName, ZipArchive::CREATE) === true) {
    $zip->addFile('path/to/file.txt', 'file.txt');
    $zip->close();
    echo 'Архив создан';
} else {
    echo 'Ошибка создания архива';
}
  

обработка php (обработка данных в php)

Пояснения: метод open() с флагом ZipArchive::CREATE создаёт новый архив. addFile() добавляет существующий файл, первый аргумент – путь к файлу на диске, второй – имя внутри архива (можно с подкаталогами). close() сохраняет изменения.

Типичная проблема: архив не создаётся или файлы не добавляются

  • Не установлено расширение Zip. Проверить через phpinfo() или наличие класса ZipArchive.
  • Недостаточно прав на запись в директорию, где создаётся архив.
  • Имя архива занято другим процессом (удалите или переименуйте).

Как добавить все файлы из папки рекурсивно?

Для добавления целой директории с сохранением структуры удобно написать вспомогательную функцию:


function addFolderToZip($dir, $zip, $zipDir = '') {
    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
    );
    foreach ($files as $file) {
        $filePath = $file->getRealPath();
        $relativePath = $zipDir . $file->getSubPathname();
        $zip->addFile($filePath, $relativePath);
    }
}

$zip = new ZipArchive();
$zip->open('folder.zip', ZipArchive::CREATE);
addFolderToZip('/path/to/folder', $zip);
$zip->close();
  

Php learning (обучение php)

Проблемы: рекурсия может привести к превышению лимита памяти при очень большом количестве файлов. Решение – ограничить глубину или использовать потоковое добавление.

Как извлечь архив с проверкой структуры?

Базовая операция извлечения:


$zip = new ZipArchive();
if ($zip->open('archive.zip') === true) {
    $zip->extractTo('/destination/folder');
    $zip->close();
} else {
    echo 'Не удалось открыть архив';
}
  

Php учебник (учебник по php)

Распространённые ошибки при извлечении:

  • Целевая папка не существует – создайте её заранее или используйте mkdir() с рекурсией.
  • Пути внутри архива содержат символы, недопустимые для файловой системы (например, двоеточие в Windows). Используйте $zip->getFromName() для чтения в память и сохранения с новым именем.
  • Переполнение дискового пространства – проверяйте свободное место до извлечения.

Как создать архив с паролем?

ZipArchive поддерживает шифрование (требуется PHP 7.2+ и libzip 1.2+):


$zip = new ZipArchive();
$zip->open('protected.zip', ZipArchive::CREATE);
$zip->setPassword('secret123');
$zip->addFile('data.txt', 'data.txt');
// Устанавливаем метод шифрования для конкретного файла
$zip->setEncryptionName('data.txt', ZipArchive::EM_AES_256);
$zip->close();
  

Apis php (api на php)

Для извлечения пароль указывается перед вызовом extractTo():


$zip->setPassword('secret123');
$zip->extractTo('./extracted');
  

Php categoryid (категории в php)

Проблема: шифрование не работает

Проверьте версию libzip (`php -i | grep libzip`). Для AES-256 требуется libzip >= 1.2. При отсутствии поддержки архив будет создан, но файлы не будут зашифрованы – ошибка не выбрасывается.

Как добавить файл из строки (без сохранения на диск)?

Метод addFromString():


$zip = new ZipArchive();
$zip->open('inline.zip', ZipArchive::CREATE);
$zip->addFromString('hello.txt', 'Содержимое файла');
$zip->close();
  

Html javascript php (интеграция html, javascript и php)


Какие есть альтернативные решения?

Класс PharData позволяет работать с ZIP как с Phar-архивом:


$phar = new PharData('archive.zip');
$phar->addFile('file.txt');
$phar->extractTo('./out');
  

Однако PharData менее гибкий (нет шифрования, сложнее работа с комментариями). Другой вариант – вызов внешней утилиты zip через exec(), но это снижает переносимость и безопасность.

Когда использовать сторонние библиотеки?

Для работы с архивами в потоковом режиме (например, генерация большого архива без хранения в памяти) подойдёт ZipStream-PHP. Для совместимости со старыми версиями PHP – PclZip. Но встроенный ZipArchive покрывает 90% задач.

- Php javascript css (javascript и css в php)
- Php m3u (создание m3u плейлиста на php)
- Php pid (идентификатор процесса (pid) в php)

Подробные расширенные примеры

Пример 1: Создание архива с рекурсивным обходом и проверкой ошибок

Пример

function addDirToZipRecursive($dir, $zip, $relativeDir = '') {
    $handle = opendir($dir);
    if (!$handle) {
        throw new RuntimeException("Не удалось открыть директорию: $dir");
    }
    while (($entry = readdir($handle)) !== false) {
        if ($entry == '.' || $entry == '..') continue;
        $fullPath = $dir . DIRECTORY_SEPARATOR . $entry;
        $archPath = $relativeDir ? $relativeDir . '/' . $entry : $entry;
        if (is_dir($fullPath)) {
            addDirToZipRecursive($fullPath, $zip, $archPath);
        } else {
            if (!$zip->addFile($fullPath, $archPath)) {
                throw new RuntimeException("Не удалось добавить файл: $fullPath");
            }
        }
    }
    closedir($handle);
}

try {
    $zip = new ZipArchive();
    $zipName = 'backup_' . date('Ymd_His') . '.zip';
    if ($zip->open($zipName, ZipArchive::CREATE) !== true) {
        throw new RuntimeException("Не удалось создать архив: $zipName");
    }
    addDirToZipRecursive('/path/to/source', $zip);
    $zip->close();
    echo "Архив создан: $zipName";
} catch (Exception $e) {
    echo 'Ошибка: ' . $e->getMessage();
}
Архив создан: backup_20250331_120000.zip

В этом примере используется рекурсивная функция с проверкой каждого шага. Ошибки выбрасываются как исключения для централизованной обработки.

Пример 2: Извлечение только файлов определённого расширения

Пример

$zip = new ZipArchive();
$zip->open('images.zip');
$extractDir = './images';
if (!is_dir($extractDir)) mkdir($extractDir, 0755, true);

for ($i = 0; $i < $zip->numFiles; $i++) {
    $name = $zip->getNameIndex($i);
    if (preg_match('/\.(jpg|jpeg|png|gif)$/i', $name)) {
        $zip->extractTo($extractDir, $name);
    }
}
$zip->close();
echo 'Извлечено ' . $i . ' изображений';
Извлечено 5 изображений

Важно: extractTo() со вторым параметром принимает как строку, так и массив имён файлов.

Пример 3: Использование progress callback для отслеживания процесса (PHP 8.0+)

Пример

$zip = new ZipArchive();
$zip->open('large.zip');
$totalSize = $zip->getArchiveSize(); // размер в байтах
$extractedSize = 0;

$zip->setExtractCallback(function ($code, $info) use (&$extractedSize, $totalSize) {
    if ($code === ZipArchive::ER_EXTRACT) {
        $extractedSize += $info['uncompressed_size'] ?? 0;
        $percent = $totalSize > 0 ? round($extractedSize / $totalSize * 100, 2) : 0;
        echo "\rИзвлечено $percent%";
    }
    return true;
});

$zip->extractTo('./destination');
$zip->close();

Callback функция вызывается для каждого извлечённого файла. $info содержит данные о файле.

Пример 4: Создание архива и отправка его браузеру без сохранения на диск

Пример

$zip = new ZipArchive();
$tmpFile = tempnam(sys_get_temp_dir(), 'zip');
if ($zip->open($tmpFile, ZipArchive::OVERWRITE) !== true) {
    throw new Exception('Не удалось создать временный архив');
}

$zip->addFromString('readme.txt', 'Hello, world!');
$zip->addFile('image.png', 'photos/image.png');
$zip->close();

header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="download.zip"');
header('Content-Length: ' . filesize($tmpFile));
readfile($tmpFile);
unlink($tmpFile);
exit;

Этот подход позволяет отдавать архив без сохранения его в публичной директории. Временный файл удаляется после отправки.

Пример 5: Проверка целостности архива и получение списка файлов с размерами

Пример

$zip = new ZipArchive();
if ($zip->open('test.zip') === true) {
    echo 'Архив открыт, количество файлов: ' . $zip->numFiles . "\n";
    for ($i = 0; $i < $zip->numFiles; $i++) {
        $stat = $zip->statIndex($i);
        printf("%s - %d байт (crc32: %s)\n", $stat['name'], $stat['size'], dechex($stat['crc']));
    }
    // Проверка целостности (по CRC)
    if ($zip->isValid()) {
        echo "Архив корректен (CRC совпадает)\n";
    } else {
        echo "Обнаружены ошибки CRC\n";
    }
    $zip->close();
}
Архив открыт, количество файлов: 2
file1.txt - 1024 байт (crc32: a1b2c3d4)
file2.txt - 2048 байт (crc32: e5f6a7b8)
Архив корректен (CRC совпадает)

Метод statIndex() возвращает метаданные, включая CRC32. isValid() проверяет контрольные суммы всех файлов (требует полного чтения архива).

Пример 6: Работа с комментариями архива и отдельных файлов

Пример

$zip = new ZipArchive();
$zip->open('comment.zip', ZipArchive::CREATE);
$zip->addFromString('a.txt', 'data');
// Комментарий к архиву
$zip->setArchiveComment('Архив создан 31.03.2025');
// Комментарий к конкретному файлу
$zip->setCommentName('a.txt', 'Этот файл содержит важные данные');
$zip->close();

// Чтение комментариев
$zip->open('comment.zip');
echo 'Комментарий архива: ' . $zip->getArchiveComment() . "\n";
echo 'Комментарий a.txt: ' . $zip->getCommentName('a.txt') . "\n";
$zip->close();
Комментарий архива: Архив создан 31.03.2025
Комментарий a.txt: Этот файл содержит важные данные

Комментарии полезны для метаданных, но не шифруются и могут быть утеряны при модификации архива сторонними программами.

Пример 7: Обработка ошибок при добавлении больших файлов с использованием потока

Пример

$zip = new ZipArchive();
$zip->open('large.zip', ZipArchive::CREATE);

// Добавление файла из потока (не загружая весь файл в память)
$stream = fopen('/path/to/bigfile.iso', 'rb');
if ($stream) {
    $zip->addFileFromStream($stream, 'bigfile.iso');
    fclose($stream);
} else {
    echo 'Не удалось открыть файл для чтения';
}

// Или добавить из строки с использованием временного файла
file_put_contents('tmp_iso', file_get_contents('http://example.com/file'), LOCK_EX);
$zip->addFile('tmp_iso', 'remote.iso');
$zip->close();
unlink('tmp_iso');

Метод addFileFromStream() доступен с PHP 8.0. Для старых версий приходится сначала загружать файл на диск.

ZIP архивы в PHP - comments

En
Php zip (php)