177

I have found here at stackoveflow some code on how to ZIP a specific file, but how about a specific folder?

Folder/
  index.html
  picture.jpg
  important.txt

inside in My Folder, there are files. after zipping the My Folder, i also want to delete the whole content of the folder except important.txt.

Found this here at stack

starball
  • 20,030
  • 7
  • 43
  • 238
woninana
  • 3,409
  • 9
  • 42
  • 66
  • As far as I can see, the stackoverflow link you have provided actually does zip multiple files. Which part do you have trouble with? – Lasse Espeholt Feb 06 '11 at 17:04
  • @lasseespeholt The link i have given you zips only a specific file, not the folder and the content of the folder.. – woninana Feb 06 '11 at 17:05
  • He takes an array of files (essentially a folder) and adds all the files to the zip file (the loop). I can see a fine answer have been posted now +1 :) which is the same code, the array is just a list of files from a directory now. – Lasse Espeholt Feb 06 '11 at 17:07
  • possible duplicate of [compress/archive folder using php script](http://stackoverflow.com/questions/3828385/compress-archive-folder-using-php-script) – Pekka Apr 30 '11 at 14:25
  • This can help you http://codingbin.com/compressing-a-directory-of-files-with-php/ – Manoj Dhiman Sep 21 '17 at 20:08

20 Answers20

419

Code updated 2015/04/22.

Zip a whole folder:

// 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();

Zip a whole folder + delete all files except "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);
}
Dador
  • 5,277
  • 1
  • 19
  • 23
  • This is almost correct. Adding the file to the may silently fail due to reaching a file descriptor limit. the php.net page for ZipArchive has some workarounds, however. – Jonathan Fingland Feb 06 '11 at 17:18
  • It deletes the some file on `My folder`, I can't find the created .zip folder and there some folders to inside `My folder` that can't be deleted. – woninana Feb 06 '11 at 17:42
  • 2
    You must set chmod (writable) on dir (where located this script) to 777. For example: If script located in /var/www/localhost/script.php, then you need set chmod 0777 on dir /var/www/localhost/. – Dador Feb 06 '11 at 18:50
  • 3
    Deleting the files before calling `$zip->close()` will not work. Check my answer [here](http://stackoverflow.com/a/21528186/171318) – hek2mgl Feb 03 '14 at 13:45
  • @hek2mgl thank you for noticing. I rewrote code in the answer. – Dador Feb 03 '14 at 17:37
  • @david-n thanks for edit suggestion. Don't know why people rejected it but it was useful. – Dador Mar 15 '14 at 11:07
  • before adding the files to zip it is good to check if it is not a directory ising `is_dir()` function. – Zeusarm Sep 10 '14 at 12:42
  • Please give me a reply. zip file is created successfully but when i will try to extract it then it is showing error. So please suggest me changes in the code. – Lakhan Nov 06 '14 at 09:20
  • 11
    @alnassre that's requirement from the question: "i also want to delete the whole content of the folder except important.txt". Also I advice you to always read code before execute it. – Dador Apr 21 '15 at 23:12
  • 1
    @alnassre hahahaha ... sorry :) ... hahaha – Ondrej Rafaj May 25 '15 at 19:54
  • Great script. Just a question though, anyway to get the percent of completion? Also, possible to modify compression levels? – NiCk Newman Nov 15 '15 at 23:02
  • 1
    @nick-newman, yeah, to calculate percent you can use http://php.net/manual/ru/function.iterator-count.php + counter inside loop. Regarding compression level - it's not possible with ZipArchive at this moment: http://stackoverflow.com/questions/1833168/can-i-change-the-compression-level-of-ziparchive – Dador Dec 20 '15 at 12:07
  • How do you force download using the "download" attribute after the ZIP is created? – Anake.me Mar 19 '16 at 02:55
  • As of 2017: The first part of this answer is failing (I didn't tryed the second one). I got a `ZipArchive::close(): It is not safe to rely on the system's timezone settings....` and a `Fatal error: Maximum execution time of 30 seconds exceeded`. Just to let you know. – Louys Patrice Bessette May 11 '17 at 21:40
  • @louys-patrice-bessette both problems is not about code in the answer being wrong, but about your settings. You should select timezone (either in php.ini or in your config), see that answer http://stackoverflow.com/a/36371689/596207 And the second problem happens because you have time limit for script execution, see that answer http://stackoverflow.com/a/15904047/596207 – Dador May 15 '17 at 16:01
  • @Dador when i download this it downloads zip to the projects public folder.i wants it at the download folder of pc.how can i do this – colombo Jan 24 '18 at 11:25
  • @colombo, this code only creates the zip archive. If you want to send it to user (so it will be downloaded in browser) you need either redirect user to created archive (i.e. to /file.zip, see https://stackoverflow.com/a/768472/596207 for example) or send it directly to user (see https://stackoverflow.com/a/7470956/596207 for example). – Dador Jan 25 '18 at 11:23
  • 1
    If you are testing on MacOS and using a temp file, then `getRealPath` will return `/private/var` while `getPathname` returns `/var`, the `substr` would give unexpected results. – zed Jan 28 '19 at 19:30
  • Hello, its 2019 but your answer is still watched. How about delete from the created zip one folder (and its contents, off course)? I mean, I need to backup everything on my folder except a specific one. I'm trying with if ($file -> isDir()) { $filesToDelete[] = $file -> getFilename(); } but all I've got is . and .., (hiden files within the folder I want to skip) Thanks! – Pluda Apr 06 '19 at 14:12
  • @Pluda, try using RecursiveIteratorIterator::CHILD_FIRST instead of RecursiveIteratorIterator::LEAVES_ONLY (see docs here https://www.php.net/manual/en/recursiveiteratoriterator.construct.php). Also, in order to delete the directory you have to delete it's content first. So besides adding directory itself to $filesToDelete it's also necessary to add all files in that directory to $filesToDelete. – Dador Apr 06 '19 at 18:10
  • @Dador Thanks! I'm trying to avoid adding the folder to the zip, but I'm not getting there. Something like if isDir and dirName is "myFolder" skip iteration in myFolder and continue with the rest... Maybe I'm complicating things... – Pluda Apr 06 '19 at 18:20
  • 1
    @Pluda, ah, sorry, seems like I misunderstood you at first. Then you need to check if $relativePath starts with $dirToExclude, like this: `if (substr($relativePath, 0, strlen($dirToExclude)) == $dirToExclude) { continue; }` (note that it could give wrong results in case of symlinks) – Dador Apr 07 '19 at 22:43
  • @Dador, thanks! I was able to delete the folder after $zip -> close, but for me that doesn't make logic. Why add something and 1 millisecond after remove it? Now with your help it is possible to suppress the folder before closing the zip. Haven't noticed wrong results so far. Thanks a ton! – Pluda Apr 09 '19 at 10:36
  • I could not use this approach to add the files under a Junction in Windows (symlink), it stops iterating inside the junction if it is outside the initial $rootPath, however it shows me the target directory, and then I can start a new RecursiveDirectoryIterator from that, but I cannot know which was the junction/symlink to put under such directory structure. If ./imasymlink points to /other/thing, I get /other/thing, but I don't get iamsymlink to put /other/thing/* under /imasymlink/ The only solution I see, use the oldest filesystem functions. Does anyone know another approach? – Jose Nobile Sep 12 '22 at 03:30
  • How to exlcude specific subfolders from zip? I have a name of that subfolders, how to exclude that? – Met El Idrissi Jun 23 '23 at 12:35
67

There is a useful undocumented method in the ZipArchive class: 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();

Now documented at: www.php.net/manual/en/ziparchive.addglob.php

John Rix
  • 6,271
  • 5
  • 40
  • 46
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • 2
    @netcoder - the benefits of having written the phpt for testing it... basically, read through the source for the ZipArchive class, and found it there.... there's also an undocumented addPattern() method that takes a regexp style pattern, but I've never managed to get that working (may be a bug in the class) – Mark Baker Feb 06 '11 at 17:32
  • 1
    @kread - you can use this with any file list that can be extracted using glob(), so I've found it extremely useful since I discovered it. – Mark Baker Feb 06 '11 at 19:16
  • @MarkBaker I know this comment is coming through years after you posted, I'm just trying my luck here. I've posted a question [here](http://stackoverflow.com/questions/29102612/zipping-the-contents-of-a-folders-in-php) about zipping as well. I'm about to try the glob method you posted here, but my main issue is that I can't use addFromString, and have been using addFile, which is just failing silently. Do you perhaps have any idea what might be going wrong, or what I might be doing wrong? – Skytiger Mar 18 '15 at 07:14
  • @user1032531 - the last line of my post (edited 13th December 2013) indicates just that, with a link to the docs page – Mark Baker Aug 20 '15 at 15:58
  • Hmm, zipping seemed to work very well, though when I download the zip archive I had to try several decompression utilities before one would work--and the resulting unzipped folder was invisible. This is on OS X 10.9.5. Anybody else find this issue? – cbmtrx Dec 08 '15 at 20:43
  • 8
    Is `addGlob` recursive? – Vincent Poirier Jan 28 '16 at 16:50
  • @Vincent Poirier Yes – Robert Dundon Jul 28 '16 at 18:39
  • @RobertDundon I can't have addGlob recursive... Can you provide an example ? – Sam Jason Braddock Aug 26 '16 at 14:45
  • 1
    ZipArchive::open() returns a non-zero integer on failure, so checking `if (!$zipArchive->open($zipFile, ZIPARCHIVE::OVERWRITE))` is invalid and just killed an hour of my time trying to debug! Have edited the answer accordingly. – John Rix Feb 28 '20 at 10:24
  • 2
    Also, using just `ZipArchive::OVERWRITE` will fail if the named file is not present, so use `(ZipArchive::CREATE | ZipArchive::OVERWRITE)` instead (assuming you want to create or overwrite as applicable). – John Rix Feb 28 '20 at 10:31
27

I assume this is running on a server where the zip application is in the search path. Should be true for all unix-based and I guess most windows-based servers.

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

The archive will reside in archive.zip afterwards. Keep in mind that blanks in file or folder names are a common cause of errors and should be avoided where possible.

Kevin Read
  • 2,173
  • 16
  • 23
22

Try this:

$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();

This will not zip recursively though.

netcoder
  • 66,435
  • 19
  • 125
  • 142
  • It sure does delete some files in `My folder`, but i have also a folder within a folder `My folder` which gives me an error of: Permission denied by unlinking the folder with in `My folder` – woninana Feb 06 '11 at 17:13
  • @Stupefy: Try `if (!is_dir($file) && $file != 'target_folder...')` instead. Or check [@kread answer](http://stackoverflow.com/questions/4914750/how-to-zip-a-whole-folder-using-php/4914785#4914785) if you want to zip recursively, it's the most efficient way. – netcoder Feb 06 '11 at 17:21
  • The folder within the `My folder` is still not deleted, but there are no more errors anyway. – woninana Feb 06 '11 at 17:33
  • I also forgot to mention that i there are no .zip files created. – woninana Feb 06 '11 at 17:36
  • @Stepefy101: You never specified that you had or wanted subfolders to be deleted/zipped. If your path has a slash in it (e.g.: `My Folder`), you need to escape the space: `My\ Folder` when using `glob`, etc. I clearly stated that this method does not work recursively. – netcoder Feb 06 '11 at 17:49
  • 1
    Deleting the files before calling `$zip->close()` will not work. Check my answer [here](http://stackoverflow.com/a/21528186/171318) – hek2mgl Feb 03 '14 at 13:48
  • Please replace this $zip->addFile($file); with :: $new_filename=end(explode("/",$file)); $zip->addFile($file,"emp/".$new_filename); This will customize your zip folder according to your own way. – Lakhan Nov 06 '14 at 11:52
19

I tried with the code below and it is working. The code is self explanatory, please let me know if you have any questions.

<?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';
}
?>
Amir Md Amiruzzaman
  • 1,911
  • 25
  • 24
  • Excellent solution. It works in laravel 5.5 too. really liked that. (y) – Web Artisan Nov 29 '17 at 06:46
  • 1
    Great code! Clean, simple and perfectly working! ;) It seems for me the best reply. If it can help someone: I just added `ini_set('memory_limit', '512M');` before the execution of the script and `ini_restore('memory_limit');` at the end. It was necessary to avoid lack of memory in case of heavy folders (it was a folder bigger than 500MB). – Jacopo Pace Dec 01 '17 at 16:38
  • 1
    In my environment (PHP 7.3, Debian) a ZIP archive without a directory listing was created (big, empty file). I had to change the following line: $name .= '/'; into $name = ($name == '.' ? '' : $name .'/'); – ESP32 Aug 13 '19 at 09:17
  • This is working for me. Thanks for sharing. Cheers! – Sathiska Jan 03 '20 at 11:00
10

This is a function that zips a whole folder and its contents in to a zip file and you can use it simple like this :

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

function :

// 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 Fallah
  • 4,609
  • 3
  • 31
  • 57
7

Use this function:

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();
}

Example use:

zip('/folder/to/compress/', './compressed.zip');
Waqar Alamgir
  • 9,828
  • 4
  • 30
  • 36
4

Why not Try EFS PhP-ZiP MultiVolume Script ... I zipped and transferred hundreds of gigs and millions of files ... ssh is needed to effectively create archives.

But i belive that resulting files can be used with exec directly from php:

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

I do not know if it works. I have not tried ...

"the secret" is that the execution time for archiving should not exceed the time allowed for execution of PHP code.

ByREV
  • 41
  • 2
3

If you have subfolders and you want to preserve the structure of the folder do this:

$zip = new \ZipArchive();
$fileName = "my-package.zip";
if ($zip->open(public_path($fileName), \ZipArchive::CREATE) === true)
{
    $files = \Illuminate\Support\Facades\File::allFiles(
        public_path('/MY_FOLDER_PATH/')
    );

    foreach ($files as $file) {
        $zip->addFile($file->getPathname(), $file->getRelativePathname());
    }

    $zip->close();
    return response()
        ->download(public_path($fileName))
        ->deleteFileAfterSend(true);
}

deleteFileAfterSend(true) to delete the file my-package.zip from the server.

Don't forget to change /MY_FOLDER_PATH/ with the path of your folder that you want to download.

Hatim Lagzar
  • 52
  • 1
  • 8
2

This is a working example of making ZIPs in 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();
Ren
  • 1,111
  • 5
  • 15
  • 24
Sun Love
  • 744
  • 5
  • 9
2

Create a zip folder in PHP.

Zip create method

   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;
    }


}

Call the zip method

$source = $source_directory;
$destination = $destination_directory;
$zipcreation = $this->zip_creation($source, $destination);
Community
  • 1
  • 1
Mamun Sabuj
  • 189
  • 1
  • 2
  • 6
1

This will resolve your issue. Please try it.

$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();
Narek
  • 3,813
  • 4
  • 42
  • 58
Lakhan
  • 12,328
  • 3
  • 19
  • 28
1

I found this post in google as the second top result, first was using exec :(

Anyway, while this did not suite my needs exactly.. I decided to post an answer for others with my quick but extended version of this.

SCRIPT FEATURES

  • Backup file naming day by day, PREFIX-YYYY-MM-DD-POSTFIX.EXTENSION
  • File Reporting / Missing
  • Previous Backups Listing
  • Does not zip / include previous backups ;)
  • Works on windows/linux

Anyway, onto the script.. While it may look like a lot.. Remember there is excess in here.. So feel free to delete the reporting sections as needed...

Also it may look messy as well and certain things could be cleaned up easily... So dont comment about it, its just a quick script with basic comments thrown in.. NOT FOR LIVE USE.. But easy to clean up for live use!

In this example, it is run from a directory that is inside of the root www / public_html folder.. So only needs to travel up one folder to get to the root.

<?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];
    }
?>

WHAT DOES IT DO??

It will simply zip the complete contents of the variable $pathBase and store the zip in that same folder. It does a simple detection for previous backups and skips them.

CRON BACKUP

This script i've just tested on linux and worked fine from a cron job with using an absolute url for the pathBase.

Angry 84
  • 2,935
  • 1
  • 25
  • 24
1

Use this is working fine.

$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;
}
Christian Giupponi
  • 7,408
  • 11
  • 68
  • 113
Indrajeet Singh
  • 2,958
  • 25
  • 25
0

I did some small improvement in the script.

  <?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();
    ?>
Poohspear
  • 29
  • 3
0

For anyone reading this post and looking for a why to zip the files using addFile instead of addFromString, that does not zip the files with their absolute path (just zips the files and nothing else), see my question and answer here

Community
  • 1
  • 1
Skytiger
  • 1,745
  • 4
  • 26
  • 53
0

includes all sub-folders:

zip_folder('path/to/input/folder',    'path/to/output_zip_file.zip') ;

Here is source-code (there might have been an update, but below I put the copy of that code):

function zip_folder ($input_folder, $output_zip_file) {
    $zipClass = new ZipArchive();
    if($input_folder !== false && $output_zip_file !== false)
    {
        $res = $zipClass->open($output_zip_file, \ZipArchive::CREATE);
        if($res === TRUE)   {
            // Add a Dir with Files and Subdirs to the archive
            $foldername = basename($input_folder);
            $zipClass->addEmptyDir($foldername);
            $foldername .= '/';         $input_folder .= '/';
            // Read all Files in Dir
            $dir = opendir ($input_folder);
            while ($file = readdir($dir))    {
                if ($file == '.' || $file == '..') continue;
                // Rekursiv, If dir: GoodZipArchive::addDir(), else ::File();
                $do = (filetype( $input_folder . $file) == 'dir') ? 'addDir' : 'addFile';
                $zipClass->$do($input_folder . $file, $foldername . $file);
            }
            $zipClass->close(); 
        }
        else   { exit ('Could not create a zip archive, migth be write permissions or other reason. Contact admin.'); }
    }
}
T.Todua
  • 53,146
  • 19
  • 236
  • 237
0

If you are sure you are doing everything correctly and it is still not working. Check your PHP (user) permissions.

Ken
  • 21
  • 2
  • This looks like a comment – User123456 Jun 22 '22 at 08:02
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/32073818) – IT goldman Jun 25 '22 at 22:58
0

My 2 cents :

class compressor {
    
        /**
         * public static $NOT_COMPRESS
         * use: compressor::$NOT_COMPRESS
         * no compress thoses files for upload
         */
        public static $NOT_COMPRESS = array(
    
                'error_log',
                'cgi-bin',
                'whatever/whatever'
        );
        /**
         * end public static $NOT_COMPRESS
         */
    
    
        /**
         * public function compress_folder( $dir, $version, $archive_dest );
         * @param  {string}  $dir | absolute path to the directory
         * @param  {string}  $version_number | ex: 0.1.1
         * @param  {string}  $archive_dest | absolute path to the future compressed file
         * @return {void}    DO A COMPRESSION OF A FOLDER
         */
        public function compress_folder(  $dir, $version, $archive_dest  ){

    
                // name of FUTURE .zip file
                $archive_name = $version_number.'.zip';
    
                // test dir exits
                if( !is_dir($dir) ){ exit('No temp directory ...'); }
    
                // Iterate and archive API DIRECTORIES AND FOLDERS
    
                // create zip archive + manager
                $zip = new ZipArchive;
                $zip->open( $archive_dest,
                        ZipArchive::CREATE | ZipArchive::OVERWRITE );
    
                // iterator / SKIP_DOTS -> ignore '..' and '.'
                $it = new RecursiveIteratorIterator(
                       new RecursiveDirectoryIterator( $dir,
                       RecursiveDirectoryIterator::SKIP_DOTS )
                      );
    
                
                // loop iterator
                foreach( $it as $file ){
    
    
                        // check files not to add for compress 
    
                                // loop list for not add to upload .zip
                                foreach( compressor::$NOT_COMPRESS as $k => $v) {
    
                                        if( preg_match( '/^('.preg_quote($v,'/').')/', $it->getSubPathName() ) == true ){
    
    
                                                // break this loop and parent loop
                                                continue 2;
                                        }
                                }
                                // end loop list
    
                        // for Test
                        // echo $it->getSubPathName()."\r\n";
    
                        // no need to check if is a DIRECTORY with $it->getSubPathName()
                        // DIRECTORIES are added automatically
                        $zip->addFile( $it->getPathname(),  $it->getSubPathName() );
    
                }
                // end  loop
    
                $zip->close();
                // END Iterate and archive API DIRECTORIES AND FOLDERS
    
        }
        /**
         * public function compress_folder( $version_number );
         */

}
// end class compressor 

use :

// future name of the archive
$version = '0.0.1';

// path of directory to compress
$dir = $_SERVER['DOCUMENT_ROOT'].'/SOURCES';

// real path to FUTURE ARCHIVE
$archive_dest = $_SERVER['DOCUMENT_ROOT'].'/COMPRESSED/'.$version.'.zip';


$Compress = new compressor();
$Compress->compress_folder( $dir, $version, $archive_dest );

// this create a .zip file like : 
$_SERVER['DOCUMENT_ROOT'].'/COMPRESSED/0.0.1.zip
0

This is the best solution for me which is working fine in my Codecanyon project and well tested.

function zipper($space_slug)
{
// Get real path for our folder
$rootPath = realpath('files/' . $space_slug);

// Initialize archive object
$zip = new ZipArchive();
/* Opening the zip file and creating it if it doesn't exist. */
$zip->open('files/' . $space_slug . '.zip', ZipArchive::CREATE | 
ZipArchive::OVERWRITE);

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

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();
}
Pri Nce
  • 576
  • 6
  • 18