how to zip *all* folders and files that are children of the parent folder

I need to be able to have a script that automatically zips *all* the folders and files in the parent folder, rather than me entering an array of child folders and files each time as I now have in the script. So the zip would contain /abc123 and on down.
Is there a smart way to do this?

Here are the folder structure and files to be zipped - from abc123 through test_folder_3:
These files are all 1 line text files ..
/zippo                      (This is the parent folder that the zip file will placed in - the zip is called test.zip)
    /abc123                  (contains 1 file: folder_1_file_1.txt)
        /test_folder_2       (contains 1 file: folder_2_file_1.txt)
        /test_folder_3       (contains 3 files: folder_3_file_1.txt, folder_3_file_2.txt, folder_3_file_3.txt)

Open in new window


And the script, so far:
function create_zip($files = array(),$destination = '',$overwrite = false)
{
	//if the zip file already exists and overwrite is false, return false
	if(file_exists($destination) && !$overwrite)
    {
        return false;
    }
	//vars
	$valid_files = array();
	//if files were passed in...
	if(is_array($files))
    {
		//cycle through each file
		foreach($files as $file)
        {
			//make sure the file exists
			if(file_exists($file))
            {
				$valid_files[] = $file;
			}
		}
	}
	//if we have good files...
	if(count($valid_files))
    {
		//create the archive
		$zip = new ZipArchive();
		if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true)
        {
			return false;
		}
		//add the files
		foreach($valid_files as $file)
        {
			$zip->addFile($file,$file);
		}
		//debug

		//close the zip
		$zip->close();

		//check to make sure the file exists
		return file_exists($destination);
	}
	else
	{
		return false;
	}
}

$directory = '../../library/zippo/';     // Enter the directory where the files to be zipped are

$files_to_zip = array(                                   // Enter the individual files for the zip file
	$directory.'abc123/folder_1_file_1.txt',
	$directory.'abc123/test_folder_2/folder_1_file_1.txt',
	$directory.'abc123/test_folder_3/folder_1_file_1.txt',
	$directory.'abc123/test_folder_3/folder_1_file_2.txt',
	$directory.'abc123/test_folder_3/folder_1_file_3.txt'
);
//if true, good; if false, zip creation failed
$result = create_zip($files_to_zip,'../../library/zippo/test.zip');    // Enter the zip file name to be created
?>

Open in new window

Torquil BeavisBusinessAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Julian HansenCommented:
Here are some links from PHP.Net that show a way to do this

http://www.php.net/manual/en/ziparchive.addfile.php#93090
http://www.php.net/manual/en/ziparchive.addfile.php#112044

Have a look at those and if you are still stuck post back.
Ray PaseurCommented:
This is an exceptionally poorly documented extension of PHP, and the user-contributed notes just scratch the surface of the quirky behaviors.  Here are a couple of notes that you'll want to be aware of as you try to debug your script.
http://php.net/manual/en/ziparchive.addfile.php#96382
http://php.net/manual/en/ziparchive.addfile.php#114769
http://php.net/manual/en/ziparchive.addfile.php#101605

My only example handles a single directory, but maybe it can provide some ideas.
<?php // demo/zip_archive.php

/**
 * Createa a Zip Archive from a subdirectory
 *
 * http://php.net/manual/en/zip.examples.php
 * http://php.net/manual/en/zip.examples.php#85714 <-- Errors are obscure!
 * http://php.net/manual/en/class.ziparchive.php
 * http://php.net/manual/en/ziparchive.close.php#101606
 */
error_reporting(E_ALL);
date_default_timezone_set('America/New_York');


// THIS IS THE LIST OF scandir() RESPONSES THAT WE DO NOT WANT
$unwanted
= array
( '.'
, '..'
, 'teste2.txt'
)
;


// THE URL ARGUMENT IS THE NAME OF THE DIRECTORY TO ZIP
$dir = (!empty($_GET["dir"])) ? $_GET["dir"] : NULL;

// BUT FOR MY TESTS IT IS HARDCODED
$dir = 'oop5';
if (!$dir) die("PLEASE PROVIDE dir= IN THE URL");


// A GOOD PATH ON MY SERVER
$path
= getcwd()
. DIRECTORY_SEPARATOR
. $dir
;
if (!is_dir($path)) die("FAIL: NOT VALID PATH $path");


// INSTANTIATE THE OBJECT
$zip = new ZipArchive();

// CREATE A DATE-TIME ARCHIVE NAME
$archive
= date('Ymd\THis')
. '_archive_'
. $dir
. '.zip'
;
// TRY TO CREATE THE ARCHIVE
if ($zip->open($archive, ZIPARCHIVE::CREATE) !== TRUE) trigger_error("FAIL: ZIP->OPEN $archive", E_USER_ERROR);


// GET THE LIST OF FILES
if (!$files = scandir($path)) die("FAIL: scandir() $path");
foreach ($files as $file)
{
    $filename = $path . DIRECTORY_SEPARATOR . $file;

    // SKIP THE UNWANTED AND ADD THE OTHERS TO THE ARCHIVE
    if ( in_array($file, $unwanted) ) continue;
    if ( !is_file($filename) )        continue;
    // ACTIVATE THIS FOR A PROGRESS REPORT: echo PHP_EOL . "$filename: $file";
    $zip->addFile($filename, $file );
}

if (!$zip->close()) die("FAIL: ZIP->CLOSE");

$fs  = filesize($archive);
$fsn = number_format($fs);


// PREPARE A LINK
$link
= '<a target="_blank" href="'
. $archive
. '">'
. "DOWNLOAD $archive $fsn BYTES"
. '</a>'
;
echo PHP_EOL . $link;

/**
 * You can use something like this to send the Zip Archive directly to the browser
 *
header("Content-Type: archive/zip");
header("Content-Disposition: attachment; filename=$dir".".zip");
header("Content-Length: $fs");
readfile($archive);
 */

Open in new window

Torquil BeavisBusinessAuthor Commented:
Thanks guys. Following your directions and scripts has led me to this point.

Below is the folder and file structure, and the zip and unzip scripts with their outputs.

Issue: The zipper script is supposed to zip all folders and files from abc123 on down, yet only zips the abc123 folder (and no files).

The zipper script is placing the zip file in the correct folder, base_1, and creates the abc123 folder in the zip file, but no other folders or files.
When the unzip script is run, the abc123 folder is correctly placed in the base_2 folder, without the other folders and files of course since there are no others there.

The class is recursive and should zip all the folders and files from abc123 down. Unfortunately the references that I've studied don't help with this.
Any ideas that I could try?

/*
Folders & files:

/app_folder (zipper script and unzipper script run from here)

    /base_1       (this is where the zip file is - folder not to be created in zip file, already created)

        /abc123     (this is first folder to be created upon unzipping into *base_2*)
            /file_A.txt     (the only file to be zipped to this folder)
            /test_folder_2  (the first folder within /abc123 to be created upon unzipping)
                /file_B.txt     (file to be zipped to this folder)
            /test_folder_3  (the second folder within /abc123 to be created upon unzipping)
                /file_C.txt     (file to be zipped to this folder)
                /file_D.txt     ( " )
                /file_E.txt     ( " )

    /base_2       (parent of first folder to be unzipped - folder not to be created from zip file, already created)

        /abc123     (this is first folder to be created upon unzipping)
            /file_A.txt     (the only file to be zipped to this folder)
            /test_folder_2  (the first folder within /abc123 to be created upon unzipping)
                /file_B.txt     (file to be zipped to this folder)
            /test_folder_3  (the second folder within /abc123 to be created upon unzipping)
                /file_C.txt     (file to be zipped to this folder)
                /file_D.txt     ( " )
                /file_E.txt     ( " )
*/

Open in new window


zipper script:
<?php
$abc123 = "abc123";                             // a path to zip up
echo "abc123 = ".$abc123."<br>";
$filename = "base_1/zipfile.zip";                 // a path and name for the zip file
echo "filename = ".$filename."<br><br>";

class Zipper extends ZipArchive
{

    public function addDir($path)
    {
        print '<br /><b>Adding Folder: [ ' . $path . ' ] to the archive.</b><br />';
        $this->addEmptyDir($path);
        $nodes = glob($path . '/*');
        foreach ($nodes as $node)
        {
            print $node . '<br />';
            if (is_dir($node))
            {
                $this->addDir($node);
            }
            else if (is_file($node))
            {
                $this->addFile($node);
            }
        }
    }

} // class Zipper

function make_archive($abc123, $filename)      // from, to
{
    // this is from extended class
    $zip = new zipper();

    if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE)
    {
        exit("cannot open <$filename>\n");
    }

    $zip->addDir($abc123);
    echo "numfiles: " . $zip->numFiles . "\n";
    $zip->close();
}

make_archive($abc123, $filename);

?>

Open in new window


Output from zipper:
/*
Output from zipper_test_10.php:

abc123 = abc123
filename = base_1/zipfile.zip


Adding Folder: [ abc123 ] to the archive.
numfiles: 1
*/

Open in new window


unzipper script:
<?php
$base_2 = "base_2";
echo "base_2 = ".$base_2."<br>";
$filename = "base_1/zipfile.zip";
echo "filename = ".$filename."<br><br>";

$zip = new ZipArchive;
$res = $zip->open($filename);
if ($res === TRUE)
{
  $zip->extractTo($base_2);
  $zip->close();
  echo 'Successfully extracted';
}
else
{
  echo 'There was a problem';
}
?>

Open in new window


Output from unzipper script:
/*
Output from unzipper_test_10.php:

base_2 = base_2
filename = base_1/zipfile.zip

Successfully extracted
*/

Open in new window

Introduction to R

R is considered the predominant language for data scientist and statisticians. Learn how to use R for your own data science projects.

Ray PaseurCommented:
Sorry, this would be a research project for me, and I don't really have time for it this weekend.  But maybe there is a different way of looking at the problem.  Here are some questions that come to mind:

What kinds of files are you needing to zip up?  What is the expected and observed compression ratio?  What is the reason for zipping them instead of keeping them in clear text?  

In my experience, the past few years have given us huge increases in data transfer rates, so if the objective of using zip archives is to shorten data transfer time, you might want to measure the elapsed time and consider whether it's worth a research project, ie: how much payback can you get for the effort?
https://xkcd.com/1205/
Torquil BeavisBusinessAuthor Commented:
Ah yes! July 4th ;)

I need to have zips - not concerned with data transfer time or file sizes.

It seems to be something to do with $nodes = glob($path . '/*'); 'nodes' or 'path'.
I've tried a huge number of cycles to try to discern the problem, and experience tells me it's something simple, or a misunderstanding of mine (probably both).

Maybe someone else can chip in.
Julian HansenCommented:
Here is a solution using the RecursiveDirectoryIterator class (more about this class here http://za1.php.net/manual/en/class.recursivedirectoryiterator.php)

<?php
// PATH TO YOUR SOURCE FILES
$source='e:\projects\ee\t897\abc123\zippo';
$target = 'test_zip.zip';

// CREATE ZIP OBJET
$zip = new ZipArchive();
$zip->open($target, ZipArchive::CREATE | ZipArchive::OVERWRITE);

// GET A RECURSIVE DIRECTORY ITERATOR
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::LEAVES_ONLY);

foreach ($files as $file)
{
  // WE DON'T NEED TO EXPRESSLY INCLUDE FOLDERS
  if (!$file->isDir())
  {
    // GET THE ABSOLUTE PATH FOR THE SOURCE FILE
    $filePath = $file->getRealPath();
  
  // TRUNCATE TO GET RELATIVE PATH FOR ZIP
    $relativePath = substr($filePath, strlen($source) + 1);

    // ADD FILE TO ARCHIVE
    $zip->addFile($filePath, $relativePath);
  }
}

// CLOSE ARCHIVE
$zip->close();

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Torquil BeavisBusinessAuthor Commented:
Perfect! With a bit of string manipulation that worked exactly, Julian. So now the zipping and unzipping work together. Thank you.
Julian HansenCommented:
You are welcome.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.