Как заархивировать целую папку с помощью PHP


132

Я нашел здесь, в stackoveflow, несколько кодов о том, как заархивировать конкретный файл, но как насчет конкретной папки?

Folder/
  index.html
  picture.jpg
  important.txt

внутри My Folderесть файлы. после архивирования My Folderя также хочу удалить все содержимое папки, кроме important.txt.

Нашел это здесь, в стеке

Мне нужна ваша помощь. Спасибо.


Насколько я понимаю, предоставленная вами ссылка stackoverflow на самом деле архивирует несколько файлов. С какой частью у вас проблемы?
Лассе Эспехольт

@lasseespeholt Ссылка, которую я вам дал, заархивирует только конкретный файл, а не папку и ее содержимое ..
woninana

Он берет массив файлов (по сути, папку) и добавляет все файлы в zip-файл (цикл). Я вижу, что сейчас был опубликован прекрасный ответ +1 :), который является тем же кодом, массив теперь представляет собой просто список файлов из каталога.
Лассе Эспехольт


Это может помочь вам codingbin.com/compressing-a-directory-of-files-with-php
MKD

Ответы:


321

Код обновлен 22.04.2015.

Заархивируйте всю папку:

// Get real path for our folder
$rootPath = realpath('folder-to-zip');

// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);

// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootPath),
    RecursiveIteratorIterator::LEAVES_ONLY
);

foreach ($files as $name => $file)
{
    // Skip directories (they would be added automatically)
    if (!$file->isDir())
    {
        // Get real and relative path for current file
        $filePath = $file->getRealPath();
        $relativePath = substr($filePath, strlen($rootPath) + 1);

        // Add current file to archive
        $zip->addFile($filePath, $relativePath);
    }
}

// Zip archive will be created only after closing object
$zip->close();

Заархивировать всю папку + удалить все файлы, кроме "important.txt":

// Get real path for our folder
$rootPath = realpath('folder-to-zip');

// Initialize archive object
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);

// Initialize empty "delete list"
$filesToDelete = array();

// Create recursive directory iterator
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($rootPath),
    RecursiveIteratorIterator::LEAVES_ONLY
);

foreach ($files as $name => $file)
{
    // Skip directories (they would be added automatically)
    if (!$file->isDir())
    {
        // Get real and relative path for current file
        $filePath = $file->getRealPath();
        $relativePath = substr($filePath, strlen($rootPath) + 1);

        // Add current file to archive
        $zip->addFile($filePath, $relativePath);

        // Add current file to "delete list"
        // delete it later cause ZipArchive create archive only after calling close function and ZipArchive lock files until archive created)
        if ($file->getFilename() != 'important.txt')
        {
            $filesToDelete[] = $filePath;
        }
    }
}

// Zip archive will be created only after closing object
$zip->close();

// Delete all files from "delete list"
foreach ($filesToDelete as $file)
{
    unlink($file);
}

2
Вы должны установить chmod (доступный для записи) в каталоге (где находится этот скрипт) на 777. Например: если скрипт находится в /var/www/localhost/script.php, вам нужно установить chmod 0777 в dir / var / www / localhost /.
Dador 06

3
Удалить файлы перед вызовом $zip->close()не получится. Проверьте мой ответ здесь
hek2mgl 03

10
@alnassre это требование из вопроса: «Я также хочу удалить все содержимое папки, кроме important.txt». Также я советую вам всегда читать код перед его выполнением.
Dador

1
@alnassre хахахаха ... извините :) ... хахаха
Ондрей Рафадж

1
@ nick-newman, да, для подсчета процентов можно использовать php.net/manual/ru/function.iterator-count.php + counter внутри цикла. Что касается уровня сжатия - в данный момент это невозможно с ZipArchive: stackoverflow.com/questions/1833168/…
Dador

54

В классе ZipArchive есть полезный недокументированный метод: addGlob ();

$zipFile = "./testZip.zip";
$zipArchive = new ZipArchive();

if ($zipArchive->open($zipFile, (ZipArchive::CREATE | ZipArchive::OVERWRITE)) !== true)
    die("Failed to create archive\n");

$zipArchive->addGlob("./*.txt");
if ($zipArchive->status != ZIPARCHIVE::ER_OK)
    echo "Failed to write files to zip\n";

$zipArchive->close();

Документировано по адресу: www.php.net/manual/en/ziparchive.addglob.php


2
@netcoder - преимущества написания phpt для его тестирования ... в основном, прочитал исходный код для класса ZipArchive и нашел его там .... есть также недокументированный метод addPattern (), который принимает шаблон стиля регулярного выражения, но мне никогда не удавалось заставить это работать (может быть, ошибка в классе)
Марк Бейкер

1
@kread - вы можете использовать это с любым списком файлов, который можно извлечь с помощью glob (), поэтому я нашел его чрезвычайно полезным с тех пор, как обнаружил его.
Марк Бейкер

@MarkBaker Я знаю, что этот комментарий приходит через годы после того, как вы опубликовали, я просто пытаюсь удачи здесь. Я отправил вопрос здесь о проносясь , а также. Я собираюсь попробовать метод glob, который вы разместили здесь, но моя основная проблема заключается в том, что я не могу использовать addFromString и использую addFile, который просто молча терпит неудачу. Вы, возможно, знаете, что может пойти не так, или что я делаю не так?
Skytiger

@ user1032531 - последняя строка моего сообщения (отредактировано 13 декабря 2013 г.) указывает именно на это со ссылкой на страницу документации
Марк Бейкер

6
Является ли addGlobрекурсивная?
Винсент Порье

20

Попробуй это:

$zip = new ZipArchive;
$zip->open('myzip.zip', ZipArchive::CREATE);
foreach (glob("target_folder/*") as $file) {
    $zip->addFile($file);
    if ($file != 'target_folder/important.txt') unlink($file);
}
$zip->close();

Однако это не будет архивироваться рекурсивно.


Он действительно удаляет некоторые файлы My folder, но у меня также есть папка в папке, My folderкоторая дает мне ошибку: Разрешение отклонено, отключив папку с помощью inMy folder
woninana

@Stupefy: Попробуйте if (!is_dir($file) && $file != 'target_folder...')вместо этого. Или проверьте ответ @kread, если вы хотите рекурсивно архивировать, это самый эффективный способ.
netcoder 06

Папка внутри My folderвсе еще не удалена, но ошибок больше нет.
woninana 06

Я также забыл упомянуть, что у меня нет файлов .zip.
woninana 06

1
Удалить файлы перед вызовом $zip->close()не получится. Проверьте мой ответ здесь
hek2mgl 03

19

Я предполагаю, что это работает на сервере, где zip-приложение находится в пути поиска. Должно быть верно для всех серверов на базе UNIX и, я думаю, большинства серверов на базе Windows.

exec('zip -r archive.zip "My folder"');
unlink('My\ folder/index.html');
unlink('My\ folder/picture.jpg');

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


15

Я пробовал использовать приведенный ниже код, и он работает. Код не требует пояснений, дайте мне знать, если у вас возникнут вопросы.

<?php
class FlxZipArchive extends ZipArchive 
{
 public function addDir($location, $name) 
 {
       $this->addEmptyDir($name);
       $this->addDirDo($location, $name);
 } 
 private function addDirDo($location, $name) 
 {
    $name .= '/';
    $location .= '/';
    $dir = opendir ($location);
    while ($file = readdir($dir))
    {
        if ($file == '.' || $file == '..') continue;
        $do = (filetype( $location . $file) == 'dir') ? 'addDir' : 'addFile';
        $this->$do($location . $file, $name . $file);
    }
 } 
}
?>

<?php
$the_folder = '/path/to/folder/to/be/zipped';
$zip_file_name = '/path/to/zip/archive.zip';
$za = new FlxZipArchive;
$res = $za->open($zip_file_name, ZipArchive::CREATE);
if($res === TRUE) 
{
    $za->addDir($the_folder, basename($the_folder));
    $za->close();
}
else{
echo 'Could not create a zip archive';
}
?>

Отличное решение. Он также работает в laravel 5.5. очень понравилось. (y)
Web Artisan

1
Отличный код! Чисто, просто и отлично работает! ;) Мне кажется, лучший ответ. Если это может кому-то помочь: я просто добавил ini_set('memory_limit', '512M');перед выполнением скрипта и ini_restore('memory_limit');в конце. Необходимо было избегать нехватки памяти в случае тяжелых папок (это была папка больше 500 МБ).
Jacopo Pace

1
В моей среде (PHP 7.3, Debian) был создан ZIP-архив без списка каталогов (большой пустой файл). Мне пришлось изменить следующую строку: $ name. = '/'; в $ name = ($ name == '.'? '': $ name. '/');
Gerfried

Это работает для меня. Спасибо, что поделился. Ура!
Сатиска

8

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

addzip ("path/folder/" , "/path2/folder.zip" );

функция:

// compress all files in the source directory to destination directory 
    function create_zip($files = array(), $dest = '', $overwrite = false) {
    if (file_exists($dest) && !$overwrite) {
        return false;
    }
    if (($files)) {
        $zip = new ZipArchive();
        if ($zip->open($dest, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
            return false;
        }
        foreach ($files as $file) {
            $zip->addFile($file, $file);
        }
        $zip->close();
        return file_exists($dest);
    } else {
        return false;
    }
}

function addzip($source, $destination) {
    $files_to_zip = glob($source . '/*');
    create_zip($files_to_zip, $destination);
    echo "done";
}

Как автоматически включить подпапки в резервную копию с помощью этого скрипта? @Alireza
floCoder

2

Почему бы не попробовать EFS PhP-ZiP MultiVolume Script ... Я заархивировал и передал сотни гигов и миллионы файлов ... ssh необходим для эффективного создания архивов.

Но я верю, что полученные файлы можно использовать с exec прямо из php:

exec('zip -r backup-2013-03-30_0 . -i@backup-2013-03-30_0.txt');

Не знаю, работает ли. Я не пробовал ...

«Секрет» в том, что время выполнения для архивирования не должно превышать время, отведенное для выполнения PHP-кода.


1

Это рабочий пример создания ZIP-архивов на PHP:

$zip = new ZipArchive();
$zip_name = time().".zip"; // Zip name
$zip->open($zip_name,  ZipArchive::CREATE);
foreach ($files as $file) {
  echo $path = "uploadpdf/".$file;
  if(file_exists($path)){
  $zip->addFromString(basename($path),  file_get_contents($path));---This is main function  
  }
  else{
   echo"file does not exist";
  }
}
$zip->close();

1

Я нашел этот пост в Google как второй лучший результат, сначала использовал exec :(

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

ОСОБЕННОСТИ СКРИПТА

  • Именование файлов резервных копий по дням, PREFIX-YYYY-MM-DD-POSTFIX.EXTENSION
  • Отчет о файле / отсутствует
  • Список предыдущих резервных копий
  • Не архивирует / не включает предыдущие резервные копии;)
  • Работает на windows / linux

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

Кроме того, это может выглядеть беспорядочно, и некоторые вещи можно легко очистить ... Так что не комментируйте это, это просто быстрый сценарий с добавленными базовыми комментариями .. НЕ ДЛЯ ЖИВОГО ИСПОЛЬЗОВАНИЯ .. Но легко очистить для живого использования !

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

<?php
    // DIRECTORY WE WANT TO BACKUP
    $pathBase = '../';  // Relate Path

    // ZIP FILE NAMING ... This currently is equal to = sitename_www_YYYY_MM_DD_backup.zip 
    $zipPREFIX = "sitename_www";
    $zipDATING = '_' . date('Y_m_d') . '_';
    $zipPOSTFIX = "backup";
    $zipEXTENSION = ".zip";

    // SHOW PHP ERRORS... REMOVE/CHANGE FOR LIVE USE
    ini_set('display_errors',1);
    ini_set('display_startup_errors',1);
    error_reporting(-1);




// ############################################################################################################################
//                                  NO CHANGES NEEDED FROM THIS POINT
// ############################################################################################################################

    // SOME BASE VARIABLES WE MIGHT NEED
    $iBaseLen = strlen($pathBase);
    $iPreLen = strlen($zipPREFIX);
    $iPostLen = strlen($zipPOSTFIX);
    $sFileZip = $pathBase . $zipPREFIX . $zipDATING . $zipPOSTFIX . $zipEXTENSION;
    $oFiles = array();
    $oFiles_Error = array();
    $oFiles_Previous = array();

    // SIMPLE HEADER ;)
    echo '<center><h2>PHP Example: ZipArchive - Mayhem</h2></center>';

    // CHECK IF BACKUP ALREADY DONE
    if (file_exists($sFileZip)) {
        // IF BACKUP EXISTS... SHOW MESSAGE AND THATS IT
        echo "<h3 style='margin-bottom:0px;'>Backup Already Exists</h3><div style='width:800px; border:1px solid #000;'>";
            echo '<b>File Name: </b>',$sFileZip,'<br />';
            echo '<b>File Size: </b>',$sFileZip,'<br />';
        echo "</div>";
        exit; // No point loading our function below ;)
    } else {

        // NO BACKUP FOR TODAY.. SO START IT AND SHOW SCRIPT SETTINGS
        echo "<h3 style='margin-bottom:0px;'>Script Settings</h3><div style='width:800px; border:1px solid #000;'>";
            echo '<b>Backup Directory: </b>',$pathBase,'<br /> ';
            echo '<b>Backup Save File: </b>',$sFileZip,'<br />';
        echo "</div>";

        // CREATE ZIPPER AND LOOP DIRECTORY FOR SUB STUFF
        $oZip = new ZipArchive;
        $oZip->open($sFileZip,  ZipArchive::CREATE | ZipArchive::OVERWRITE);
        $oFilesWrk = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pathBase),RecursiveIteratorIterator::LEAVES_ONLY);
        foreach ($oFilesWrk as $oKey => $eFileWrk) {
            // VARIOUS NAMING FORMATS OF THE CURRENT FILE / DIRECTORY.. RELATE & ABSOLUTE
            $sFilePath = substr($eFileWrk->getPathname(),$iBaseLen, strlen($eFileWrk->getPathname())- $iBaseLen);
            $sFileReal = $eFileWrk->getRealPath();
            $sFile = $eFileWrk->getBasename();

            // WINDOWS CORRECT SLASHES
            $sMyFP = str_replace('\\', '/', $sFileReal);

            if (file_exists($sMyFP)) {  // CHECK IF THE FILE WE ARE LOOPING EXISTS
                if ($sFile!="."  && $sFile!="..") { // MAKE SURE NOT DIRECTORY / . || ..
                    // CHECK IF FILE HAS BACKUP NAME PREFIX/POSTFIX... If So, Dont Add It,, List It
                    if (substr($sFile,0, $iPreLen)!=$zipPREFIX && substr($sFile,-1, $iPostLen + 4)!= $zipPOSTFIX.$zipEXTENSION) {
                        $oFiles[] = $sMyFP;                     // LIST FILE AS DONE
                        $oZip->addFile($sMyFP, $sFilePath);     // APPEND TO THE ZIP FILE
                    } else {
                        $oFiles_Previous[] = $sMyFP;            // LIST PREVIOUS BACKUP
                    }
                }
            } else {
                $oFiles_Error[] = $sMyFP;                       // LIST FILE THAT DOES NOT EXIST
            }
        }
        $sZipStatus = $oZip->getStatusString();                 // GET ZIP STATUS
        $oZip->close(); // WARNING: Close Required to append files, dont delete any files before this.

        // SHOW BACKUP STATUS / FILE INFO
        echo "<h3 style='margin-bottom:0px;'>Backup Stats</h3><div style='width:800px; height:120px; border:1px solid #000;'>";
            echo "<b>Zipper Status: </b>" . $sZipStatus . "<br />";
            echo "<b>Finished Zip Script: </b>",$sFileZip,"<br />";
            echo "<b>Zip Size: </b>",human_filesize($sFileZip),"<br />";
        echo "</div>";


        // SHOW ANY PREVIOUS BACKUP FILES
        echo "<h3 style='margin-bottom:0px;'>Previous Backups Count(" . count($oFiles_Previous) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
        foreach ($oFiles_Previous as $eFile) {
            echo basename($eFile) . ", Size: " . human_filesize($eFile) . "<br />";
        }
        echo "</div>";

        // SHOW ANY FILES THAT DID NOT EXIST??
        if (count($oFiles_Error)>0) {
            echo "<h3 style='margin-bottom:0px;'>Error Files, Count(" . count($oFiles_Error) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
            foreach ($oFiles_Error as $eFile) {
                echo $eFile . "<br />";
            }
            echo "</div>";
        }

        // SHOW ANY FILES THAT HAVE BEEN ADDED TO THE ZIP
        echo "<h3 style='margin-bottom:0px;'>Added Files, Count(" . count($oFiles) . ")</h3><div style='overflow:auto; width:800px; height:120px; border:1px solid #000;'>";
        foreach ($oFiles as $eFile) {
            echo $eFile . "<br />";
        }
        echo "</div>";

    }


    // CONVERT FILENAME INTO A FILESIZE AS Bytes/Kilobytes/Megabytes,Giga,Tera,Peta
    function human_filesize($sFile, $decimals = 2) {
        $bytes = filesize($sFile);
        $sz = 'BKMGTP';
        $factor = floor((strlen($bytes) - 1) / 3);
        return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor];
    }
?>

ЧТО ЭТО ДЕЛАЕТ??

Он просто заархивирует все содержимое переменной $ pathBase и сохранит zip в той же папке. Он просто обнаруживает предыдущие резервные копии и пропускает их.

CRON BACKUP

Этот сценарий, который я только что протестировал на Linux, отлично работал с заданием cron с использованием абсолютного URL-адреса для pathBase.


Я также исключил сценарий удаления, вы можете увидеть принятый ответ на этот вопрос
Angry 84

Я должен любить эти случайные голоса против без объяснения причин.
Angry 84

1

Используйте эту функцию:

function zip($source, $destination)
{
    if (!extension_loaded('zip') || !file_exists($source)) {
        return false;
    }

    $zip = new ZipArchive();
    if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
        return false;
    }

    $source = str_replace('\\', '/', realpath($source));

    if (is_dir($source) === true) {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);

        foreach ($files as $file) {
            $file = str_replace('\\', '/', $file);

            // Ignore "." and ".." folders
            if (in_array(substr($file, strrpos($file, '/')+1), array('.', '..'))) {
                continue;
            }               

            $file = realpath($file);

            if (is_dir($file) === true) {
                $zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
            } elseif (is_file($file) === true) {
                $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
            }
        }
    } elseif (is_file($source) === true) {
        $zip->addFromString(basename($source), file_get_contents($source));
    }

    return $zip->close();
}

Пример использования:

zip('/folder/to/compress/', './compressed.zip');

1

Используйте это нормально.

$dir = '/Folder/';
$zip = new ZipArchive();
$res = $zip->open(trim($dir, "/") . '.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
if ($res === TRUE) {
    foreach (glob($dir . '*') as $file) {
        $zip->addFile($file, basename($file));
    }
    $zip->close();
} else {
    echo 'Failed to create to zip. Error: ' . $res;
}

1

Создайте zip-папку в PHP.

Метод создания почтового индекса

   public function zip_creation($source, $destination){
    $dir = opendir($source);
    $result = ($dir === false ? false : true);

    if ($result !== false) {

        
        $rootPath = realpath($source);
         
        // Initialize archive object
        $zip = new ZipArchive();
        $zipfilename = $destination.".zip";
        $zip->open($zipfilename, ZipArchive::CREATE | ZipArchive::OVERWRITE );
         
        // Create recursive directory iterator
        /** @var SplFileInfo[] $files */
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
         
        foreach ($files as $name => $file)
        {
            // Skip directories (they would be added automatically)
            if (!$file->isDir())
            {
                // Get real and relative path for current file
                $filePath = $file->getRealPath();
                $relativePath = substr($filePath, strlen($rootPath) + 1);
         
                // Add current file to archive
                $zip->addFile($filePath, $relativePath);
            }
        }
         
        // Zip archive will be created only after closing object
        $zip->close();
        
        return TRUE;
    } else {
        return FALSE;
    }


}

Вызов метода zip

$source = $source_directory;
$destination = $destination_directory;
$zipcreation = $this->zip_creation($source, $destination);

0

Я немного улучшил сценарий.

  <?php
    $directory = "./";
    //create zip object
    $zip = new ZipArchive();
    $zip_name = time().".zip";
    $zip->open($zip_name,  ZipArchive::CREATE);
    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($directory),
        RecursiveIteratorIterator::LEAVES_ONLY
    );
    foreach ($files as $file) {
        $path = $file->getRealPath();
        //check file permission
        if(fileperms($path)!="16895"){
            $zip->addFromString(basename($path),  file_get_contents($path)) ;
            echo "<span style='color:green;'>{$path} is added to zip file.<br /></span> " ;
        }
        else{
            echo"<span style='color:red;'>{$path} location could not be added to zip<br /></span>";
        }
    }
    $zip->close();
    ?>

Это заархивирует файлы, но список каталогов исчез, у него больше нет каталога,
Суджай Сридхар

0

Это решит вашу проблему. Пожалуйста, попробуйте.

$zip = new ZipArchive;
$zip->open('testPDFZip.zip', ZipArchive::CREATE);
foreach (glob(APPLICATION_PATH."pages/recruitment/uploads/test_pdf_folder/*") as $file) {
    $new_filename = end(explode("/",$file));
    $zip->addFile($file,"emp/".$new_filename);
}           
$zip->close();

0

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.