Как заархивировать файлы на сервере php

Обновлено: 03.07.2024

Если вы пользовались компьютером хоть немного, то возможно вам встречались файлы с расширением .zip. Это специальные файлы в которые могут содержать в сжатом состоянии большое количество других файлов, директорий и поддиректорий. Это делает их очень удобными для передачи данных через интернет. А знаете ли вы, что вы можете использовать Python для сжатия и распаковки архивов?

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

Сжатие Одиночных Файлов

Это очень просто, и потребует написать совсем немного кода. Начинаем с того, что импортируем модуль zipfile и затем инициируем объект ZipFile с возможностью записи, указав это с помощью второго параметра 'w'. Первый параметр, это путь к файлу. Вот код, который нам нужен:

Пожалуйста, обратите внимание, что я буду указывать путь во всех фрагментах кода в формате для Windows; если вы работаете на Linux или Mac, вам нужно будет внести соответствующие изменения.

Вы можете указать различные методы сжатия, что бы заархивировать файл. В Python версии 3.3 были добавлены новые методы BZIP2 и LZMA , а также некоторые другие инструменты, которые не поддерживают эти два метода сжатия. По этой причине безопасно использовать метод DEFLATED . Но вам все же стоит попробовать эти методы, что бы увидеть разницу в размерах сжатого файла.

Сжатие Нескольких Файлов

Это будет чуть сложнее, так как вы должны выполнить итерационный процесс для всех файлов. Код показанный ниже должен заархивировать все файлы в директории с расширением pdf.

На этот раз нам необходимо импортировать модуль os и использовать метод walk() , чтобы пробежаться про всем файлам и поддиректориям в нашей основной директории. Я архивирую только файлы с расширением pdf. Вы так же можете создавать различные архивные файлы для разных форматов файлов используя оператор if .

Если вы не хотите, сохранить структуру каталога, вы можете положить все файлы вместе, используя следующую строку:

Метод write() допускает три параметра. Первый параметр - это имя нашего файла, который мы хотим сжать. Второй параметр не обязательный, он позволяет вам указать другое имя для файла архива. Если ничего не указано, будет использоваться имя архивируемого файла.

Извлечение Всех Файлов

Вы можете использовать метод extractall() для извлечения всех файлов и папок из zip-файла в текущую рабочую директорию. Вы можете также указать имя папки в extractall() для извлечения всех файлов и директорий в заданный каталог. Если директория, которую вы указали не существует, метод сам создаст новую. Вот код, который вы можете использовать для извлечения файлов:

Если вы хотите распаковать несколько файлов, вам необходимо подставить имена этих файлов в виде списка.

Извлечение Единичных Файлов

Это подобно извлечению нескольких файлов. Одно отличие состоит в том, что на этот раз, вам необходимо сначала подставить имя файла и затем, путь для извлечения. Кроме того необходимо использовать метод extract() вместо extractall() . Вот фрагмент кода для извлечения отдельных файлов.

Чтение Архивов

Рассмотрим сценарий, где вам нужно узнать содержит ли zip-архив конкретный файл. До этого момента, вы могли это сделать только распаковав весь архив. Аналогичным образом, может потребоваться извлечь только те файлы, которые больше, определенного размера. Модуль Zipfile позволяет нам узнать содержимое архива без его распаковки.

Применение метода namelist() к объекту ZipFile вернет список всех элементов архива по имени. Чтобы получить информацию о конкретном файле в архиве, можно использовать для ZipFile метод getinfo() . Это даст вам доступ к информации об этом файле, такой как, размер сжатого и несжатого файла или информацию о времени его последнего изменения. Мы вернемся к этому позже.

Вызов метода getinfo() для каждого файла может быть утомительным процессом, когда этих файлов много. В этом случае можно использовать метод infolist() для возврата списка всех элементов, содержащихся в объекте ZipInf. Порядок этих объектов в списке такой же, как и в zip-файлах.

Вы можете также непосредственно прочитать содержимое определенного файла из архива, с помощью метода read(file) , где file — имя файла, который вы хотите прочесть. Для этого, архив должен быть открыт в режиме чтения или в режиме добавления.

Чтобы получить размер конкретного сжатого файла из архива, нужно использовать атрибут compress_size . Аналогично чтобы узнать, несжатый размер, можно использовать атрибут file_size .

Следующий код использует свойства и методы, которые мы только что обсудили, чтобы извлечь только те файлы, размер которых менее 1 МБ.

Чтобы узнать время и дату последнего изменения определенного файла из архива, можно использовать атрибут date_time . Это возвращает кортеж из шести величин. Этими величинами будут год, месяц, день месяца, часы, минуты и секунды, в установленном порядке. Год будет всегда больше или равен 1980 года и часы, минуты и секунды от нуля.

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

Заключительные мысли

Как видно из этого урока, использование модуля zipfile, позволяет вам гибко использовать сжатие файлов. Вы можете архивировать файлы в директории в различные архивы в зависимости от их типа, имени и размера. Вы так же можете решать оставлять вам структуру директории или нет. Аналогично при извлечении файлов, вы можете извлекать их куда вам нужно, на основе собственных критериев, таких как размер, и т.д.

Если честно, мне было очень интересно архивировать и извлекать файлы пока я писал свой код. Я надеюсь урок был вам полезен, и если у вас остались какие-то вопросы, пишите их пожалуйста в комментариях.

Значение индекса последней добавленной записи (файл или каталог). Доступно с PHP 8.0.0 и PECL zip 1.18.0.

Статус Zip-архива. Доступно для закрытого архива, начиная с PHP 8.0.0 и PECL zip 1.18.0.

Системный статус Zip-архива. Доступно для закрытого архива, начиная с PHP 8.0.0 и PECL zip 1.18.0.

Количество файлов в архиве

Имя файла в файловой системе

Комментарий к архиву

Содержание

User Contributed Notes 15 notes

Zip a folder (include itself).
Usage:
HZip::zipDir('/path/to/sourceDir', '/path/to/out.zip');

<?php
class HZip
<
/**
* Add files and sub-directories in a folder to zip file.
* @param string $folder
* @param ZipArchive $zipFile
* @param int $exclusiveLength Number of text to be exclusived from the file path.
*/
private static function folderToZip ( $folder , & $zipFile , $exclusiveLength ) <
$handle = opendir ( $folder );
while ( false !== $f = readdir ( $handle )) <
if ( $f != '.' && $f != '..' ) <
$filePath = " $folder / $f " ;
// Remove prefix from file path before add to zip.
$localPath = substr ( $filePath , $exclusiveLength );
if ( is_file ( $filePath )) <
$zipFile -> addFile ( $filePath , $localPath );
> elseif ( is_dir ( $filePath )) <
// Add sub-directory.
$zipFile -> addEmptyDir ( $localPath );
self :: folderToZip ( $filePath , $zipFile , $exclusiveLength );
>
>
>
closedir ( $handle );
>

/**
* Zip a folder (include itself).
* Usage:
* HZip::zipDir('/path/to/sourceDir', '/path/to/out.zip');
*
* @param string $sourcePath Path of directory to be zip.
* @param string $outZipPath Path of output zip file.
*/
public static function zipDir ( $sourcePath , $outZipPath )
<
$pathInfo = pathInfo ( $sourcePath );
$parentPath = $pathInfo [ 'dirname' ];
$dirName = $pathInfo [ 'basename' ];

$z = new ZipArchive ();
$z -> open ( $outZipPath , ZIPARCHIVE :: CREATE );
$z -> addEmptyDir ( $dirName );
self :: folderToZip ( $sourcePath , $z , strlen ( " $parentPath /" ));
$z -> close ();
>
>
?>

With PHP 5.6+, you may come up with theses errors.

Warning: Unknown: Cannot destroy the zip context in Unknown on line 0

Warning: ZipArchive::close(): Can't remove file: No such file or directory in xxxx.php on line xx

Warning: Unknown: Cannot destroy the zip context in Unknown on line 0

So, don't forget to put at least one file to your zip archive.

A way of zipping files and downloading them thereafter:
<?php

$files = array( 'image.jpg' , 'text.txt' , 'music.wav' );
$zipname = 'enter_any_name_for_the_zipped_file.zip' ;
$zip = new ZipArchive ;
$zip -> open ( $zipname , ZipArchive :: CREATE );
foreach ( $files as $file ) $zip -> addFile ( $file );
>
$zip -> close ();

///Then download the zipped file.
header ( 'Content-Type: application/zip' );
header ( 'Content-disposition: attachment; filename=' . $zipname );
header ( 'Content-Length: ' . filesize ( $zipname ));
readfile ( $zipname );

The following code can be used to get a list of all the file names in a zip file.

<?php
$za = new ZipArchive ();

$za -> open ( 'theZip.zip' );

for( $i = 0 ; $i < $za -> numFiles ; $i ++ ) <
$stat = $za -> statIndex ( $i );
print_r ( basename ( $stat [ 'name' ] ) . PHP_EOL );
>
?>

Simple class xZip to zip big folders into multiple parts and unzip multi zip files at once.

<?php
class xZip public function __construct () <>
private function _rglobRead ( $source , & $array = array()) if (! $source || trim ( $source ) == "" ) $source = "." ;
>
foreach ((array) glob ( $source . "/*/" ) as $key => $value ) $this -> _rglobRead ( str_replace ( "//" , "/" , $value ), $array );
>

foreach ((array) glob ( $source . "*.*" ) as $key => $value ) $array [] = str_replace ( "//" , "/" , $value );
>
>
private function _zip ( $array , $part , $destination ) $zip = new ZipArchive ;
@ mkdir ( $destination , 0777 , true );

if ( $zip -> open ( str_replace ( "//" , "/" , " < $destination >/partz < $part >.zip" ), ZipArchive :: CREATE )) foreach ((array) $array as $key => $value ) $zip -> addFile ( $value , str_replace (array( "../" , "./" ), NULL , $value ));
>
$zip -> close ();
>
>
public function zip ( $limit = 500 , $source = NULL , $destination = "./" ) if (! $destination || trim ( $destination ) == "" ) $destination = "./" ;
>

$this -> _rglobRead ( $source , $input );
$maxinput = count ( $input );
$splitinto = (( $maxinput / $limit ) > round ( $maxinput / $limit , 0 )) ? round ( $maxinput / $limit , 0 ) + 1 : round ( $maxinput / $limit , 0 );

for( $i = 0 ; $i < $splitinto ; $i ++) $this -> _zip ( array_slice ( $input , ( $i * $limit ), $limit , true ), $i , $destination );
>

unset( $input );
return;
>
public function unzip ( $source , $destination ) @ mkdir ( $destination , 0777 , true );

foreach ((array) glob ( $source . "/*.zip" ) as $key => $value ) $zip = new ZipArchive ;
if ( $zip -> open ( str_replace ( "//" , "/" , $value )) === true ) $zip -> extractTo ( $destination );
$zip -> close ();
>
>
>

public function __destruct () <>
>

//$zip = new xZip;
//$zip->zip(500, "images/", "images_zip/");
//$zip->unzip("images_zip/", "images/");
?>

There is a usefull function to get the ZipArchive status as a human readable string :

<?php
function ZipStatusString ( $status )
switch( (int) $status )
case ZipArchive :: ER_OK : return 'N No error' ;
case ZipArchive :: ER_MULTIDISK : return 'N Multi-disk zip archives not supported' ;
case ZipArchive :: ER_RENAME : return 'S Renaming temporary file failed' ;
case ZipArchive :: ER_CLOSE : return 'S Closing zip archive failed' ;
case ZipArchive :: ER_SEEK : return 'S Seek error' ;
case ZipArchive :: ER_READ : return 'S Read error' ;
case ZipArchive :: ER_WRITE : return 'S Write error' ;
case ZipArchive :: ER_CRC : return 'N CRC error' ;
case ZipArchive :: ER_ZIPCLOSED : return 'N Containing zip archive was closed' ;
case ZipArchive :: ER_NOENT : return 'N No such file' ;
case ZipArchive :: ER_EXISTS : return 'N File already exists' ;
case ZipArchive :: ER_OPEN : return 'S Can\'t open file' ;
case ZipArchive :: ER_TMPOPEN : return 'S Failure to create temporary file' ;
case ZipArchive :: ER_ZLIB : return 'Z Zlib error' ;
case ZipArchive :: ER_MEMORY : return 'N Malloc failure' ;
case ZipArchive :: ER_CHANGED : return 'N Entry has been changed' ;
case ZipArchive :: ER_COMPNOTSUPP : return 'N Compression method not supported' ;
case ZipArchive :: ER_EOF : return 'N Premature EOF' ;
case ZipArchive :: ER_INVAL : return 'N Invalid argument' ;
case ZipArchive :: ER_NOZIP : return 'N Not a zip archive' ;
case ZipArchive :: ER_INTERNAL : return 'N Internal error' ;
case ZipArchive :: ER_INCONS : return 'N Zip archive inconsistent' ;
case ZipArchive :: ER_REMOVE : return 'S Can\'t remove file' ;
case ZipArchive :: ER_DELETED : return 'N Entry has been deleted' ;

default: return sprintf ( 'Unknown status %s' , $status );
>
>

Read a file from an archive to a variable.
A warning is printed automatically in case of a CRC32 mismatch, which we capture, so we can print our own error message.

<?php
$zip = new ZipArchive ();
if ( $zip -> open ( 'archive.zip' )) $fp = $zip -> getStream ( 'myfile.txt' ); //file inside archive
if(! $fp )
die( "Error: can't get stream to zipped file" );
$stat = $zip -> statName ( 'myfile.txt' );

$buf = "" ; //file buffer
ob_start (); //to capture CRC error message
while (! feof ( $fp )) $buf .= fread ( $fp , 2048 ); //reading more than 2156 bytes seems to disable internal CRC32 verification (bug?)
>
$s = ob_get_contents ();
ob_end_clean ();
if( stripos ( $s , "CRC error" ) != FALSE ) echo 'CRC32 mismatch, current ' ;
printf ( "%08X" , crc32 ( $buf )); //current CRC
echo ', expected ' ;
printf ( "%08X" , $stat [ 'crc' ]); //expected CRC
>

fclose ( $fp );
$zip -> close ();
//Done, unpacked file is stored in $buf
>
?>

To create a corrupt file, change a byte in a zip file using a hex editor.

There is a limit withing PHP 5.3.3 (which seems to have been addressed in later versions; 5.3.29 seems ok on a different server).

If you try to open a zip file with more than 65,535 files in it (in my case it had 237,942 files) then you cannot access the later files. The numFiles property only reports the first 65k files.

<?php
//use bzip2 + ZipArchive to reduce file size of your zip archives.
$zip = new ZipArchive ;
$zip -> open ( 'i.zip' , ZIPARCHIVE :: CREATE | ZIPARCHIVE :: OVERWRITE );
$file = 'wuxiancheng.cn.sql' ;
$bzFilename = $file . '.bz2' ;
$sql = file_get_contents ( $file );
$sql = bzcompress ( $sql , 9 );
$zip -> addFromString ( $bzFilename , $sql );
$zip -> setArchiveComment ( 'zipped on ' . date ( 'Y-M-d' ));
?>

Hi there.
I just wrote a little function to zip a whole folder while maintaining the dir-structure. I hope it might help someone.

<?php
function folderToZip ( $folder , & $zipFile , $subfolder = null ) if ( $zipFile == null ) // no resource given, exit
return false ;
>
// we check if $folder has a slash at its end, if not, we append one
$folder .= end ( str_split ( $folder )) == "/" ? "" : "/" ;
$subfolder .= end ( str_split ( $subfolder )) == "/" ? "" : "/" ;
// we start by going through all files in $folder
$handle = opendir ( $folder );
while ( $f = readdir ( $handle )) if ( $f != "." && $f != ".." ) if ( is_file ( $folder . $f )) // if we find a file, store it
// if we have a subfolder, store it there
if ( $subfolder != null )
$zipFile -> addFile ( $folder . $f , $subfolder . $f );
else
$zipFile -> addFile ( $folder . $f );
> elseif ( is_dir ( $folder . $f )) // if we find a folder, create a folder in the zip
$zipFile -> addEmptyDir ( $f );
// and call the function again
folderToZip ( $folder . $f , $zipFile , $f );
>
>
>
>
?>

Use it like this:
<?php
$z = new ZipArchive ();
$z -> open ( "test.zip" , ZIPARCHIVE :: CREATE );
folderToZip ( "storeThisFolder" , $z );
$z -> close ();
?>

Have a good day!

Here is a simple function which zips folders with all sub folders or only a simple file. the $data var can be a string or an array.

<?php
public function un_zip ( $data , $arcpf , $mode = 'zip' , $obj = '' ) <
$absoluterpfad = 'YOUR_BASE_PATH' ;
$arcpf = $absoluterpfad . DS . $arcpf ;
if( is_object ( $obj )== false ) <
$archiv = new ZipArchive ();
$archiv -> open ( $arcpf , ZipArchive :: CREATE );
>else < $archiv =& $obj ;>
if( $mode == 'zip' ) <
if( is_array ( $data )== true ) <
foreach( $data as $dtmp ) <
$archiv =& un_zip ( $dtmp , $arcpf , 'zip' ,& $archiv );
>
>else <
if( is_dir ( $data )== true ) <
$archiv -> addEmptyDir ( str_replace ( $absoluterpfad . DS , '' , $data ));
$files = scandir ( $data );
$bad = array( '.' , '..' );
$files = array_diff ( $files , $bad );
foreach( $files as $ftmp ) <
if( is_dir ( $data . DS . $ftmp )== true ) <
$archiv -> addEmptyDir ( str_replace ( $absoluterpfad . DS , '' , $data . '/' . $ftmp ));
$archiv =& un_zip ( $data . DS . $ftmp , $arcpf , 'zip' ,& $archiv );
>elseif( is_file ( $data . DS . $ftmp )== true ) <
$archiv -> addFile ( $data . DS . $ftmp , str_replace ( $absoluterpfad . DS , '' , $data . '/' . $ftmp ));
>
>
>elseif( is_file ( $data )== true ) < $archiv -> addFile ( $data , str_replace ( $absoluterpfad . DS , '' , $data ));>
>
>
if( is_object ( $obj )== false ) < $archiv -> close ();>
else
if( $mode == 'unzip' ) < $archiv -> extractTo ( $data );>
>
?>

Important: Due to the natural file size limit of 4GB (

3,6GB to be correct) of zip files, this class will generate corrupt files of the result is larger than 4 GB. Using tar.gz is a proper alternative.

Be wary that there are several algorithms to generate a zip file. I found that Office OpenXML files created with ZipArchive are not recognized by Excel 2007, for example.

You have to use a different class to zip in this case, such as PclZip.

You can check general purpose flag to test if the zip file is encrypted. Example function below.

/**
* Check if the file is encrypted
*
* Notice: if file doesn't exists or cannot be opened, function
* also return false.
*
* @param string $pathToArchive
* @return boolean return true if file is encrypted
*/
function isEncryptedZip ( $pathToArchive ) $fp = @ fopen ( $pathToArchive , 'r' );
$encrypted = false ;
if ( $fp && fseek ( $fp , 6 ) == 0 ) $string = fread ( $fp , 2 );
if ( false !== $string ) $data = unpack ( "vgeneral" , $string );
$encrypted = $data [ 'general' ] & 0x01 ? true : false ;
>
fclose ( $fp );
>
return $encrypted ;
>

How to detect corrupt files with CRC mismatch:

Creating a corrupt archive for testing is simple - zip some files and change a byte with a hex editor in the resulting ZIP file. Now you can test the file with a ZIP application to learn which file inside the archive is corrupt.

ZipArchive seems unable to detect broken files. ZipArchive::CHECKCONS doesn't help, only if it's not a ZIP file at all. It happily decompressed corrupt files in my tests and the user downloading the data is not informed.

Первая половина этого руководства объясняет различные способы создания ZIP-файла с помощью встроенных API-интерфейсов CodeIgniter. Мы увидим, как создавать и сохранять zip-файлы на сервере, и как вы можете сделать их доступными для загрузки конечным пользователям.

Вторая половина включает обсуждение того, как вы можете разархивировать файл. Чтобы продемонстрировать это, мы создадим пользовательскую страницу, которая позволит пользователям загружать zip-файлы, которые будут извлечены на сервере после успешной загрузки файла. Для достижения желаемых функциональных возможностей нам пригодится расширение ZipArchive PHP!

Прежде чем мы продолжим и фактически погрузимся в материал разработки, я перечислил файлы, которые мы собираемся разработать в ходе этого учебника:

  • Application / controllers / Zip.php: Это файл контроллера, который демонстрирует различные способы создания zip-файла.
  • Application / controllers / Unzip.php: Это файл контроллера, который включает в себя код, используемый для распаковки загруженного пользователем файла.
  • Application / views / file_upload_form.php: Это файл представления, который содержит довольно простой код для загрузки файлов HTML.
  • Application / views / file_upload_result.php: это файл представления, который показывает результат загруженного пользователем файла; В основном это говорит вам, если файл был успешно разархивирован.
  • Application / libraries / Extractor.php: Этот файл демонстрирует концепцию пользовательской библиотеки в CodeIgniter.

Со всем, что у нас есть, мы готовы перейти к следующему разделу!

Как архивировать файлы?

Идем дальше и создаем файл application/controllers/Zip.php со следующим содержимым.

Это довольно стандартный файл контроллера, с которым вы уже знакомы. Он содержит несколько методов, и каждый из них показывает вам другой способ создания zip-файла.

Кроме того, он предоставляет два частных метода: _load_zip_lib и _archieve_and_download , которые вызываются из остальных методов. Конечно, вам не нужно реализовывать эти методы, но мы просто реорганизовали наш код, чтобы вы не повторяли тот же код в других методах. Давайте сначала рассмотрим эти два метода.

Вот как выглядит метод _load_zip_lib.

Он загружает встроенную zip-библиотеку среды CodeIgniter, чтобы вы могли использовать возможности этой библиотеки во всем остальном коде. Теперь вы можете получить доступ к zip-библиотеке с помощью соглашения $this-> zip .

Далее, рассмотрим метод _archieve_and_download .

Когда мы загрузили zip-библиотеку, вы можете использовать предоставленные ею методы. Метод архивирования позволяет вам по пути создать zip-файл, указанному в качестве первого аргумента. С другой стороны, метод загрузки предлагает пользователю загрузить файл.

Не беспокойтесь, если вы задаетесь вопросом о содержимом нашего zip-файла, сейчас мы к этому перейдем.

Все на месте, поэтому мы готовы к работе!

Давайте рассмотрим код метода data. Этот метод показывает вам, как создавать файлы «на лету» и переносить их в zip-файл.

Начнем с того, что мы вызвали метод _load_zip_lib , который загружает библиотеку zip. Затем мы использовали метод add_data класса zip, который позволяет вам создать файл и одновременно заполнить его содержимым! Конечно, он будет добавлен в архив!

Первый аргумент должен быть именем файла, а второй - содержимым файла.

Как вы можете видеть, мы добавили два файла: name.txt и profile.txt , с некоторым демо-контентом. Наконец, мы вызываем _archieve_and_download с my_info.zip в качестве аргумента этого метода. Что он делает?

  • Он создаст zip-файл my_info.zip в каталоге загрузки.
  • Он также предложит пользователю загрузить файл, а имя, в котором будет сохранен файл, будет my_info.zip .

Если у вас возникнут проблемы, вы можете задать их мне в комментариях!

Далее, есть метод data_array .

Этот метод идентичен предыдущему, о котором мы только что говорили, за исключением того, что мы предоставили массив файлов методу add_data вместо отдельных файлов!

Затем давайте рассмотрим код метода data_with_subdirs .

На всякий случай, если вы хотите упорядочить свои файлы в определенных каталогах, метод add_data также позволяет создавать их. Полученный результат вышеупомянутого метода не будет отличаться, за исключением того, что файлы name.tx t и profile.txt будут помещены в каталог info .

Хотя метод add_data предоставляет хорошую возможность, которая позволяет вам создавать файлы «на лету», чаще всего вам необходимо заархивировать существующие файлы на сервере. Во всяком случае, это как раз тема наших следующих методов.

Давайте быстро посмотрим, как выглядит наш следующий метод files . Он создаст zip архив файлов в каталоге uploads .

Цель метода read_file - прочитать существующий файл на сервере и добавить его в архив. Итак, как вы видите, что мы добавили два файла 1.jpg и 2.jpg в архив. Конечно, эти два файла должны присутствовать в каталоге uploads в корневом каталоге вашего сайта.

Если вы передадите TRUE как второй аргумент метода read_file , результирующий zip-файл сохранит точную структуру директории, в которую был помещен файл.

Последний метод в этом сегменте - это метод dir . Он создаст zip-архив всего каталога.

Вы можете использовать метод read_dir , если хотите создать zip-архив всего каталога вместо определенных файлов. В нашем примере выше он создаст файл dir_images.zip , содержащий все файлы в каталоге /uploads/images/ .

Важно отметить, что вся структура каталогов будет сохранена по умолчанию в zip-файле. Но, если вы хотите проигнорировать его, просто передайте FALSE в качестве второго аргумента метода read_dir . В этом случае создается только каталог images в zip-файле.

Итак, мы заканчиваем нашу историю о том, как создавать zip-архив, используя различные методы, предоставляемые встроенным zip-классом.

Как распаковать файлы?

К сожалению, нет встроенной библиотеки CodeIgniter, которая позволяет нам разархивировать zip-архив. Но расширение ZipArchive PHP делает этот процесс весьма легким, как мы сейчас увидим.

Мы создадим довольно простой пример, демонстрирующий, как разархивировать загруженные пользователем файлы.

Идем дальше и создаем файл application/controllers/Unzip.php со следующим содержимым.

Давайте также создадим наши шаблоны представлений, и тогда мы увидим, как это работает.

Создайте файл шаблон application/views/file_upload_form.php со следующим содержимым.

Он создает простую форму для загрузки файлов, чтобы пользователь мог загрузить zip-файл! Пожалуйста, обратите внимание, что я свел все к минимуму ради простоты.

Теперь давайте создадим файл шаблона application/views/file_upload_result.php

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

Теперь давайте вернемся к нашему контроллеру и пройдемся по каждому методу.

В конструкторе нашего контроллера мы загрузили встроенные хелперы CodeIgniter такие как form и url, чтобы мы могли использовать вспомогательные функции, такие как form_open_multipart , site_url и т.п.

Затем давайте посмотрим на метод index .

Также обратите внимание, что действие нашей формы - unzip/upload , где данные будут отправлены. Мы использовали хелпер form_open_multipart для создания тега multipart form!

Upload Page
Upload Page
Upload Page

Затем нам нужно реализовать метод upload , который будет обрабатывать файлы для загрузки и извлечения файлов. Используйте для него код из контроллера Unzip.php .

Если вы знакомы с загрузкой файлов в CodeIgniter, код не должен выглядеть чужим для новым. Для тех, кто не знаком, вам не о чем беспокоиться, так как встроенные API загрузки в CodeIgniter довольно просты.

Следующий код загружает библиотеку загрузки с некоторой начальной конфигурацией, предоставляемой переменной массива $config .

Мы настроили его так, чтобы загруженный файл был помещен в папку uploads в корне приложения, и пользователю будет разрешено загружать только zip-файлы.

В этом случае файл загружается успешно, поэтому следующий шаг - это путь к загруженному файлу.

Наконец, мы создаем объект ZipArchive, открываем наш zip-файл и извлекаем его в каталог uploads .

Единственное, что нам осталось - это вызвать представление file_upload_result , и вот как оно должно выглядеть!

Upload Result Page
Upload Result Page
Upload Result Page

Итак, это другая часть истории!

Рефакторинг Unzipping кода в библиотеку

Вы заметили бы, что метод upload содержит код ZipArchive, который извлекает загруженный файл. Что делать, если вам нужно использовать этот код в нескольких местах? Возможно, у вас возникнет соблазн скопировать и вставить код по мере необходимости.

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

Двигаемся дальше и создаем файл application/libraries/Extractor.php со следующим содержимым.

Теперь давайте заменим метод upload в вашем Unzip.php -контроллере следующим.

Как вы можете видеть, мы загрузили нашу пользовательскую библиотеку и использовали ее для извлечения содержимого!

И да, это конец этой статьи.

Заключение

Надеюсь, вам понравилась статья, в которой мы начали изучать основную zip-библиотеку среды CodeIgniter и различными способами создавать ZIP-архив. Во второй части я объяснил, как можно распаковывать загруженные пользователем файлы с помощью расширения ZipArchive PHP.

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

Сжатие файлов при их передаче через Интернет имеет множество преимуществ. В большинстве случаев, общий размер всех файлов в сжатом виде приятно уменьшается. Это означает, что вы сэкономите трафик, а пользователи получат более быструю скорость загрузки. Когда пользователи загрузят файл, они могут распаковывать его в любое время. Короче говоря, сжатие может сделать передача файлов через Интернет намного проще и для вас, и для ваших посетителей.

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

В этом уроке вы научитесь применять zip и unzip — сжимать и извлекать файлы в/из zip-архив в PHP. Вы также узнаете, как удалить или переименовать файлы в архиве, не без их извлечения.

Сжатие файлов в PHP

Класс PHP ZipArchive обладает множеством свойств и методов, которые помогут вам сжсжимать и распаковывать все ваши файлы.

Сжатие отдельных файлов

Вы можете добавлять файлы в zip-архив по одному или сразу весь каталог. В любом случае первым шагом является создание нового экземпляра ZipArchive , а затем вызов метода open ($filename, [$flags]) . Этот метод откроет новый zip-архив для чтения, записи или других изменений. Существует четыре допустимых значения для необязательного параметра $flag , которым определяется способ обработки.

  • ZipArchive::OVERWRITE — этот флаг перезапишет содержимое в указанном архиве, если он уже существует.
  • ZipArchive::CREATE — этот флаг создаст новый архив, если он ещё не существует.
  • ZipArchive::EXCL — этот флаг приведёт к ошибке, если архив уже существует.
  • ZipArchive::CHECKCONS — этот флаг сообщает PHP о выполнении дополнительных проверок на целостность архива и выдаст ошибку, если при неудачной проверке.

Вы можете посмотреть документацию по этому методу, чтобы узнать о различных кодах ошибок, возвращаемых в случае сбоев при открытии файла. Если zip-файл успешно открыт или создан, метод вернет true .

Если архив откроется успешно, вы можете использовать метод addFile($filename, $localname, $start, $length) для добавления любого файла с заданным путем в ваш архив. Параметр $filename — это путь к файлу, который вы хотите добавить в архив. Параметр $localname используется для присвоения имени файлу для хранения его внутри архива. Вы можете вызывать addFile() каждый раз, когда хотите добавить новый файл в архив.

После добавления всех необходимых файлов в архив, вы можете вызвать метод close() , чтобы закрыть его и сохранить изменения.

Допустим, у вас есть веб-сайт, который позволяет пользователям скачивать файлы шрифтов вместе с их лицензиями. Файлы, подобные этим, станут прекрасными примерами автоматизированного архивирования на PHP. Следующий код показывает, как это делается.

Мы начнём с создания экземпляра ZipArchive , а затем с помощью метода open() создадим наш архив. С помощью метода addFile() добавим в архив файлы шрифта .ttf и лицензии .txt.

Следует отметить, что исходные файлы находились внутри каталога fonts/Monoton. Однако, код PHP помещает его прямо в корень нашего архива. Вы можете изменить структуру каталогов, а также имена файлов, находящихся в архиве.

Сжатие нескольких файлов из каталога

Добавление отдельных файлов в архив, со временем, может стать утомительным. Например, вы можете создать архив всех .pdf или .jpg файлов в каталоге. В этом случае, метод addGlob($pattern, $flags, $options) докажет свою полезность. Единственный минус этого метода в том, что вы теряете контроль над расположением отдельных файлов в архиве. Однако, вы все равно можете влиять на структуру каталогов внутри архива, используя параметр $options . Параметры передаются в виде ассоциативного массива.

  • add_path — значение, которое вы назначаете на add_path , ставится перед (префикс) локальным адресом файла в архиве.
  • remove_path — значение, которое вы назначаете на remove_path , используется для удаления соответствующего префикса из пути различных файлов, которые добавляются в архив.
  • remove_all_path — если задать remove_all_path значение true , то это приведет к удалению всего из пути файла, кроме его названия. В этом случае файлы добавятся в корень архива.

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

Следующий фрагмент кода прояснит использование addGlob() и всех этих параметров.

Как обычно, мы начинаем с создания экземпляра ZipArchive и затем используем метод open() для создания нашего архива. Каждый раз перед вызовом метода addGlob() , мы указываем разные значения для ключа add_path в массиве $options . Таким образом, мы можем одновременно обработать один конкретный набор файлов и применить к нему соответствующие параметры архивирования.

В первом случае мы перебираем все файлы .jpg в каталоге lights и помещаем их в каталог light_wallpapers в архиве. Аналогично, мы перебираем все файлы .ttf в каталоге documents, а затем помещаем их в архив в папку с именем font_files. Наконец, мы перебираем сразу все файлы .jpg и .jpg в наших документах и помещаем их все вместе в каталог images.

Как вы можете видеть, значения в параметре $options полезны при организации содержимого внутри архива.

Извлечение содержимого из архива

У класса ZipArchive есть метод для извлечения содержимого архива, называемый extractTo($destination, $entries) . Вы можете использовать его для извлечения всего в архиве или только определенных файлов. Параметр $entries может использоваться для указания одного имени файла, который нужно извлечь, или же, вы можете использовать его для передачи массива файлов.

Важно помнить, что вам нужно указать правильный путь к файлу внутри архива, чтобы извлечь его. Например, мы заархивировали файл шрифта AlegreyaSans-Light.ttf в предыдущем разделе. Файл сохранён в архиве в каталоге font_files. Это означает, что путь, который нужно указать в параметре $entries , будет font_files/AlegreyaSans-Light.ttf, а не просто AlegreyaSans-Light.ttf.

Структура каталогов и файлов будет сохранена во время извлечения, и файлы будут извлечены в соответствующие каталоги.

Если вы пропустите второй параметр, данный метод извлечёт все файлы из архива.

Больше контроля над архивами

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

Вы можете подсчитать количество файлов в архиве, используя метод count() . Другой вариант — использовать свойство numFiles . Их можно использовать для перебора всех файлов в архиве и извлекать только те из них, которые вам нужны, или вы можете сделать с ними что-то ещё, например, удалить их из архива.

В следующем примере, мы удаляем все файлы из архива, содержащие слово Italic. Аналогичный код можно использовать для удаления всех файлов, которые не содержат определенного слова. Также, вы можете перебирать файлы и заменять определенное слово на другое.

В приведённом выше коде, мы используем deleteName() для удаления конкретного файла. Однако, вы можете использовать его для удаления всего каталога.

Заключительные мысли

Мы рассмотрели множество полезных методов класса ZipArchive , которые сделают автоматическое сжатие и извлечение файлов в PHP простым. Теперь вы сможете сжимать отдельные файлы или группу файлов, исходя из ваших собственных нужд. Аналогичным образом, вы должны иметь возможность извлечь любой файл из архива, не затрагивая другой контент.

С помощью count() и numFiles у вас будет больше контроля над отдельными файлами, а их переименование или удаление будет очень простым. Обязательно посмотрите документацию хотя бы один раз, чтобы узнать больше об этих функциях.

Читайте также: