Создание zip архивов с помощью PHP скрипта

6 ноября, 2007

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

Прежде всего, убедитесь, что включена поддержка всех нужных функций. Для этого в файле php.ini нужно убрать символ комментария (;) в начале строки:
extension=php_zip.dll

Теперь переходим к созданию архива.
Все операции с архивом выполняются с помощью объекта ZipArchive, создать его не сложно:

  1. $zip = new ZipArchive();

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

Если на этом этапе ошибок не произошло, то с помощью метода addFile() можно добавить в архив файлы. Метод принимает два параметра:
первый – имя исходного файла;
второй – имя под которым файл будет добавлен в архив (если этот параметр не указан, будет использовано имя из первого параметра).

Примечание. Тут есть один нюанс. Если имя исходного файла “d:/docs/myfile.txt” и вы не укажите второй параметр, то в архиве будет создана папка “d”, а в ней – “docs”. Файл “myfile.txt” будет размещен в “docs”. Чтобы избежать создания папок в архиве просто укажите во втором параметре “myfile.txt”, и тогда файл будет размещен в корне архива.

Завершает работу с архивом метод close().

Так, с теорией закончили. Теперь посмотрим, как все это работает на примере.

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

  1. <?php
  2. //папка в которой будет размещен архив
  3. $archive_dir = "E:/archiveFolder/";
  4. //папка с исходными файлами
  5. $src_dir = "E:/srcFolder/";
  6.  
  7. //создание zip архива
  8. $zip = new ZipArchive();
  9. //имя файла архива
  10. $fileName = $archive_dir."backup_".date('j_m_Y_h_m_s').".zip";
  11. if ($zip->open($fileName, ZIPARCHIVE::CREATE) !== true) {
  12.     fwrite(STDERR, "Error while creating archive file");
  13.     exit(1);
  14. }
  15.  
  16. //добавляем файлы в архив все файлы из папки src_dir
  17. $dirHandle = opendir($src_dir);
  18. while (false !== ($file = readdir($dirHandle))) {
  19.     $zip->addFile($src_dir.$file, $file);
  20. }
  21. //закрываем архив
  22. $zip->close();
  23.  
  24. fwrite(STDOUT, "Archive created\n");
  25.  
  26. exit(0);
  27. ?>

Переменная $src_dir содержит путь к папке с исходными файлами, а $archive_dir – путь к папке в которой будет создан архив.

Примечание: учтите, что наш скрипт эти папки не создает, поэтому сделайте это самостоятельно.

В переменной $fileName содержится имя архива. К имени я добавил дату и время создания архива в формате “день_месяц_год_часы_минуты_секунды”. Это позволяет многократно запускать скрипт и не думать о том, что новая версия архива запишется поверх старой.

В строках 11-14 мы открываем архив, при этом используется константа ZIPARCHIVE::CREATE, которая указывает, что если архива не существует, то он должен быть создан. Если во время создание архива возникли ошибки, выводим сообщение и завершаем работу.

После этого, мы открываем папку с исходными файлами и добавляем их в архив (строки 17-20).
Метод close() (в строке 22) закрывает архив.

Запускаем скрипт:
php путь_к_скрипту\имя_скрипта.php

Если ошибок не было, в папке "E:/archiveFolder/" вы будет создан архив.

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

Постовой

Если нужен щебень заходите на vost.ru

Понравилась статья? Подписывайтесь на продолжение rss link !

Или на мой твиттер twitter link

]]>

Добавьте эту страницу в google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

]]>

Опубликовано в PHP View Comments

]]>
  • Derfid
    Про щебень в точку! Спасибо!
  • Ralph DiMarko
    а можно ли как то запаролить архив?
  • Можно, смотрите этот комментарий
  • Ralph DiMarko
    спасибо, а может есть еще пример создания на хостинге?
    это будет что-то вроде exec(zip ) а что как дальше не знаю, кто знает подскажите пожалуйста. и как вообще проверить стоит ли на хосте архиватор.
  • Боюсь, кроме тех. поддержки хостера вам никто не подскажет. Если речь о shared хостинге, то функция exec вообще может быть запрещена.
  • У меня не работало , пока не вставил
    if ($file != '.' and $file != '..')
    {
    $zip->addFile($src_dir.$file, $file);
    }
    Без этого скрипт выполнялся , а архив не создавался.
  • Валерий
    Подскажите как запаковать папку со вложенными папками и файлами?
  • Можно написать рекурсивную функцию, которая будет обходить все папки начиная с заданной. Или использовать готовую библиотеку для этих целей. Второй вариант значительно проще ;)
  • Дмитрий
    Народ, как сделать так чтобы дотфайл не попадал в архив?
  • Просто не добавляйте его :)
    В этом примере я получаю файлы из папки с помощью readdir (строка 18). Она вернёт все файлы, находящиеся в папки. Просто вставьте внутрь цикла проверку, и пропускайте ненужные вам файлы.
  • Дмитрий
    понял, спасибо.
  • Создал бы кто нибудь нормальный мануал по делению файлов в командной строке Putty по русски с примерами. Мануалы какие то кривые и сложные.
  • prescott
    php_zip.dll - это только для венды, для линукса и уникса совсем по другому
  • Dockeee
    Да, и можно было об этом сказать. Зовется он либо php_zip.so либо просто zip.so
    Лежит в /usr/lib/php/modules/
  • Maxim
    Здравствуйте! У меня такой вопрос: Файл в архив добавляется след. образом $zip->addFile($filePath, $fileName). Можно ли в качестве $fileName передавалась строка с русским названием файла в архиве? И если можно, то как?(пробовал просто предать русскую строку но при открытии архива в качестве имён стоят козюбрики). Заранее спасибо за помощь!
  • Нет, раз у библиотеки есть проблемы с кириллицей, то лучше её не использовать. Если есть много файлов с русскими именами, то можно написать скрипт, который их переименует, например, транслитом.
  • Dockeee
    Все. Попив кофе и отдохнув свежий взгляд нашол косяки.
    итак, разбор косяков:
    в строке

    if ($zip->open($tgt_file, ZIPARCHIVE::CREATE!==true)) {

    закрывающая скобка должна стоять перед неравенством т.е. так:

    if ($zip->open($tgt_file, ZIPARCHIVE::CREATE)!==true) {

    Далее.
    обычный косяк оставленный после экспериментов с путями - сделать так:

    $src="./SourceFile.txt";
    $tgt="./TargetFile.zip";

    и все заработало.
  • Dockeee
    Попробовал немного видоизменить код - свести его в функцию, и архивировать отдельный файл, но ничего не выходит
    Сама функция (файл func.php):

    function ZIPFile($src_file, $tgt_file){
    $zip = new ZipArchive();
    if ($zip->open($tgt_file, ZIPARCHIVE::CREATE!==true)) {
    print("Ошибка создания архива");
    exit(1);
    }
    $zip->addFile($src_file);
    $zip->close();
    print("Архив".$tgt_file." создан");
    exit(0);
    }



    пытаюсь вызвать так:


    include ("func.php");
    $src=".\SourceFile.txt";
    $tgt=".\TargetFile.zip";
    ZIPFile($src, $tgt);
  • А какая ошибка при этом появляется?
    Ошибка создания архива?
    Если да, то нужно проверить может ли вообще скрипт создать этот файл ".\TargetFile.zip"? Попробуйте указать путь полностью.
  • Владимир
    Проблему решил, метод конечно очень похож на молоток и напильник, но все же расскажу, может вы меня поправите. В общем, т.к. архив создается после закрытия и мы знаем лимит файлов, можно просто после каждых 500 файлов закрывать архив и снова открывать. Проверил работает, выглядит конечно криво, но по другому не получилось.
  • Выглядит действительно не очено, но если решение работает и результат устраивает, то смысла переделывать я не вижу. Очень похоже, что проблема в самой библиотеке.
  • lio
    по дефолту работа скрипта 30 секунд, если лимит времени привышен, то скрипт ведет себя не коректно! надо прописать лимит на скрипт больше, если того требует время работы скрипта.
  • Владимир
    Такой вопрос, создаю скриптом архив, количество файлов 7000, после добавления 500 архив закрыть не может, ставлю ограничение на 500 файлов все нормально. memory_limit ставил разные значения исход тот же.
  • Есть еще параметр из-за которого может возникнуть такая проблема
    max_execution_time
  • Владимир
    Извините про лимит забыл сказать, я поставил в скрипте 3600, с большим запасом, соответственно проблема та же.
  • Вы работаете с выделенным сервером? Если да, то есть вариант обойти эту проблему. С помощью 7-zip или другого внешнего архиватора. Т.е. запустить его с помощью exec.
  • lio
    вообщем зделал. но всеравно зип в начале нужно сохранить а потом только удалить! :) может еще что подскажите горе програмисту(зачем учится языку програмирования, когда можно посматреть как это делают другие!).
    $value ) {
    $$key=$value;
    }
    } else {
    foreach ( $HTTP_GET_VARS as $key => $value ) {
    $$key=$value;
    }
    }

    if (!$lang) {
    if (substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) == 'ru') {
    $lang=ru;
    } else {
    $lang=en;
    }
    }

    require("config.php");
    require("lang/".$lang.".php");

    // Устанавливаем соединение с FTP-сервером
    if ($ftp_server) {
    if ($ftp_port) {
    if(!$connect = @ftp_connect($ftp_server, $ftp_port)) {
    error_mes(LANG_NO_CON);
    } else {
    if (!$loginOn = @ftp_login($connect, $ftp_user, $ftp_password)) error_mes(LANG_NO_REG);
    }
    } else {
    error_mes(LANG_PORT);
    }
    } else {
    error_mes(LANG_SERVER);
    }


    // Запрос файла на передачу
    if ($get) {
    @ftp_chdir($connect, $dir) or error_mes(LANG_ERROR_LOST);
    file_get($connect, $get, $tempdir, $dir);
    }
    // Если нет запроса, то продолжаем вывод списка

    $list = @ftp_rawlist($connect, $dir) or error_mes(LANG_ERROR_LOST);

    print "";
    print "".LANG_NAME."".LANG_SIZE."".LANG_DATA."".LANG_TIME."\n";

    list_ftp($list);
    @ftp_close($connect) or error_mes(LANG_ERROR_LOST);

    print " ";
    $time = date("U");
    print "$time";

    function list_ftp($list)
    {

    // Получаем все файлы выбранного каталога, указаного в config.php
    // Выводим содержимое каталога
    foreach($list as $file)
    {
    // Разбиваем строку по пробельным символам
    // Примечание: файлы не могут содержать пробелы в имени
    list($acc,
    $bloks,
    $group,
    $user,
    $size,
    $month,
    $day,
    $time,
    $file) = preg_split("/[\s]+/", $file);
    if(substr($acc, 0, 1) == '-')
    {
    print "";
    print "". $file . "";
    print "".file_size($size)."";
    print "". $month . "," . $day . "";
    print "" . $time . "";
    print "\n";
    }
    }
    }


    // Приобразовываем в нормальный размер
    function file_size($size) {
    $gb = 1024*1024*1024;
    $mb = 1024*1024;
    if ($size >= $gb) {$size = sprintf ("%01.2f",$size/$gb) . " GB";}
    else if ( $size >= $mb ) {$size = sprintf ("%01.2f",$size/$mb) . " MB";}
    else if ( $size >= 1024 ) {$size = sprintf ("%01.2f",$size/1024) . " KB";}
    else {$size = $size . " byte";}
    return $size;
    }

    // Вывод ошибок
    function error_mes($mes) {
    print "Time: ". date("U") ."Message: $mes";
    exit;
    }

    function file_get($connect,$get,$tempdir,$dir) {

    $fp = fopen($tempdir . $get, "w");
    @ftp_fget($connect, $fp, $get, FTP_BINARY) or error_mes(LANG_ERROR_DOWN);
    fclose($fp);
    @ftp_close($connect) or error_mes(LANG_ERROR_LOST);
    $zip = new ZipArchive;
    $zipfile = $get.".zip";
    $res = $zip -> open($tempdir . $zipfile, ZIPARCHIVE::CREATE);
    $zip -> addFromString("string.txt", "Это строка, которая будет записана в файл string.txt, а сам файл помещен в архив");
    // Файл file.txt будет помещен в архив под именем file_zip.txt
    $zip -> addFile($tempdir . $get, "$get");
    $zip -> close();
    header("Content-disposition: attachment; filename=\"$zipfile\"");
    header("Content-type: application/octetstream");
    readfile($tempdir . $zipfile);
    unlink($tempdir . $get);
    unlink($tempdir . $zipfile);
    exit;
    }
    ?>


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


    Например, чтобы понять куда вставлять чужой код :)
  • А готовый файл менеджер с поддержкой zip на php никто не подскажет? Желательно небольшой.
    Заранее благодарен.
  • Какая именно поддержка zip нужна?
  • lio
    пример:
    пхпскриптзаходитна фтп в указуную папку, делает фореш файлов и выводит лист пользователю (реализовал) после того как пользователь выбрал файл, тыкает на него, файло качается в тмп папки сервера и передает клиенту (реализовано) для скачки.
    но как запачить и выдать на лету этотже фаил клиенту? пытался делать с встроеным зип модулем, но он его сохраняет и не удаляет в последствии из тмп дир сервера! а нужно что бы все что скачалось с фтп сервера удалялось после передачи!
  • Решение "в лоб".
    Написать отдельный скрипт, который будет чистить папку tmp и запускать этот скрипт cron'ом.
  • Class 'ZipArchive' not found in
    Ошибка даже после перезапуска Денвера. Что можно сделать?
  • Проверить подключена ли библиотека.
    В php.ini должна быть раскоментированна строка
    extension=php_zip.dll
  • Николай
    А как можно создать запороленный архив при помощи php, можно ли его вообще создать при помощи php?
  • Это можно сделать с помощью с помощью внешних утилит, например, 7-zip. Этот архиватор допускает работу в режиме командной строки, т.е. его можно запустить с помощью функции exec

    exec(""c:\\program files\\7-zip\\7z.exe" a archive.7z -psecret -mhe *.txt");

    где secret - пароль
    Путь к архиватору, естественно, нужно указать ваш.
    Параметры командной строки описаны в справке.
    " - это дополнительные кавычки, нужны, т.к. program files содержит пробел
  • lio
    А можно ли усложнить пример?

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

    пример реализовать возможно? зарание спс.
  • Да, усложнить можно, но что означает передать клиенту? Отправить почтой?
    Или клиент заходит на сайт и выбирает файл из какого-нибудь списка?
  • Алексей
    Здравствуйте! Подскажите, как создать архив новостей на сайте? В смысле, чтобы новости не заменялись ежедневно, а было видно несколько страниц архивных новостей. Хостинг бесплатный. Заранее спасибо за ответ!
  • То, что хостинг бесплатный - это хорошо... но их много и они разные ;)
    У вас есть какая-нибудь панель управления или движок какой-то установлен?
    Если вы можете выполнять свои php скрипты, то сделать однозначно можно. Если не можете, то все зависит от возможностей панели управления.
  • Сергей
    Здравствуйте!
    Скопировал скрипт, вместо диска "е" указал "z", так как использую денвер. Пишет ошибку Warning: fwrite(): supplied argument is not a valid stream resource in Z:\home\arch.ru\www\1.php on line 24
    zipZip enabled
    Extension Version $Id: php_zip.c,v 1.1.2.49 2009/02/05 19:53:22 pajoye Exp $
    Zip version 1.8.11
    Libzip version 0.9.0
    А при проверке на наличие директории (is_dir($src_dir)) пишеь 1.
    Заранее спасибо.
  • Попробуйте изменить адрес на
    Z:/home/arch.ru/www/1.php
  • юра диденко
    Как сделать чтобы архив создавался в текущей папке? в котором были бы все файлы сайта. (я незнаю полный путь к этим файлам) Спасибо!
  • Если вы не знаете размещение файлов, то заархивировать их вы не сможете.
    Если эти файлы находятся в той же папке, что и ваш скрипт, то узнать путь к нему можно с помощью $_SERVER['SCRIPT_FILENAME']
  • Lev
    С файлами как понятно. А если надо упаковать не файлы а данные которые уже находятся в памяти? Например данные динамически генерируются на лету или находятся в скрипте в виде строк.
  • В zip архиве в любом случае должны быть файлы. Но вы можете использовать метод addFromString для того чтобы добавить в архив данные из памяти (при этом нужно будет указать имя файла который будет создан в архиве с этими данными).
  • Lev
    С файлами понятно, а если надо упаковать не файлы, а данные которые уже находятся в памяти?
    Например данные могут динамически генерироваться или содержаться в скрипте в виде строк.
  • Сори предыдущий можно удалить комент, не разобрался с тэгами :)
    Есть другой алгоритм Создание Zip на php
  • Интересно, а производительность вы не сравнивали?
  • Есть немного другой алгоритм :
blog comments powered by Disqus ]]>