How to [Recursively] Zip a Directory in PHP

How to [recursively] Zip a directory in PHP?

Here is a simple function that can compress any file or directory recursively, only needs the zip extension to be loaded.

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 . '/'));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}

return $zip->close();
}

Call it like this:

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

How to ZIP an entire folder in PHP, even the empty ones?

// Initialize archive object
$zip = new ZipArchive();
$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)
{
// Get real and relative path for current file
$filePath = $file->getRealPath();
$relativePath = substr($filePath, strlen($rootPath) + 1);

if (!$file->isDir())
{
// Add current file to archive
$zip->addFile($filePath, $relativePath);
}else {
if($relativePath !== false)
$zip->addEmptyDir($relativePath);
}
}

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

Hi. I modified the previous answer and now I get the zip file including the empty folders. I hope this helps.

How to zip a whole folder using PHP

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

Recursively zip multiple folders

If I understand you correctly, you can simply change your code to expect $source to be either string or array. Then you can loop through that array and add all desired folders and their sub-folders

Examples:

function Zip($source, $destination)
{
if (is_string($source)) $source_arr = array($source); // convert it to array

if (!extension_loaded('zip')) {
return false;
}

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

foreach ($source_arr as $source)
{
if (!file_exists($source)) continue;
$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('\\', '/', realpath($file));

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

}

return $zip->close();

}

Zip might be empty of all specified paths are invalid but you can take care of that too.

Trouble with zipping directory in PHP

copy all your files into a temp location then use this to create a zip file of your temp folder then delete your temp folder

/** 
* Function will recursively zip up files in a directory and all sub directories / files in the specified source
* @param - $source - directory that you want contents of zipping - note does NOT zip primary directory only files and folders within directory
* @param - $destination - filepath and filename you are storing your created zip files in (could also be used to stream files down using the correct stream headers) eg: "/createdzips/zippy.zip"
* @return nothing - nada - null - zero - zilch - zip :)
*/
function zipcreate($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('\\', '/', realpath($file));
if (is_dir($file) === true) {
$zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
} else if (is_file($file) === true) {
$zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
}
}
} else if (is_file($source) === true) {
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}

zipcreate("c:/xampp/htdocs/filemanager/Screenshots", "c:/xampp/htdocs/filemanager/uploads/screenshots.zip");


header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"c:/xampp/htdocs/filemanager/uploads/screenshots.zip\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize("c:/xampp/htdocs/filemanager/uploads/screenshots.zip"));

PHP: Get all zip file from multiple sub-directories using scandir

I think that your problem stems from the fact that scandir() isn't (by itself) a recursive directory search, it only lists the files and directories directly in the specified directory. You have accounted for that already with your recursive call to your listFolderFiles() function if you detect that $ff is a directory. However, your problem is that you have already filtered out directories in your previous if statement (assuming your directories don't end in '.zip'). I think the below function is what you are after:

            function listFolderFiles($dir){
$ffs = scandir($dir);
echo '<ol>';
foreach($ffs as $ff){
$ext = pathinfo($ff, PATHINFO_EXTENSION);

if($ff != '.' && $ff != '..' && (is_dir($dir.'/'.$ff) || $ext == 'zip')){
echo '<li>';
$str = preg_replace('/\D/', '', $ff);
$str = substr($str, 0,-1);

$getYear = substr($str, 0,4);
$getMonth = substr($str, -4,2);
$getDay = substr($str, -2,2);
$theDate = $getYear.'-'.$getMonth.'-'.$getDay;
$theRealDate = date('Y M j', strtotime($theDate));
echo $theRealDate;


if(is_dir($dir.'/'.$ff)){
listFolderFiles($dir.'/'.$ff);
}

echo '</li>';
}

}
echo '</ol>';
}
listFolderFiles('store_files');


Related Topics



Leave a reply



Submit