Работа с архивами в PHP: от простых до сложных решений
Основные подходы к архивации в PHP
Архивация файлов - частая задача при разработке бэкапов, выгрузок данных и автоматизации. В PHP есть несколько способов создания и чтения архивов. Рассмотрим самые распространённые и эффективные решения.
Использование класса ZipArchive (наилучший вариант)
Класс ZipArchive встроен в стандартную библиотеку PHP и подходит для 99% задач. Работает с ZIP-форматом, поддерживает сжатие, пароли, комментарии и многое другое.
$zip = new ZipArchive();
$filename = 'archive.zip';
if ($zip->open($filename, ZipArchive::CREATE) === true) {
$zip->addFile('file1.txt', 'file1.txt');
$zip->addFile('file2.jpg', 'images/file2.jpg');
$zip->close();
echo 'Архив создан';
} else {
echo 'Ошибка создания архива';
}
Index php archive (архив в php)
Пояснение: open с флагом CREATE создаёт новый архив. addFile добавляет файл с указанием пути внутри архива. После всех действий вызывается close.
Проблемы: отсутствие расширения zip в PHP выдаёт ошибку. Решение - установка расширения через менеджер пакетов (например, apt install php-zip на Ubuntu). Также при добавлении больших файлов может превыситься лимит памяти - используйте setCompressionIndex с методом сжатия или добавляйте файлы группами.
Как создать архив с помощью системной утилиты zip через exec?
Если расширение zip не установлено, можно вызвать внешнюю программу.
exec('zip -r backup.zip /path/to/folder', $output, $exitCode);
if ($exitCode === 0) {
echo 'Архив создан успешно';
} else {
echo 'Ошибка: ' . implode('\n', $output);
}
Пояснение: флаг -r рекурсивно добавляет папку. Важно проверять код возврата. Безопасность: экранируйте пути с escapeshellarg.
Проблема: команда может быть запрещена политикой хостинга. Решение - использовать shell_exec или proc_open с проверкой прав. Также проверьте доступ к исполняемому файлу zip (which zip).
Как создать PHAR-архив?
Класс PharData позволяет создавать архивы в форматах tar, tar.gz, tar.bz2, zip.
$phar = new PharData('archive.tar.gz');
$phar->addFile('file.txt', 'file.txt');
$phar->addFromString('config.php', '<? return [];');
$phar->compress(Phar::GZ);
Пояснение: PharData создаёт tar-архив (без сжатия). compress упаковывает его в tar.gz. Подходит для больших проектов.
Проблема: требуется расширение phar. Часто включено по умолчанию. На старых версиях PHP возможны ошибки с путями - используйте абсолютные пути.
Как создать ZIP-архив без ZipArchive (ручной метод)?
Для демонстрации низкоуровневой работы можно написать собственную функцию, сформировав ZIP-структуру.
function createZipManual($zipPath, $files) {
$zip = pack('V', 0x04034b50) . pack('v', 10) . pack('v', 0); // сигнатура
// ... длинный код (упрощён для статьи)
file_put_contents($zipPath, $zip);
}
Пояснение: такой метод не рекомендуется для продакшена из-за сложности и риска ошибок. Подходит для обучения.
Проблемы: легко ошибиться в смещениях, не обрабатываются большие файлы, медленная работа. Лучше использовать готовые библиотеки.
Углублённые примеры и редкие сценарии
Создание архива с вложенными каталогами (рекурсивный обход)
$zip = new ZipArchive();
$path = '/var/www/project';
$zip->open('backup_' . date('Ymd') . '.zip', ZipArchive::CREATE);
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
if (!$file->isDir()) {
$localPath = substr($file->getPathname(), strlen($path) + 1);
$zip->addFile($file->getPathname(), $localPath);
}
}
$zip->close();
Результат: создан ZIP-архив, содержащий все файлы из папки с сохранением структуры.
Файл: backup_20250215.zip размером 2.3 МБ
Добавление комментария к архиву и настройка сжатия
$zip = new ZipArchive();
$zip->open('archive.zip', ZipArchive::CREATE);
$zip->setArchiveComment('Бэкап от 15.02.2025');
$zip->addFile('data.log', 'logs/data.log');
for ($i = 0; $i < $zip->numFiles; $i++) {
$zip->setCompressionIndex($i, ZipArchive::CM_BZIP2);
}
$zip->close();
Пояснение: сжатие BZIP2 даёт лучший коэффициент, но работает медленнее. Комментарий можно прочитать через getArchiveComment.
Установка пароля на ZIP-архив (шифрование)
$zip = new ZipArchive();
$zip->open('protected.zip', ZipArchive::CREATE);
$zip->setPassword('secret123');
$zip->addFile('private.txt', 'private.txt');
$zip->setEncryptionName('private.txt', ZipArchive::EM_AES_256);
$zip->close();
Примечание: шифрование доступно с PHP 7.2. Без указания метода используется стандартное PKWARE шифрование.
Создание tar-архива с помощью PharData
$phar = new PharData('backup.tar');
$phar->buildFromDirectory('/var/www/data');
$phar->compress(Phar::GZ); // создаст backup.tar.gz
unlink('backup.tar'); // удалить исходный tar
Результат: единственный файл backup.tar.gz.
backup.tar.gz - 1.1 МБ
Распаковка архива с извлечением только определённых файлов
$zip = new ZipArchive();
$zip->open('backup.zip');
// Извлечь только файлы с расширением .log
for ($i = 0; $i < $zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
if (pathinfo($name, PATHINFO_EXTENSION) === 'log') {
$zip->extractTo('/extract/path', $name);
}
}
$zip->close();
Позволяет избежать извлечения ненужных больших файлов.
Создание самодостаточного PHAR-архива с кодом PHP
$phar = new Phar('app.phar');
$phar->startBuffering();
$phar->buildFromDirectory(__DIR__ . '/src');
$defaultStub = $phar->createDefaultStub('index.php');
$phar->setStub($defaultStub);
$phar->stopBuffering();
После этого файл app.phar можно запускать как php app.phar.
Обработка ошибок при работе с большими архивами
ini_set('memory_limit', '512M');
$zip = new ZipArchive();
if ($zip->open('large.zip', ZipArchive::CREATE) !== true) {
throw new RuntimeException('Не удалось создать архив');
}
// Добавление по одному файлу с проверкой
$files = ['file1.bin', 'file2.bin'];
foreach ($files as $f) {
if ($zip->addFile($f, basename($f)) === false) {
error_log('Ошибка добавления: ' . $f);
}
}
if ($zip->close() === false) {
error_log('Ошибка закрытия архива');
}
Полезно при обработке тысяч файлов - логируйте каждый сбой.