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% задач.
Подробные расширенные примеры
Пример 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. Для старых версий приходится сначала загружать файл на диск.