Hello i used this function for create a zip file (with sub files and sub directories)
<?php
function folderToZip($folder, &$zipFile, $exclusiveLength) {
$handle = opendir($folder);
while (false !== $f = readdir($handle)) {
if ($f != '.' && $f != '..') {
$filePath = "$folder/$f";
// Remove prefix from file path before add to zip.
$localPath = substr($filePath, $exclusiveLength);
if (is_file($filePath)) {
$zipFile->addFile($filePath, $localPath);
} elseif (is_dir($filePath)) {
// Add sub-directory.
$zipFile->addEmptyDir($localPath);
folderToZip($filePath, $zipFile, $exclusiveLength);
}
}
}
closedir($handle);
}
function zipDir($sourcePath, $outZipPath)
{
$pathInfo = pathInfo($sourcePath);
$parentPath = $pathInfo['dirname'];
$dirName = $pathInfo['basename'];
$z = new ZipArchive();
$z->open($outZipPath, ZIPARCHIVE::CREATE);
//$z->addEmptyDir($dirName);
folderToZip($sourcePath, $z, strlen("$parentPath/"));
$z->close();
}
zipDir('mydirectory', 'copy_'.time().'.zip');
?>
The function works perfectly, but only when the file that creates the .zip file is external to "mydirectory"
- mydirectory
- createzip.php
But I would like the file that creates the .zip file was in "mydirectory/update/"
- mydirectory
- mydirectory/update/createzip.php
and do this : zipDir('../../mydirectory', 'copy_'.time().'.zip'); , but this does not work
UPDATE : with this function, the problem persists, I can not make a copy of the folder by running the script to copy from folder to be copied
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();
}
Replace
zipDir('mydirectory', 'copy_'.time().'.zip');
with
$time = time();
zipDir('mydirectory', 'copy_'.$time.'.zip');
rename('copy_'.$time.'.zip', 'mydirectory/update/copy_'.$time.'.zip');
This will create the zip and then move it to the path mydirectory/update/createzip.php
Hope this is what you meant.
On my old VPS I was using the following code to copy the files and directories within a directory to a new directory that was created after the user submitted their form.
function copyr($source, $dest)
{
// Simple copy for a file
if (is_file($source)) {
return copy($source, $dest);
}
// Make destination directory
if (!is_dir($dest)) {
mkdir($dest);
$company = ($_POST['company']);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Deep copy directories
if ($dest !== "$source/$entry") {
copyr("$source/$entry", "$dest/$entry");
}
}
// Clean up
$dir->close();
return true;
}
copyr('Template/MemberPages', "Members/$company")
However now on my new VPS it will only create the main directory, but will not copy any of the files to it. I don't understand what could have changed between the 2 VPS's?
Try something like this:
$source = "dir/dir/dir";
$dest= "dest/dir";
mkdir($dest, 0755);
foreach (
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::SELF_FIRST) as $item
) {
if ($item->isDir()) {
mkdir($dest . DIRECTORY_SEPARATOR . $iterator->getSubPathname());
} else {
copy($item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathname());
}
}
Iterator iterate through all folders and subfolders and make copy of files from $source to $dest
Could I suggest that (assuming it's a *nix VPS) that you just do a system call to cp -r and let that do the copy for you.
This function copies folder recursivley very solid. I've copied it from the comments section on copy command of php.net
function recurse_copy($src,$dst) {
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
I have changed Joseph's code (below), because it wasn't working for me. This is what works:
function cpy($source, $dest){
if(is_dir($source)) {
$dir_handle=opendir($source);
while($file=readdir($dir_handle)){
if($file!="." && $file!=".."){
if(is_dir($source."/".$file)){
if(!is_dir($dest."/".$file)){
mkdir($dest."/".$file);
}
cpy($source."/".$file, $dest."/".$file);
} else {
copy($source."/".$file, $dest."/".$file);
}
}
}
closedir($dir_handle);
} else {
copy($source, $dest);
}
}
[EDIT] added test before creating a directory (line 7)
The Symfony's FileSystem Component offers a good error handling as well as recursive remove and other useful stuffs. Using #OzzyCzech's great answer, we can do a robust recursive copy this way:
use Symfony\Component\Filesystem\Filesystem;
// ...
$fileSystem = new FileSystem();
if (file_exists($target))
{
$this->fileSystem->remove($target);
}
$this->fileSystem->mkdir($target);
$directoryIterator = new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS);
$iterator = new \RecursiveIteratorIterator($directoryIterator, \RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $item)
{
if ($item->isDir())
{
$fileSystem->mkdir($target . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
else
{
$fileSystem->copy($item, $target . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
}
Note: you can use this component as well as all other Symfony2 components standalone.
Here's what we use at our company:
static public function copyr($source, $dest)
{
// recursive function to copy
// all subdirectories and contents:
if(is_dir($source)) {
$dir_handle=opendir($source);
$sourcefolder = basename($source);
mkdir($dest."/".$sourcefolder);
while($file=readdir($dir_handle)){
if($file!="." && $file!=".."){
if(is_dir($source."/".$file)){
self::copyr($source."/".$file, $dest."/".$sourcefolder);
} else {
copy($source."/".$file, $dest."/".$file);
}
}
}
closedir($dir_handle);
} else {
// can also handle simple copy commands
copy($source, $dest);
}
}
function recurse_copy($source, $dest)
{
// Check for symlinks
if (is_link($source)) {
return symlink(readlink($source), $dest);
}
// Simple copy for a file
if (is_file($source)) {
return copy($source, $dest);
}
// Make destination directory
if (!is_dir($dest)) {
mkdir($dest);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Deep copy directories
recurse_copy("$source/$entry", "$dest/$entry");
}
// Clean up
$dir->close();
return true;
}
OzzyCheck's is elegant and original, but he forgot the initial mkdir($dest);
See below. No copy command is ever provided with contents only. It must fulfill its entire role.
$source = "dir/dir/dir";
$dest= "dest/dir";
mkdir($dest, 0755);
foreach (
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST) as $item) {
if ($item->isDir()) {
mkdir($dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
} else {
copy($item, $dest . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
}
}
Here's a simple recursive function to copy entire directories
source: http://php.net/manual/de/function.copy.php
<?php
function recurse_copy($src,$dst) {
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
?>
Why not just ask the OS to take care of this?
system("cp -r olddir newdir");
Done.
<?php
/**
* code by Nk (nk.have.a#gmail.com)
*/
class filesystem
{
public static function normalizePath($path)
{
return $path.(is_dir($path) && !preg_match('#/$#', $path) ? '/' : '');
}
public static function rscandir($dir, $sort = SCANDIR_SORT_ASCENDING)
{
$results = array();
if(!is_dir($dir))
return $results;
$dir = self::normalizePath($dir);
$objects = scandir($dir, $sort);
foreach($objects as $object)
if($object != '.' && $object != '..')
{
if(is_dir($dir.$object))
$results = array_merge($results, self::rscandir($dir.$object, $sort));
else
array_push($results, $dir.$object);
}
array_push($results, $dir);
return $results;
}
public static function rcopy($source, $dest, $destmode = null)
{
$files = self::rscandir($source);
if(empty($files))
return;
if(!file_exists($dest))
mkdir($dest, is_int($destmode) ? $destmode : fileperms($source), true);
$source = self::normalizePath(realpath($source));
$dest = self::normalizePath(realpath($dest));
foreach($files as $file)
{
$file_dest = str_replace($source, $dest, $file);
if(is_dir($file))
{
if(!file_exists($file_dest))
mkdir($file_dest, is_int($destmode) ? $destmode : fileperms($file), true);
}
else
copy($file, $file_dest);
}
}
}
?>
/var/www/websiteA/backup.php :
<?php /* include.. */ filesystem::rcopy('/var/www/websiteA/', '../websiteB'); ?>
hmm. as that's complicated ))
function mkdir_recursive( $dir ){
$prev = dirname($dir);
if( ! file_exists($prev))
{
mkdir_recursive($prev);
}
if( ! file_exists($dir))
{
mkdir($dir);
}
}
...
$srcDir = "/tmp/from"
$dstDir = "/tmp/to"
mkdir_recursive($dstDir);
foreach( $files as $file){
copy( $srcDir."/".$file, $dstDir."/".$file);
}
$file - somthing like that file.txt
I guess you should check user(group)rights. You should consider chmod for example, depending on how you run (su?)PHP. You could possibly also choose to modify your php configuration.
There were some issues with the functions that I tested in the thread and here is a powerful function that covers everything. Highlights:
No need to have an initial or intermediate source directories. All of the directories up to the source directory and to the copied directories will be handled.
Ability to skip directory or files from an array. (optional) With the global $skip; skipping of files even under sub level directories are handled.
Full recursive support, all the files and directories in multiple depth are supported.
$from = "/path/to/source_dir";
$to = "/path/to/destination_dir";
$skip = array('some_file.php', 'somedir');
copy_r($from, $to, $skip);
function copy_r($from, $to, $skip=false) {
global $skip;
$dir = opendir($from);
if (!file_exists($to)) {mkdir ($to, 0775, true);}
while (false !== ($file = readdir($dir))) {
if ($file == '.' OR $file == '..' OR in_array($file, $skip)) {continue;}
if (is_dir($from . DIRECTORY_SEPARATOR . $file)) {
copy_r($from . DIRECTORY_SEPARATOR . $file, $to . DIRECTORY_SEPARATOR . $file);
}
else {
copy($from . DIRECTORY_SEPARATOR . $file, $to . DIRECTORY_SEPARATOR . $file);
}
}
closedir($dir);
}
Recursively copies files from source to target, with choice of overwriting existing files on the target.
function copyRecursive($sourcePath, $targetPath, $overwriteExisting) {
$dir = opendir($sourcePath);
while (($file = readdir($dir)) !== false) {
if ($file == "." || $file == "..") continue; // ignore these.
$source = $sourcePath . "/" . $file;
$target = $targetPath. "/" . $file;
if (is_dir($source) == true) {
// create the target directory, if it does not exist.
if (file_exists($target) == false) #mkdir($target);
copyRecursive($source, $target, $overwriteExisting);
} else {
if ((file_exists($target) == false) || ($overwriteExisting == true)) {
copy($source, $target);
}
}
}
closedir($dir);
}
This question already has answers here:
How to zip a whole folder using PHP
(20 answers)
Closed 1 year ago.
Directory is something like:
home/
file1.html
file2.html
Another_Dir/
file8.html
Sub_Dir/
file19.html
I am using the same PHP Zip class used in PHPMyAdmin http://trac.seagullproject.org/browser/branches/0.6-bugfix/lib/other/Zip.php . I'm not sure how to zip a directory rather than just a file. Here's what I have so far:
$aFiles = $this->da->getDirTree($target);
/* $aFiles is something like, path => filetime
Array
(
[home] =>
[home/file1.html] => 1251280379
[home/file2.html] => 1251280377
etc...
)
*/
$zip = & new Zip();
foreach( $aFiles as $fileLocation => $time ){
$file = $target . "/" . $fileLocation;
if ( is_file($file) ){
$buffer = file_get_contents($file);
$zip->addFile($buffer, $fileLocation);
}
}
THEN_SOME_PHP_CLASS::toDownloadData($zip); // this bit works ok
but when I try to unzip the corresponding downloaded zip file I get "operation not permitted"
This error only happens when I try to unzip on my mac, when I unzip through the command line the file unzips ok. Do I need to send a specific content type on download, currently 'application/zip'
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');
Yet another recursive directory tree archiving, implemented as an extension to ZipArchive. As a bonus, a single-statement tree compression helper function is included. Optional localname is supported, as in other ZipArchive functions. Error handling code to be added...
class ExtendedZip extends ZipArchive {
// Member function to add a whole file system subtree to the archive
public function addTree($dirname, $localname = '') {
if ($localname)
$this->addEmptyDir($localname);
$this->_addTree($dirname, $localname);
}
// Internal function, to recurse
protected function _addTree($dirname, $localname) {
$dir = opendir($dirname);
while ($filename = readdir($dir)) {
// Discard . and ..
if ($filename == '.' || $filename == '..')
continue;
// Proceed according to type
$path = $dirname . '/' . $filename;
$localpath = $localname ? ($localname . '/' . $filename) : $filename;
if (is_dir($path)) {
// Directory: add & recurse
$this->addEmptyDir($localpath);
$this->_addTree($path, $localpath);
}
else if (is_file($path)) {
// File: just add
$this->addFile($path, $localpath);
}
}
closedir($dir);
}
// Helper function
public static function zipTree($dirname, $zipFilename, $flags = 0, $localname = '') {
$zip = new self();
$zip->open($zipFilename, $flags);
$zip->addTree($dirname, $localname);
$zip->close();
}
}
// Example
ExtendedZip::zipTree('/foo/bar', '/tmp/archive.zip', ZipArchive::CREATE);
I've edited Alix Axel's answer to take a third argrument, when setting this third argrument to true all the files will be added under the main directory rather than directly in the zip folder.
If the zip file exists the file will be deleted as well.
Example:
Zip('/path/to/maindirectory','/path/to/compressed.zip',true);
Third argrument true zip structure:
maindirectory
--- file 1
--- file 2
--- subdirectory 1
------ file 3
------ file 4
--- subdirectory 2
------ file 5
------ file 6
Third argrument false or missing zip structure:
file 1
file 2
subdirectory 1
--- file 3
--- file 4
subdirectory 2
--- file 5
--- file 6
Edited code:
function Zip($source, $destination, $include_dir = false)
{
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
if (file_exists($destination)) {
unlink ($destination);
}
$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);
if ($include_dir) {
$arr = explode("/",$source);
$maindir = $arr[count($arr)- 1];
$source = "";
for ($i=0; $i < count($arr) - 1; $i++) {
$source .= '/' . $arr[$i];
}
$source = substr($source, 1);
$zip->addEmptyDir($maindir);
}
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();
}
USAGE: thisfile.php?dir=./path/to/folder (After zipping, it starts download too:)
<?php
$exclude_some_files=
array(
'mainfolder/folder1/filename.php',
'mainfolder/folder5/otherfile.php'
);
//***************built from https://gist.github.com/ninadsp/6098467 ******
class ModifiedFlxZipArchive extends ZipArchive {
public function addDirDoo($location, $name , $prohib_filenames=false) {
if (!file_exists($location)) { die("maybe file/folder path incorrect");}
$this->addEmptyDir($name);
$name .= '/';
$location.= '/';
$dir = opendir ($location); // Read all Files in Dir
while ($file = readdir($dir)){
if ($file == '.' || $file == '..') continue;
if (!in_array($name.$file,$prohib_filenames)){
if (filetype( $location . $file) == 'dir'){
$this->addDirDoo($location . $file, $name . $file,$prohib_filenames );
}
else {
$this->addFile($location . $file, $name . $file);
}
}
}
}
public function downld($zip_name){
ob_get_clean();
header("Pragma: public"); header("Expires: 0"); header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private", false); header("Content-Type: application/zip");
header("Content-Disposition: attachment; filename=" . basename($zip_name) . ";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($zip_name));
readfile($zip_name);
}
}
//set memory limits
set_time_limit(3000);
ini_set('max_execution_time', 3000);
ini_set('memory_limit','100M');
$new_zip_filename='down_zip_file_'.rand(1,1000000).'.zip';
// Download action
if (isset($_GET['dir'])) {
$za = new ModifiedFlxZipArchive;
//create an archive
if ($za->open($new_zip_filename, ZipArchive::CREATE)) {
$za->addDirDoo($_GET['dir'], basename($_GET['dir']), $exclude_some_files); $za->close();
}else {die('cantttt');}
if (isset($_GET['dir'])) {
$za = new ModifiedFlxZipArchive;
//create an archive
if ($za->open($new_zip_filename, ZipArchive::CREATE)) {
$za->addDirDoo($_GET['dir'], basename($_GET['dir']), $exclude_some_files); $za->close();
}else {die('cantttt');}
//download archive
//on the same execution,this made problems in some hostings, so better redirect
//$za -> downld($new_zip_filename);
header("location:?fildown=".$new_zip_filename); exit;
}
if (isset($_GET['fildown'])){
$za = new ModifiedFlxZipArchive;
$za -> downld($_GET['fildown']);
}
?>
Try this link <-- MORE SOURCE CODE HERE
/** Include the Pear Library for Zip */
include ('Archive/Zip.php');
/** Create a Zipping Object...
* Name of zip file to be created..
* You can specify the path too */
$obj = new Archive_Zip('test.zip');
/**
* create a file array of Files to be Added in Zip
*/
$files = array('black.gif',
'blue.gif',
);
/**
* creating zip file..if success do something else do something...
* if Error in file creation ..it is either due to permission problem (Solution: give 777 to that folder)
* Or Corruption of File Problem..
*/
if ($obj->create($files)) {
// echo 'Created successfully!';
} else {
//echo 'Error in file creation';
}
?>; // We'll be outputting a ZIP
header('Content-type: application/zip');
// It will be called test.zip
header('Content-Disposition: attachment; filename="test.zip"');
//read a file and send
readfile('test.zip');
?>;
Here Is my code For Zip the folders and its sub folders and its files and make it downloadable in zip Format
function zip()
{
$source='path/folder'// Path To the folder;
$destination='path/folder/abc.zip'// Path to the file and file name ;
$include_dir = false;
$archive = 'abc.zip'// File Name ;
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
if (file_exists($destination)) {
unlink ($destination);
}
$zip = new ZipArchive;
if (!$zip->open($archive, ZipArchive::CREATE)) {
return false;
}
$source = str_replace('\\', '/', realpath($source));
if (is_dir($source) === true)
{
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
if ($include_dir) {
$arr = explode("/",$source);
$maindir = $arr[count($arr)- 1];
$source = "";
for ($i=0; $i < count($arr) - 1; $i++) {
$source .= '/' . $arr[$i];
}
$source = substr($source, 1);
$zip->addEmptyDir($maindir);
}
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));
}
$zip->close();
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.$archive);
header('Content-Length: '.filesize($archive));
readfile($archive);
unlink($archive);
}
If Any Issue With the Code Let Me know.
I needed to run this Zip function in Mac OSX
so I would always zip that annoying .DS_Store.
I adapted https://stackoverflow.com/users/2019515/user2019515 by including additionalIgnore files.
function zipIt($source, $destination, $include_dir = false, $additionalIgnoreFiles = array())
{
// Ignore "." and ".." folders by default
$defaultIgnoreFiles = array('.', '..');
// include more files to ignore
$ignoreFiles = array_merge($defaultIgnoreFiles, $additionalIgnoreFiles);
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
if (file_exists($destination)) {
unlink ($destination);
}
$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);
if ($include_dir) {
$arr = explode("/",$source);
$maindir = $arr[count($arr)- 1];
$source = "";
for ($i=0; $i < count($arr) - 1; $i++) {
$source .= '/' . $arr[$i];
}
$source = substr($source, 1);
$zip->addEmptyDir($maindir);
}
foreach ($files as $file)
{
$file = str_replace('\\', '/', $file);
// purposely ignore files that are irrelevant
if( in_array(substr($file, strrpos($file, '/')+1), $ignoreFiles) )
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();
}
SO to ignore the .DS_Store from zip, you run
zipIt('/path/to/folder', '/path/to/compressed.zip', false, array('.DS_Store'));
Great solution but for my Windows I need make a modifications. Below the modify code
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;
if (is_dir($file) === true)
{
$zip->addEmptyDir(str_replace($source . '/', '', $file));
}
else if (is_file($file) === true)
{
$str1 = str_replace($source . '/', '', '/'.$file);
$zip->addFromString($str1, file_get_contents($file));
}
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
This code works for both windows and linux.
function Zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
return false;
}
$zip = new ZipArchive();
if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
return false;
}
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
DEFINE('DS', DIRECTORY_SEPARATOR); //for windows
} else {
DEFINE('DS', '/'); //for linux
}
$source = str_replace('\\', DS, realpath($source));
if (is_dir($source) === true)
{
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
echo $source;
foreach ($files as $file)
{
$file = str_replace('\\',DS, $file);
// Ignore "." and ".." folders
if( in_array(substr($file, strrpos($file, DS)+1), array('.', '..')) )
continue;
$file = realpath($file);
if (is_dir($file) === true)
{
$zip->addEmptyDir(str_replace($source . DS, '', $file . DS));
}
else if (is_file($file) === true)
{
$zip->addFromString(str_replace($source . DS, '', $file), file_get_contents($file));
}
echo $source;
}
}
else if (is_file($source) === true)
{
$zip->addFromString(basename($source), file_get_contents($source));
}
return $zip->close();
}
Here's my version base on Alix's, works on Windows and hopefully on *nix too:
function addFolderToZip($source, $destination, $flags = ZIPARCHIVE::OVERWRITE)
{
$source = realpath($source);
$destination = realpath($destination);
if (!file_exists($source)) {
die("file does not exist: " . $source);
}
$zip = new ZipArchive();
if (!$zip->open($destination, $flags )) {
die("Cannot open zip archive: " . $destination);
}
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);
$sourceWithSeparator = $source . DIRECTORY_SEPARATOR;
foreach ($files as $file)
{
// Ignore "." and ".." folders
if(in_array(substr($file,strrpos($file, DIRECTORY_SEPARATOR)+1),array('.', '..')))
continue;
if (is_dir($file) === true)
{
$zip->addEmptyDir(
str_replace($sourceWithSeparator, '', $file . DIRECTORY_SEPARATOR));
}
else if (is_file($file) === true)
{
$zip->addFile($file, str_replace($sourceWithSeparator, '', $file));
}
}
return $zip->close();
}
Here is the simple, easy to read, recursive function that works very well:
function zip_r($from, $zip, $base=false) {
if (!file_exists($from) OR !extension_loaded('zip')) {return false;}
if (!$base) {$base = $from;}
$base = trim($base, '/');
$zip->addEmptyDir($base);
$dir = opendir($from);
while (false !== ($file = readdir($dir))) {
if ($file == '.' OR $file == '..') {continue;}
if (is_dir($from . '/' . $file)) {
zip_r($from . '/' . $file, $zip, $base . '/' . $file);
} else {
$zip->addFile($from . '/' . $file, $base . '/' . $file);
}
}
return $zip;
}
$from = "/path/to/folder";
$base = "basezipfolder";
$zip = new ZipArchive();
$zip->open('zipfile.zip', ZIPARCHIVE::CREATE);
$zip = zip_r($from, $zip, $base);
$zip->close();
Following #user2019515 answer, I needed to handle exclusions to my archive. here is the resulting function with an example.
Zip Function :
function Zip($source, $destination, $include_dir = false, $exclusions = false){
// Remove existing archive
if (file_exists($destination)) {
unlink ($destination);
}
$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);
if ($include_dir) {
$arr = explode("/",$source);
$maindir = $arr[count($arr)- 1];
$source = "";
for ($i=0; $i < count($arr) - 1; $i++) {
$source .= '/' . $arr[$i];
}
$source = substr($source, 1);
$zip->addEmptyDir($maindir);
}
foreach ($files as $file){
// Ignore "." and ".." folders
$file = str_replace('\\', '/', $file);
if(in_array(substr($file, strrpos($file, '/')+1), array('.', '..'))){
continue;
}
// Add Exclusion
if(($exclusions)&&(is_array($exclusions))){
if(in_array(str_replace($source.'/', '', $file), $exclusions)){
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();
}
How to use it :
function backup(){
$backup = 'tmp/backup-'.$this->site['version'].'.zip';
$exclusions = [];
// Excluding an entire directory
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('tmp/'), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file){
array_push($exclusions,$file);
}
// Excluding a file
array_push($exclusions,'config/config.php');
// Excluding the backup file
array_push($exclusions,$backup);
$this->Zip('.',$backup, false, $exclusions);
}