Уже долгие годы самым распространенным форматом сжатия данных, является формат ZIP. Данный формат широко используется в разработках под web. Поэтому многие языки для web-программирования имеют либо встроенные средства или возможности подключения необходимых библиотек для работы с zip-архивами.
Непосредственно в самом PHP функций для распаковки и создания zip-архивов нету. Хотя это зависит, от вариантов его сборки. Но они присутствуют в PHP расширении “php_zip”. И именно оно позволяет работать с архивными zip-файлами.
Распаковка архива
С распаковкой архивов при веб разработке, приходиться сталкиваться наиболее часто, нежели при разработке прикладного ПО. Особенно когда возникает необходимость в пакетной загрузке данных (документы, сертификаты и т.д.). Ведь даже диалоговое окно для открытия файла в браузере, не имеет возможности мульти выбора файлов. Конечно, можно воспользоваться каким-либо flash-загрузчиком, но во многих ситуациях это не подходит. А значит остается всего один вариант – архивация данных. Для работы по распаковке архива есть ряд функций встроенных в расширение php_zip:
void zip_close (resource $zip)
Закрывает архивный zip-файл. Параметр zip обязан быть zip-архивом, открытым до этого функцией zip_open().
void zip_entry_close (resource $zip_entry)
Закрывает вхождение директории, специфицированное параметром zip_entry. Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_entry_open().
int zip_entry_filesize (resource $zip_entry)
Возвращает фактический размер вхождения директории zip_entry. Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read().
string zip_entry_name (resource $zip_entry)
Возвращает имя вхождения директории zip_entry. Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read().
Открывает вхождение директории в zip-файле для чтения. Параметр zip это правильный дескриптор ресурса, возвращённый функцией zip_open(). Параметр zip_entry это ресурс вхождения директории, возвращённый функцией zip_read(). Необязательный параметр mode может быть одним из режимов, специфицированных в документации для fopen().
Примечание: в настоящее время mode игнорируется и всегда имеет значение “rb”.Это из-за тог, что zip поддерживается в PHP с доступом только для чтения. Возвращает true при успехе, false при неудаче. В отличие от fopen() и других подобных функций, возвращаемое значение функции zip_entry_open() указывает только на результат операции и не нужно для чтения или закрытия вхождения директории.
string zip_entry_read (resource $zip_entry [, int $length])
Читает до length байтов из открытого вхождения директории. Если параметр length не специфицирован, Функция zip_entry_read() пытается прочитать 1024 байта. Параметр zip_entry является правильным вхождением директории, возвращённым функцией zip_read(). Возвращает прочитанные данные, или false, если достигнут конец файла.
Примечание: параметр length должен быть несжатым размером, который вы хотите прочитать.
resource zip_open (string $filename)
Открывает новый zip-архив для чтения. Параметр filename это имя файла открываемого zip-архива. Возвращает дескриптор ресурса для дальнейшего использования в zip_read() и zip_close(), или возвращает false, если filename не существует.
resource zip_read (resource $zip)
Читает следующее вхождение в файле zip-архива. Параметр zip обязан быть zip-архивом, открытым ранее функцией zip_open(). Возвращает ресурс вхождения директории для дальнейшего использования с zip_entry_… () функциями.
int zip_entry_compressedsize(resource $zip_entry)
Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read(). Возвращает сжатый размер вхождения директории zip_entry.
Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read(). Возвращает метод сжатия для вхождения директории zip_entry.
Ниже приведен найденный и модифицированный мной исходный код функции для распаковки архива. Данная функция производит распаковку архива в корневой каталог. Поэтому если есть необходимость в создании директории для последующего расположения в ней распакованных файлов и каталогов, то ее требуется слегка изменить.
Выше был продемонстрирован классический пример распаковки архива. Обратите внимание на то, что указанный к архиву путь, должен быть абсолютным. Но тем не менее существует еще одна возможность, чтобы его распаковать. Для этого нужно прибегнуть к помощи методов класса ZipArchive. Этот класс находится все в том же расширении “php_zip”. Итак для того чтобы применить другой вариант распаковки, необходимо написать следующий код:
$zip = new ZipArchive;
if ($zip->open('archive.zip') === TRUE) {
$zip->extractTo(ROOT_DIR .'/test/');
$zip->close();
echo 'Архив распакован';
} else {
echo 'Не удалось распаковать архив';
}
Для распаковки архива у данного класса используется только один метод:
Будущая директория местонахождения распакованного архива задается в параметре $destination. Параметр $entries содержит элементы для извлечения. Он является необязательным и может принимать как одно значение, так и массив значений.
Второй вариант выглядит намного красивее и компактнее, чем первый, не так ли? Поэтому я свой выбор остановил именно на нем. И напоследок протестируем оба варианта на скорость распаковки архива объемом в 205Mb:
Первый вариант:
5.72193 cек
5.99901 cек
5.94039 cек
Второй вариант:
4.82474 cек
5.49326 cек
4.93721 cек
Создание архива
Создание архива происходит сложнее, чем его распаковка. Если конечно требуется создать архив с одним файлом или одной директорией, то здесь все просто. А вот если упаковывать директории с неограниченным уровнем вложенности каталогов, то здесь уже придется немного подумать. Во-первых, необходим хороший рекурсивный алгоритм для обхода директорий. Во-вторых, нужно дополнительно хранить локальное имя файла/каталога. Итак, для создания архива нам понадобятся четыре метода класса ZipArchive:
bool addEmptyDir (string $dirname)
Добавляет в архив пустую директорию. Параметр dirname должен содержать имя директории. Метод в случае успеха возвращает true или false в противном случае.
void addFile (string $filename [, string $localname = NULL [, int $start = 0 [, int $length = 0 ]]])
Добавляет в архив файл, который находится по указанному в параметре filename пути. Параметр localname отвечает за имя файла в архиве. И если он указан, то параметр filename будет переопределен. Параметры start и length, зарезервированы для будущих целей. Данный метод так же в случае успеха возвращает true или false в случае ошибки.
void open (string $filename [, int $flags ])
Данный метод необходим для открытия нового архива с целью: чтения, записи или создания. Параметр filename должен содержать имя архива. Необязательный параметр flags используется в качестве режима открытия файла (ZIPARCHIVE::OVERWRITE, ZIPARCHIVE::CREATE, ZIPARCHIVE::EXCL, ZIPARCHIVE::CHECKCONS). Метод возвращает true в случае успеха или код ошибки (см. предопределенные константы ошибок).
void close ()
Этот метод закрывает открытый или созданный архив и сохраняет изменения. Данный метод автоматически вызывается в конце сценария.
Ниже приведен исходный код созданного класса, позволяющего производить создание zip-архивов:
class Zip extends ZipArchive {
var $lPrefix;
function ToZip ($source, $destination){
$result = false;
// Получаем директорию исходного каталога или файла
$dir = pathinfo($destination, PATHINFO_DIRNAME);
// Создаем если необходимо директории для будущего архива
if (@!file_exists($dir)) {
if (!mkdir($dir, 0777, true))
return false;
}
// Проверяем существование директории для будущего архива
if (@file_exists($dir)) {
if ($this->open($destination, ZIPARCHIVE::CREATE)) {
/*
* Получаем длину пути исходной директории с
* прибавленным одним слешем
*/
$this->lPrefix = strlen(pathinfo($source,
PATHINFO_DIRNAME) . '/');
if (is_dir($source)) {
/*
* Если файл является директорией, то создаем
* структуру каталогов и файлов в будущем архиве
*/
$this->PackingDirectory($source);
$result = true;
} else if (is_file($source) && @file_exists($source)) {
/*
* Если файл является не директорией и существует, то
* добавляем его сразу в архив
*/
$this->addFile($source, pathinfo($source,
PATHINFO_BASENAME));
$result = true;
}
$this->close();
}
}
return $result;
}
function PackingDirectory ($source){
// Получаем дескриптор обходимого каталога
$handle = @opendir($source);
/*
* Совершаем рекурсивный обход всех вложенных
* директорий
*/
while (false !== $node = readdir($handle)) {
if ($node != '.' && $node != '..') {
// Полный путь файла, плюс имя узла
$fPath = "$source/$node";
/*
* Локальный путь файла
* (от исходного каталога)
*/
$lPath = substr($fPath, $this->lPrefix);
if (is_dir($fPath)){
/*
* Если файл является каталогом, то
* добавляем в архив категорию
*/
$this->addEmptyDir($lPath);
$this->PackingDirectory($fPath);
} else {
// Иначе добавляем файл
$this->addFile($fPath, $lPath);
}
}
}
// Закрываем дескриптор обходимого каталога
closedir($handle);
}
}
Данный класс позволяет создавать архив из каталогов с неограниченным уровнем вложенности. Для создания архива, необходимо вызвать только один метод ToZip.
bool ToZip (string $source, string $destination)
Создает zip-архив. В параметре source требуется указать путь к каталогу или файлу, который требуется запаковать. А в качестве параметра destination передается имя будущего архива. Метод возвращает true в случае успеха или false в случае возникновения ошибки.
Примеры использования:
$zip = new Zip ();
/*
* Добавление в архив директории: /текущая директория/1/
* имя архива: test.zip
* Результат: создастся архив в текущей директории с именем test.zip
*/
$zip->ToZip(ROOT_DIR . '/1', ROOT_DIR . /'test.zip');
/*
* Добавление в архив директории: /текущая директория/1/
* имя архива: /текущая директория/new_arcive/test.zip
* Результат: создастся архив в директории -
* /текущая директория/new_arcive/ с именем test.zip
* если директория new_archive не существует, то она будет создана
*/
$zip->ToZip(ROOT_DIR . '/1', ROOT_DIR .'/new_archive/test.zip');
/*
* Добавление в архив файла с именем: /текущая директория/test.txt
* имя архива: /текущая директория/file.zip
* Результат: создастся архив file.zip в текущей директории
*/
$zip->ToZip(ROOT_DIR . '/test.txt', ROOT_DIR . '/file.zip');
Предопределенные константы режима работы
ZIPARCHIVE::CREATE (integer)
Создавать архив, если он не существует.
ZIPARCHIVE::OVERWRITE (integer)
Всегда создавать новый архив, этот режим перезаписывает файлы, если они существуют.
ZIPARCHIVE::EXCL (integer)
Выводить ошибку, если архив существует.
ZIPARCHIVE::CHECKCONS (integer)
Выполнять дополнительные проверки на структуру архива, и выдавать ошибку при неудаче.
Предопределенные константы флагов
ZIPARCHIVE::FL_NOCASE (integer)
Игнорировать регистр символов в именах элементов архива.
ZIPARCHIVE::FL_NODIR (integer)
Не учитывать пути директорий в архиве.
ZIPARCHIVE::FL_COMPRESSED (integer)
Читать сжатые данные.
ZIPARCHIVE::FL_UNCHANGED (integer)
Использовать исходные данные, игнорируя изменения.
Предопределенные константы методов сжатия
ZIPARCHIVE::CM_DEFAULT (integer)
Выбрать лучший метод сжатия deflate или stored (без сжатия).
Работа с zip-архивами в PHP
Уже долгие годы самым распространенным форматом сжатия данных, является формат ZIP. Данный формат широко используется в разработках под web. Поэтому многие языки для web-программирования имеют либо встроенные средства или возможности подключения необходимых библиотек для работы с zip-архивами.
Непосредственно в самом PHP функций для распаковки и создания zip-архивов нету. Хотя это зависит, от вариантов его сборки. Но они присутствуют в PHP расширении “php_zip”. И именно оно позволяет работать с архивными zip-файлами.
Распаковка архива
С распаковкой архивов при веб разработке, приходиться сталкиваться наиболее часто, нежели при разработке прикладного ПО. Особенно когда возникает необходимость в пакетной загрузке данных (документы, сертификаты и т.д.). Ведь даже диалоговое окно для открытия файла в браузере, не имеет возможности мульти выбора файлов. Конечно, можно воспользоваться каким-либо flash-загрузчиком, но во многих ситуациях это не подходит. А значит остается всего один вариант – архивация данных. Для работы по распаковке архива есть ряд функций встроенных в расширение php_zip:
Закрывает архивный zip-файл. Параметр zip обязан быть zip-архивом, открытым до этого функцией zip_open().
Закрывает вхождение директории, специфицированное параметром zip_entry. Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_entry_open().
Возвращает фактический размер вхождения директории zip_entry. Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read().
Возвращает имя вхождения директории zip_entry. Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read().
Открывает вхождение директории в zip-файле для чтения. Параметр zip это правильный дескриптор ресурса, возвращённый функцией zip_open(). Параметр zip_entry это ресурс вхождения директории, возвращённый функцией zip_read(). Необязательный параметр mode может быть одним из режимов, специфицированных в документации для fopen().
Примечание: в настоящее время mode игнорируется и всегда имеет значение “rb”.Это из-за тог, что zip поддерживается в PHP с доступом только для чтения. Возвращает true при успехе, false при неудаче. В отличие от fopen() и других подобных функций, возвращаемое значение функции zip_entry_open() указывает только на результат операции и не нужно для чтения или закрытия вхождения директории.
Читает до length байтов из открытого вхождения директории. Если параметр length не специфицирован, Функция zip_entry_read() пытается прочитать 1024 байта. Параметр zip_entry является правильным вхождением директории, возвращённым функцией zip_read(). Возвращает прочитанные данные, или false, если достигнут конец файла.
Примечание: параметр length должен быть несжатым размером, который вы хотите прочитать.
Открывает новый zip-архив для чтения. Параметр filename это имя файла открываемого zip-архива. Возвращает дескриптор ресурса для дальнейшего использования в zip_read() и zip_close(), или возвращает false, если filename не существует.
Читает следующее вхождение в файле zip-архива. Параметр zip обязан быть zip-архивом, открытым ранее функцией zip_open(). Возвращает ресурс вхождения директории для дальнейшего использования с zip_entry_… () функциями.
Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read(). Возвращает сжатый размер вхождения директории zip_entry.
Параметр zip_entry обязан быть правильным вхождением директории, открытым функцией zip_read(). Возвращает метод сжатия для вхождения директории zip_entry.
Ниже приведен найденный и модифицированный мной исходный код функции для распаковки архива. Данная функция производит распаковку архива в корневой каталог. Поэтому если есть необходимость в создании директории для последующего расположения в ней распакованных файлов и каталогов, то ее требуется слегка изменить.
Выше был продемонстрирован классический пример распаковки архива. Обратите внимание на то, что указанный к архиву путь, должен быть абсолютным. Но тем не менее существует еще одна возможность, чтобы его распаковать. Для этого нужно прибегнуть к помощи методов класса ZipArchive. Этот класс находится все в том же расширении “php_zip”. Итак для того чтобы применить другой вариант распаковки, необходимо написать следующий код:
Для распаковки архива у данного класса используется только один метод:
Будущая директория местонахождения распакованного архива задается в параметре $destination. Параметр $entries содержит элементы для извлечения. Он является необязательным и может принимать как одно значение, так и массив значений.
Второй вариант выглядит намного красивее и компактнее, чем первый, не так ли? Поэтому я свой выбор остановил именно на нем. И напоследок протестируем оба варианта на скорость распаковки архива объемом в 205Mb:
Создание архива
Создание архива происходит сложнее, чем его распаковка. Если конечно требуется создать архив с одним файлом или одной директорией, то здесь все просто. А вот если упаковывать директории с неограниченным уровнем вложенности каталогов, то здесь уже придется немного подумать. Во-первых, необходим хороший рекурсивный алгоритм для обхода директорий. Во-вторых, нужно дополнительно хранить локальное имя файла/каталога. Итак, для создания архива нам понадобятся четыре метода класса ZipArchive:
Добавляет в архив пустую директорию. Параметр dirname должен содержать имя директории. Метод в случае успеха возвращает true или false в противном случае.
Добавляет в архив файл, который находится по указанному в параметре filename пути. Параметр localname отвечает за имя файла в архиве. И если он указан, то параметр filename будет переопределен. Параметры start и length, зарезервированы для будущих целей. Данный метод так же в случае успеха возвращает true или false в случае ошибки.
Данный метод необходим для открытия нового архива с целью: чтения, записи или создания. Параметр filename должен содержать имя архива. Необязательный параметр flags используется в качестве режима открытия файла (ZIPARCHIVE::OVERWRITE, ZIPARCHIVE::CREATE, ZIPARCHIVE::EXCL, ZIPARCHIVE::CHECKCONS). Метод возвращает true в случае успеха или код ошибки (см. предопределенные константы ошибок).
Этот метод закрывает открытый или созданный архив и сохраняет изменения. Данный метод автоматически вызывается в конце сценария.
Ниже приведен исходный код созданного класса, позволяющего производить создание zip-архивов:
Данный класс позволяет создавать архив из каталогов с неограниченным уровнем вложенности. Для создания архива, необходимо вызвать только один метод ToZip.
Создает zip-архив. В параметре source требуется указать путь к каталогу или файлу, который требуется запаковать. А в качестве параметра destination передается имя будущего архива. Метод возвращает true в случае успеха или false в случае возникновения ошибки.
Примеры использования:
Предопределенные константы режима работы
Предопределенные константы флагов
Предопределенные константы методов сжатия
Предопределенные константы ошибок
Свежие записи
Рубрики:
Теги