Create a Zip File Using PHP

By  on  

Creating .ZIP archives using PHP can be just as simple as creating them on your desktop. PHP's ZIP class provides all the functionality you need! To make the process a bit faster for you, I've coded a simple create_zip function for you to use on your projects.

The PHP

/* creates a compressed zip file */
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
		//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
		
		//close the zip -- done!
		$zip->close();
		
		//check to make sure the file exists
		return file_exists($destination);
	}
	else
	{
		return false;
	}
}

Sample Usage

$files_to_zip = array(
	'preload-images/1.jpg',
	'preload-images/2.jpg',
	'preload-images/5.jpg',
	'kwicks/ringo.gif',
	'rod.jpg',
	'reddit.gif'
);
//if true, good; if false, zip creation failed
$result = create_zip($files_to_zip,'my-archive.zip');

The function accepts an array of files, the name of the destination files, and whether or not you'd like the destination file to be overwritten if a file of the same name exists. The function returns true if the file was created, false if the process runs into any problems.

This functionality is great for web-based file managers. Who knows, I may just submit this to Christoph's MooTools FileManager project. Happy zipping!

Recent Features

Incredible Demos

  • By
    Face Detection with jQuery

    I've always been intrigued by recognition software because I cannot imagine the logic that goes into all of the algorithms. Whether it's voice, face, or other types of detection, people look and sound so different, pictures are shot differently, and from different angles, I...

  • By
    Create Digg URLs Using PHP

    Digg recently came out with a sweet new feature that allows users to create Tiny Digg URLs which show a Digg banner at the top allowing easy access to vote for the article from the page. While I love visiting Digg every once in a...

Discussion

  1. Hi, I have a question. I looked everywhere, the doc on php.net, google, forums, but I can’t find out: How do you set the compression method (storage, fast, normal, best) with the ZipArchive class? I need to set it to the storage mode, so it just groups files together without compressing them, because those files are already compressed (jpeg, mp3) and the compression actually take some times with big files like mp3s. I do use caching (I just don’t delete the archive after submission), but the thing is the archives need to be created at least once, and it takes forever. If anyone knows, I’m interested

  2. Everyday I check my feeds, and every day you seem to have written another ridiculously informative article! Thanks again, and where do you find the time! :)

  3. @Luke: I have a very patient girlfriend… :)

    • I am jealous of you, this can be done with just handful of functions. Thanks.

  4. Ahmed

    How about compressing an entire folder?

  5. @ahmed: you’d have to modify the script so it checks for each file if it’s a folder with the is_dir function, then use open_dir to get all the files and add them to the array. Just make sure you test for “.” and “..” when looping through the folder so they are not added to the array. Oh and check for sub folders with is_dir too. A recursive function would be ideal. Then i think there is function to create folders inside zip archive.
    So it would definitely need a little bit of work, but it can be done. I recommend you look at the doc of is_dir, open_dir and ZipArchive::addEmptyDir on php.net. There are always so nice user posted example for each function

  6. Langel

    I’ve had problems in the past where a client’s webhost doesn’t have the zlib package installed in their php. I actually worked up a work-around utilizing the zip and unzip programs built into *nix systems. Funny though, I couldn’t test/debug locally on my windows machine without adding a path to the system, and so I just kept uploading the script and testing anyways. I are silly sometimes. =P

  7. function create_zip(array $files = NULL,$destination = ”,$overwrite = false) {

    You can put “array” before the first parameter, this will make sure only an array can be passed into it. You can only do this for arrays and classes iirc. If I pass “hello” as the first parameter, the script will break. count(‘hello’) will return (int) 1 which, when casted to a bool be TRUE. Using the modified code above will result in the following error while passing a string value.

    Catchable fatal error: Argument 1
    passed to create_zip() must be an
    array, string given,

  8. You sir, are a god.

  9. Maybe we can create rar archives via exec commands?

  10. Langel

    That’s a good question! Lemme know here if you come up with any answers. ;D/

  11. saqib

    Hi,
    I got error on line $zip = new ZipArchive();. I don’t know why although i had enable the PHP_Zip module. Can anybody tell why?

  12. Yah I ran into the same problem as saqib on my two servers that I have zlib 1.2.3 installed on:

    Fatal error: Class ‘ZipArchive’ not found

  13. Just another great article from David.
    Oh and having a “patient girlfriend” is a gift

  14. Some very nice, informative articles here, stuff in PHP I can use for Coldfusion as well. But this one is even simpler in CF:

    ;-)

    Thanx, and I’ll follow your writings via the RSS-feed!

    • Well yeah, they already did all the work in CF, thats why it cost so much.

  15. Darn, tags are filtered out, so I’ll just write it in plain English: <cfzip>

  16. Hi David! Great function. Saved me some time and some hair!

    I was using it to ZIP files that weren’t in the same directory as the script, and so I was getting lots of nested directories. Normally this is a Good Thing, but I’m using the script in a situation where I’m only zipping one file at a time, so I wanted to get rid of the subdirectories. I added a fourth parameter to the function: $distill_subdirectories = true, and then changed the code around line 24 to:

    //add the files
    foreach($valid_files as $file) {
        if ($distill_subdirectories) {
            $zip->addFile($file, basename($file) );
        } else {
            $zip->addFile($file, $file);
        }
    }
    

    Figured that might be helpful to some.

    (Note that the _ should be _)

    • Serj

      Hi Eric =)
      Thank You nice snippet.

    • robbie

      yeah! thank you!

    • This is really a handy snippet … I was in search of the code to eliminate entire directory structure. Nice Fork…!!

  17. Is it possible to change the destination directory of the files in the ZIP? I don’t want my files to inherit the same directory structure as their original path.

  18. hi,
    I’ve used code very similar to this expect I get no zip file actually made
    after creating the file, and adding a file to it I have the following code:

    echo “numfiles: ” . $zip->numFiles . “”;
    echo “status:” . $zip->status . “”;
    if ( $zip->close()) {echo “Success!”;}
    else { echo ” failed to save “;}

    numfiles gives me a result of 1
    stsua gives 0

    and I get “failed to save”

    I’m fairly sure this is not a permissions issue since another file in the same directory opens several files then creates a new one from excerpts. I’ve been searching google all day but can find to reference to this anywhere ( ‘cept one post on php.net which states its a permissions issue)

    Thanks in advance,
    Verbosity

  19. jeff

    Nice zip class tutorial:) When zipping up multiple files or whole directories, how do you control zips that will potentially use up all the server’s memory? ie. trying to make a zip file from 2GB of data.

  20. @Jeff: You wouldn’t want to attempt that, I don’t think.

    • Jonathan

      When dealing w/large files or a final ZIP file that would turn out very large (e.g. 2GB) is it possible to split the ZIP file up into multiple files on creation? Any web server is gonna choke on a 2GB file however splitting the operation up into 40+ individual ZIP files could theoretically work, no?

  21. jeff

    Thanks for the speedy response. Yea, that’s the same answer I came up with. I guess a quick and dirty solution could be to calculate the potential zip content size on page load and disable the ability to zip the whole folder if the content size is too great. Just curious if you’d ever run into this problem.

  22. I know when a website creates even a 100mb zip there is a very noticeable wait for the page to load…

  23. Lolki

    Hi David, and thanks a lot for what you do, and the way you do it !
    I would like to adapt your script to use it on my website. But I would like to get the file names to zip from records in mysql database ?
    How can I do that ?

    Hope you can give me an hint ! ;)

  24. The plugin you use to convert you code into the snazzy display above, also converts & to & when you select “Raw Code”. Wich means anyone copying the “Raw Code” will get errors. Thought you might wanna know.

    :)

    Adam

  25. Adin

    Thanks broo….

    Its very usefull, u sample code is working and no error.

    Best Regards,

    Adin

  26. Mono

    Your script worked perfectly for me. Really happy with that!

    Thanks,
    Mono

  27. this is clear for last else-if:

    function create_zip($files = array(),$destination = '',$overwrite = false)
    {
    	if(file_exists($destination) && !$overwrite)
    		return false;
    	$valid_files = array();
    	if(is_array($files))
    		foreach($files as $file)
    			if(file_exists($file))
    				$valid_files[] = $file;
    	if(empty($valid_files))
    		return false;
    	$zip = new ZipArchive();
    	if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true)
    		return false;
    	foreach($valid_files as $file)
    		$zip->addFile($file,$file);
    	//debug
    	//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
    	$zip->close();
    	return file_exists($destination);
    }
    • 0)
      {
      // Checking files are selected
      $zip = new ZipArchive(); // Load zip library
      $zip_name = time().”.zip”; // Zip name
      if($zip->open($zip_name, ZIPARCHIVE::CREATE)!==TRUE)
      {
      // Opening zip file to load files
      $error .= “* Sorry ZIP creation failed at this time”;
      }
      foreach($post[‘files’] as $file)
      {
      $zip->addFile($file_folder.$file); // Adding files into zip
      }
      $zip->close();
      if(file_exists($zip_name))
      {
      // push to download the zip
      header(‘Content-type: application/zip’);
      header(‘Content-Disposition: attachment; filename=”‘.$zip_name.'”‘);
      readfile($zip_name);
      // remove zip file is exists in temp path
      unlink($zip_name);
      }

      }
      else
      $error .= “* Please select file to zip “;
      }
      else
      $error .= “* You dont have ZIP extension”;
      }
      ?>

  28. Param

    Hello David,

    This is a really nice snippet. However, I was trying the following scenario
    1. passing the complete physical path of two diff files placed in two diff locations.
    2. trying to create a zip file from these two files at a seperate location [passing the complete physical path to the ‘destination’ parameter as well]

    This , however, is not creating the zip file as desired. Anything to do with the paths ?

  29. You have posted really tremendous work. Thanks.

  30. Adin

    The result .zip file successfull open with winrar, but if we use 7zip or winzip it will be show error for extract the file zip.

  31. I write a recurse function which can zip a file or a complete directory. This function only require the path of the file or directory as argument. You can read this function here:
    http://ramui.com/articles/php-zip-files-and-directory.html

  32. Daniel

    I have used your test example above. The zip file appears to have been created and they filesize suggests there are contents, but on opening the zip file (windows platform), it is empty?

    Any ideas?

  33. Daniel

    @Jam: I second this observation. Having now worked out how to create the zip file on a windows platform (although not accessible using XPs zip), the file is added mimicking the folder structure from where it was added. I only need the actual file i want to attach, not all parent folders aswell.

  34. mrlilhare

    Hi David,
    Can we make a functions for choose file name from table, move them in a location and then add all that in a archive file.

  35. Lolki

    Hi Mr Lilhare,
    I have coded this, and maybe it can help you.
    First I display a list of songs picked form a database in a table, with checkboxes.
    When the user have finished picking his songs, He clicks on a button, and then magic happens. The script zip the files chose in a archive. I didn’t see any interest in moving the songs to another place to create thz zip, but it is easy to code. In my case, when the zip is ready, I copy it into the user private directory, and I even add a PDF with the song list into the zip.

    //$files_to_zip=array(); 
    $id_utilisateur = $_GET['id_utilisateur'];
    $id_synchro = $_GET['mb'];
    //$fichier_pdf = "$id_utilisateur/AUTORISATION-$id_synchro.pdf";
    
    mysql_select_db($xxxxx, $xxxxx);
    $query = mysql_query("SELECT DISTINCT table_synchro.id_synchro, table_musique.nom_fichier FROM (table_musique LEFT JOIN table_synchro ON table_synchro.id_musique=table_musique.id_musique) WHERE table_synchro.id_synchro='$id_synchro'  ") or die(mysql_error()); 
    
    while ($row = mysql_fetch_assoc($query)) {$files_to_zip[] = '../high/'.$row['nom_fichier'].'.mp3';} 
    $files_to_zip[] = $id_utilisateur.'/AUTORISATION-'.$id_synchro.'.pdf';
    
    //print_r($files_to_zip);  
    
    $chemin= "fiche.php?id_synchro=$id_synchro&KT_back=1&new=1";
    header("Location: $chemin"); 
    
    /* creates a compressed zip file */
    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,basename($file));
    		}
    		
    		//debug
    		//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
    		
    		//close the zip -- done!
    		$zip->close();
    		
    		//check to make sure the file exists
    		return file_exists($destination);
    	}
    	else
    	{
    		return false;
    	}
    }
    
    
    
    $nom_zip = 'Name-'.$id_synchro.'.zip';
    $nouveau_nom_zip = $id_utilisateur.'/'.$nom_zip;
    $perdu = $id_utilisateur.'/index.html';
    
    
    
    
    //if true, good; if false, zip creation failed
    $result = create_zip($files_to_zip,$nom_zip);
    echo $result;
    
    
    if (is_dir($id_utilisateur)) { 
    //chmod($nom_zip,0777);
    copy ($nom_zip, $nouveau_nom_zip);
    unlink ($nom_zip);
    }
    
    else
    
    { 
    mkdir($id_utilisateur,0777); 	
    //chmod($nom_zip,0777);
    copy ($nom_zip, $nouveau_nom_zip);
    copy ("perdu.html", $perdu);
    unlink ($nom_zip);
    
    }
    
    mysql_free_result($query);
    
  36. yaseen

    @Eric Strathmeyer: Good function by David, and i have similar situation so these lines help me as well. Thanks

  37. nitin

    Compressing an entire folder

    function directoryToArray($directory, $recursive) {
    $array_items = array();
    if ($handle = opendir($directory)) {
    while (false !== ($file = readdir($handle))) {
    if ($file != “.” && $file != “..” && $file != “Thumbs.db”) {
    if (is_dir($directory. “/” . $file)) {
    if($recursive) {
    $array_items = array_merge($array_items, directoryToArray($directory. “/” . $file, $recursive));
    }
    $file = $directory . “/” . $file;
    $array_items[] = preg_replace(“/\/\//si”, “/”, $file);
    } else {
    $file = $directory . “/” . $file;
    $array_items[] = preg_replace(“/\/\//si”, “/”, $file);
    }
    }
    }
    closedir($handle);
    }
    return $array_items;
    }
    $files_to_zip = directoryToArray(“myfolder”,true);

    • ZeNz0r

      Had to fix the content of the

      is_dir

      condition, as both the folder and “file without extension” were being created.

      Here’s the fixed function:

      function directoryToArray($directory, $recursive) {
      	$array_items = array();
      	if ($handle = opendir($directory)) {
      		while (false !== ($file = readdir($handle))) {
      			if ($file != '.' && $file != '..' && $file != 'Thumbs.db' && $file != 'error_log') {
      				if (is_dir($directory. '/' . $file)) {
      					if($recursive) {
      						$array_items = array_merge($array_items, directoryToArray($directory. '/' . $file, $recursive));
      					}
      				} else {
      					$file = $directory . '/' . $file;
      					$array_items[] = preg_replace('/\/\//si', '/', $file);
      				}
      			}
      		}
      		closedir($handle);
      	}
      	return $array_items;
      }
      
  38. selami

    thanks for great code ♥♥♥

  39. strgg

    thanks nitin, works like a charm

  40. Wow mate! Thank you very much! Excactly what I was looking for! Now I need to find a way to backup a complete website in this zip. Then use it as a weekly cron. Any ideas?

  41. Ian Agustiawan

    i have used that code…

    but i stiil get error when i extract the file.zip..
    ”crc failed….this file is corrupt.”

  42. David

    I used your code and it seemed to work file. However, when I try to ‘extract file’ in windows explorer I get a message the ‘windows has blocked access to these files to help protect your computer’. It suggests that I unblock the file in the properties dialog, but no such option exists.

    So, is windows not capable of extracting the files or is it a corrupt zip file? Anybody have experience with this?

    Thanks.

    • Mike

      I’m getting this same behavior. Work on Ubuntu archive mounter, but not in archive manager. Doesn’t work on windows.

      Here’s the error message on linux:

      7-Zip 9.04 beta Copyright (c) 1999-2009 Igor Pavlov 2009-05-30
      p7zip Version 9.04 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,4 CPUs)

      Error: /home/michael/Downloads/dsat-assessment.zip: Can not open file as archive

      Errors: 1

      Any suggestions?

    • Carrie

      I had the same error, and found it was filenames used inside the zipped folder were set to include the entire path. I modified the code to use just the file name:

      //add the files
      foreach($valid_files as $file)
      {
      //addFile – http://www.php.net/manual/en/ziparchive.addfile.php
      //filename – The path to the file to add.
      //localname – this is the local name inside the ZIP archive that will override the filename.
      $filename = basename(file);
      $ext = pathinfo($file, PATHINFO_EXTENSION);
      $localname = $filename.”.”.$ext;
      //debug
      echo ”.$file.” ~ “.$localname;
      $zip->addFile($file,$localname);
      }

  43. Pranav Dave

    Hey David and Anybody Here,

    I used the david snippet in my local machine, it doesn’t work as it doesn’t get the files I have written in array,
    do I have to write the complete path..? pls provide some example..

  44. sheetalmhalsekar

    @nitin:

    Hello Nitin, I have used ur code .I am not getting any error, but zip file is also not created.Anything else is needed.
    U r help is needed.

    Thanks,
    Sheetal

  45. nitin

    @sheetalmhalsekar

    hi sheetal, function posted by me creates an array list of directory items.

    $files_to_zip = directoryToArray(“myfolder”,true);

    now pass the array “$files_to_zip” to create_zip function

    $result = create_zip($files_to_zip,’my-archive.zip’);

  46. zenmonkey

    I’m having problems implementing the script in the SilverStripe CMS. I added a few else statements after some of the ifs that don’t have them so I could see where the problem is. It seems to be throwing errors when in cycles through each of the files. It says they don’t exist. Any ideas?

  47. Hi David

    Thanks for this script – it’s a lifesaver!

    Question – I”ve used this function as part of a web application that creates downloadable archives of files on the fly for my users. However – when they download the zips onto a PC (running XP) the PC won’t open them – saying that the files are untrusted because they have come from another computer.

    Is there anything I can add to my zip-archives at the point of creation which will stop them from getting blocked by SP2 filters?

    I hate PCs…

  48. how to create zip from directory?

    thanks

  49. For all those here who have had an issue with nested folders inside your zip file with PC/Windows blocking extraction – I too had this issue. eg I have modified this script to keep the nested folder structure by passing in an array of files to add with source & destination keys.

    When my windows users (I’m a mac man myself) couldn’t open I started to wonder whether it was an encoding error as some of my folder names contain parentheses – not by my design but a default of Adobe’s where they export artwork files to a (Footage) folder. But I digress.

    The issue ended up being a dirty old slash / at the beginning of my nested folder structure. eg /(Footage)/foo/bar After removing proceeding / eg (Footage)/foo/bar – all worked fine.

    Note that programs like winzip handled the opening / slash fine – just the builtin windows extractor had the issue.

    I hope this helps out any if at all – took me a few hours to sort.
    Best
    Kyle

    • Nick

      Kyle – thank you VERY much. I was having the same problem of not being able to open ZIP archive files with nested directories created by ZipArchive on any Windows platform (with the built-in Windows ZIP program.) This was driving me crazy and it turned out to be the leading dot-slash just like you said. So I stripped it out and everything is working fine now on Windows and Linux/Unix based platforms.

      Thanks again!

      – Nick

  50. Chris

    @daniel (or anyone else getting an “empty” zip file)

    I too was getting zip files of the appropriate size, but appeared empty when viewed and and I tried to extract, windows was telling me the file was invalid. After looking at the ZipArchive manual on php.net, the problem stems from:

    $zip->addFile($file,$file);

    unless you have the function in the same directory as the files you want to zip, you will need to include the file path (which most people will if they use the function as an include). The 2nd parameter in addFile is the name of the file inside the zip, so if your $file var includes the path, that’s where the nested folder issue is coming from. So to solve this, I changed the code to :

    $just_name = preg_replace("/(.*)\/?([^\/]+)/","$2",$file); 	
    $zip->addFile($file,$just_name);
    

    which will strip out the file path (if any) and leave you only the file name for the 2nd variable in addFile. Now my zips open and extract just fine = )

    • Hello chris
      Thanks for you answer
      Your description works fine, but i like to keep the orginel file name and i can see that the variable $2 is the given file name. How can i keep the original name?

      Best regart Poul

    • Hei Chris never mind:)

      Hei Chris never mind:)

      i solloverd it by sending another array to the create_zip function:

      function create_zip($files = array(),$destination = '',$overwrite = false,$file_names = array())
      

      and the´n i loopt the aray:

      	$count = 0;
      		foreach($valid_files as $file) {
      		
      		$just_name = preg_replace("/(.*)\/?([^\/]+)/",$file_names[$count],$file);
      				print "file_names".$file_names[$count];
      			if ($distill_subdirectories) {
      				$zip->addFile($file, $just_name );
      			} else {
      				$zip->addFile($file, $just_name);
      		}
      		$count++;
      		}
      
      

      Thanks anyway

    • Aye Aye Mon

      I had the same problem extracting the generated zip on Windows because file path contained ../
      I fixed it by

      $zip->addFile($file,basename($file));
  51. Chris

    Hello Poul,

    if you are still having problems, use echo command (or print_r for arrays) to print out variable values so you can be sure they are correct at each step, or to print a “working” message for your if/else statements to see if they fail.

  52. Sandeep

    Thanks David :) This was great help.

  53. how can i put a password into the zip file?

  54. Kelly

    Failed To save is the echo i receive.
    echo "numfiles: " . $zip->numFiles . "";
    echo "status:" . $zip->status . "";
    if ( $zip->close()) {echo "Success!";}
    else { echo " failed to save ";}

    I tried a file that was in the same directory as well, but still not able to save the zip. its as if the zip is not being created or something. the numfiles says 5 and the status says 23. I feel like I am missing one small part and once I have that, this will work.

    my php info:
    Zip enabled
    Extension Version $Id: php_zip.c 300470 2010-06-15 18:48:33Z pajoye $
    Zip version 1.9.1
    Libzip version 0.9.0

    ZLib Support enabled
    Stream Wrapper support compress.zlib://
    Stream Filter support zlib.inflate, zlib.deflate
    Compiled Version 1.2.3
    Linked Version 1.2.3

    Directive Local Value Master Value
    zlib.output_compression Off Off
    zlib.output_compression_level -1 -1
    zlib.output_handler no value no value

    The code i am using is copied from above almost to a T, with the only difference of i am creating an array of files on the fly (i did try a static file, same results) and a post above gave a preg_replace that I put in.

    Again, thank you in advance for the help and great script.

  55. Andy Kay

    doesnt work. no error, no file created. I think you need to edit the code before giving it out!

  56. Andy Kay

    getting status code ‘0’ in debug mode – no zip created.

  57. Hi, David !
    If the files in Hebrew (like, עוד קובץ אחד.png), it saved in invalid encoding. I get ??? ??? ???.png.
    Please, help me !!

  58. mona

    ini_set(“max_execution_time”, 3000);
    $zip = new ZipArchive(); //uses php_zip.zll and a small php.ini modification
    // open archive

    $zipName = “backup.zip”; //this can already exist, if not, it creates a new one.

    if ($zip->open(“$zipName”, ZIPARCHIVE::CREATE) !== TRUE) {
    die (“Could not open archive”);
    }
    $dirName = ‘../backup/’; //type ur directory name on which you copy ur zip file

    $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(“../”)); //path to folder that you want in the zip
    // iterate over the directory
    // add each file found to the archive

    foreach ($iterator as $key=>$value) {
    $zip->addFile($dirName.$key,$dirName.$key) or die (“ERROR: Could not add file to zip: $key”);
    }

    // close and save archive
    $zip->close();

    //if directory is not available then you create your directory
    if(!is_dir(‘../backup’))
    {
    mkdir(‘../backup’,777);
    }

    $dest=”../backup/”.$zipName;//on which you copy your zip file
    $source=”../admin/”.$zipName;//already exists your zip file in this folder

    $strcopy=copy($source,$dest);
    unlink($source);

  59. Mohsen elgendy

    Hi,
    I used your function with Arabic language but, the problem is when any file which is in Arabic language it doesn’t get zipped with the right name when in fact it get zipped like this “+¦+ê+¦+ç.jpg”. So Any help ? Thanks a lot david

  60. karthik

    hey thanks man it helped me a lot….great code,but when it creates a zip file it will take whole path so i found the mistake that

    The problem here is that $zip->addFile is being passed the same two parameters.

    According to the documentation:

    bool ZipArchive::addFile ( string $filename [, string $localname ] )

    filename
    The path to the file to add.

    localname
    local name inside ZIP archive.

    This means that the first parameter is the path to the actual file in the filesystem and the second is the path & filename that the file will have in the archive.

    When you supply the second parameter, you’ll want to strip the path from it when adding it to the zip archive. For example, on Unix-based systems this would look like:

    $new_filename = substr($file,strrpos($file,’/’) + 1);
    $zip->addFile($file,$new_filename);

  61. karthik

    hey thanks man it helped me a lot….great code,but when it creates a zip file it will take whole path so i found the mistake that

    The problem here is that $zip->addFile is being passed the same two parameters.

    According to the documentation:

    bool ZipArchive::addFile ( string $filename [, string $localname ] )

    filename
    The path to the file to add.

    localname
    local name inside ZIP archive.

    This means that the first parameter is the path to the actual file in the filesystem and the second is the path & filename that the file will have in the archive.

    When you supply the second parameter, you’ll want to strip the path from it when adding it to the zip archive. For example, on Unix-based systems this would look like:

    $new_filename = substr($file,strrpos($file,’/’) + 1);
    $zip->addFile($file,$new_filename);

    I got this solution from other source

  62. priya

    Hi Thanks,
    for the code..it worked for me..

    I want to delete a zip folder.plz can u let me know how to delete?

  63. priya

    Hello,
    Thanks for the code..It helped me a lot..
    Plz can u let me know how can we delete the zip folder?

    • Arun

      Use unlink() function to delete any files.

  64. ron

    why not use system commands..

    system(” zip -r archive.zip *; “);

    there is no easier way of doin this..cheers.

  65. Ben

    I see you are “hosted on Media Temple” but my Media Temple gs does not have ZipArchive enabled. I’ve tried installing the pecl extension (instructions on their kb) but it is still not working.

    “Fatal error: Class ‘ZipArchive’ not found in (php filename)”

    Thanks!

  66. Phatnoir

    Hey, I was having problems with this generating folders within the archive. Here is my humble solution to the problem:

    //add the files
    foreach($valid_files as $file) {
    $base = basename($file);
    $zip->addFile($file,$base);
    }

  67. Awesome tutorial! And thanks to Phatnoir for the tip on making it a flat zip file without the directories!

  68. Neill

    Hi there,

    I have copied this function and it’s working fine. Although when go to extract the files, I’m getting that file is corrupted (Failed CRC check).

    Any clues on why is this happening? Could it be the library version?

    Thanks,

    Neill

  69. Granados

    Hi, I used this script, and it generated a zip file, but I couldn’t extract it, and it contained along with my files these single dot and double dot files in it. I made the following modification to the code in order to exclude them from the array.


    foreach ($iterator as $key=>$value) {
    if(substr($key,-1) != '.' && substr($key,-2) != '..'){
    $t.= $key." ";
    $zip->addFile(realpath($key), $key) or die ("ERROR: Could not add file: $key");
    }

  70. Granados

    Whops, sorry, I made a mistake, instead of the double dots, put a single one inside the if.

  71. tttony

    Very good!!

    The copy function does not works very well, copy the code but doing some changes inside the code

  72. saranya

    hi,
    thanx for the code..really working fine in windows..but this same code not working when i use linux…pls help this problem..thanx in advance

    Regards,
    saran..

  73. Lolki

    Saranya. If you dont give more information, nobody will help you.
    What is your problem? Did you try to print some debugging variables? What does it say?

  74. saranya

    sorry pls ignore the code..

  75. saranya

    In linux server zip file will not create..above code is used by me in linux sever…

  76. Lolki

    Doesnt help me much if you dont output some debug info. Uncomment them in the code.

  77. Serj

    Hello David =)

    Thank You very much for useful function.

    Sincerely, Serj.

  78. JamesC

    Sorry, but this doesn’t work for me… Could you give us some more sample code?

    I’m currently using following script (obviously I’ve included the big script above this):

    $files_to_zip = array(
    ROOT_URL.$URL_ORIGINAL
    );
    //if true, good; if false, zip creation failed
    $result = create_zip($files_to_zip,$URL_ZIP);
    if($result) {
    echo ‘Download‘;
    }

  79. Deepali

    I want to upload multiple files and should be save in zip file..
    can anyone tell me d php code for my requirement??

  80. David you are a monster… yet again, thanks from the UK.

  81. Drew Wesley

    Can the destination parameter be cached in memory or in a temporary directory instead of an actual location? If not, unlink() is cool – I’m just trying to avoid having to write to disk for a download.

  82. Surya

    It does not work for me

    open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
          return false;
        }
        //add the files
        foreach($valid_files as $file) {
          $zip->addFile($file,$file);
        }
        //debug
        //echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
        
        //close the zip -- done!
        $zip->close();
        
        //check to make sure the file exists
        return file_exists($destination);
      }
      else
      {
        return false;
      }
    }
    
    $files_to_zip = array();
    //getting the relative path along with the file through POST from a HTML form
    foreach($_POST['song'] as $fileabc)
    {
    $files_to_zip[]=$fileabc;
    }
    //if true, good; if false, zip creation failed
    $result = create_zip($files_to_zip,'my-archive.zip');
    if($result==true)echo "Success"; else echo "failed";
    ?>
    
  83. Really Really nice code & expert solution.
    I am very glad to found this code.

    Thanks a loooottt

    Rizwan

  84. subhojit777

    I am running this code snippet in my Drupal website, but its not working. Till $zip->addFile($file, $file) its working fine i.e. I can see the result 1 in log file(error_log()). But, $zip->close() is returning null, I mean nothing just blank not even a boolean value or 0/1, hence the zip file is not created. I don’t know what I am doing wrong.
    One more thing $zip->status is returning 0, don’t know what it means, proper comments were missing in your code snippet and in the php’s website.

  85. SAFAD

    to everyone having status 0 issue, and archive not created, give the function an array instead of a string containing file name :
    correct usage;
    $file = array(‘file.txt’);
    create_zip($file,$dest);
    incorrect usage;
    $file = ‘file.txt’;
    create_zip($file,$dest);

  86. David you rock and so as your tutorials. I find your tutorials funny [ i don’t know why ] . may be because of your website design or i don’t know why.

  87. Superb tutorial! I’d never delved into this before, and it’s exactly what I was looking for. Many thanks!

  88. Niko

    Hi!
    Sorry about this post, cause I posted it in wrong place, but anyways – I liked the “codehighlighter” plug-in of your WordPress, could you tell me the plug-in’s exact name?

  89. you can try this code

  90. I think it’d be better to use is_file() instead of file_exists(), because file_exists() will return true if you accidentally pass it a directory. is_file() only returns true if the parameter is a real file and it exists.

  91. Pamela Jacobs

    Thank you for your article. I am having a problem unzipping an archive via php zipArchive. No matter what I try I can only get one of the files to come out. (Two in the zip.) I am essentially new to php and have tried every tutorial and idea and example on every site I can find. I am just doing something wrong. Any time it actually does something it brings one of the files out and then hangs as if loading on my local host. It is like it never finishes the file. Another thing… I would assume that it would bring the files out in alphabetical order, (files are names AmazonExport.csv and StandardExport.csv) yet the only file ever brought out is StandardExport. Is it bringing them both… but for some reason only writing the last one and then waiting around for something else to happen? Any assistance would be awesome!

    This is what I have at this moment… I am changing the code trying new things every few minutes….

    $input_zip = "ItemExport.zip" ;
    $target_dir = "./" ;
    $zip = new ZipArchive;
    $res = $zip->open($input_zip);
    if ($res === TRUE)
    {
    $zip->extractTo($target_dir);
    $zip->close();
    }
    else {
    die("Failed");
    }

    • Hey, Pamela. Have you tried to extract one file at a time?

      Something like this, might help you. :)

      $path = 'zipfile.zip'
      $zip = new ZipArchive;
      if ($zip->open($path) === true) {
          for($i = 0; $i numFiles; $i++) {
              $zip->extractTo('path/to/extraction/', array($zip->getNameIndex($i)));
              // here you can run a custom function for the particular extracted file                
          }    
          $zip->close();         
      }
      
  92. Maen

    Good job, thanks

  93. This is very useful, Thank you.

  94. Thanks David for this useful post – the only reason I am actually doing this is because I have download limits on my ISP and I have to keep downloading 100mb log files.

    You just maybe helped me from being throttled.

  95. Roy

    very useful! im using this to make backups on a website since I have only ftp access
    great post !

  96. For those of you on Mediatemple who got the error – Class ‘ZipArchive’ not found – below is a link to a very handy tutorial on how to install it on the MT gridservers. I just did it successfully, and the code now works.

    http://wiki.mediatemple.net/w/(gs):Install_Zip_for_PHP_5

  97. hi,
    i’ve copied this tutorial with no changes, but i get the error:

    The zip archive contains 100 files with a status of 0 failed to save

    not at all sure why.

  98. Dude

    Thanks, just saved my day!

  99. Vikash Pathak

    Thanks, its useful.

  100. Once again I end up finding the solution on davidwalsh.name!!

    Your website has had the exact info I needed so many times, it’s unbelievable that you are “just” one person… I put your website in the same line as experts exchange when it comes to finding the solution I was seeking :)

    Thanks!

  101. Arpita

    Hi All

    I am using this piece of code to create zip But now I want to slit the zip according to the size. I mean if the created zip is greater than 10 MB (say It is of 2 MB) It must break itself in pieces (In this case It must split in 2 pieces one of 10 mb and other one of 2 MB) Can any body help me with this

  102. Harpreet

    Thanks David. Very useful. Helped me a lot.

  103. Old, but it’s still helpful, thank you very much !

  104. Thanks David, I modified your code some to allow my users to zip and download images from my site, i’ll post it here in case anyone can use it thanks again!

    //THIS IS DOWNLOAD.PHP
    include("create_zip.php");
    if(isset($_POST['zip_files'])){
    if(isset($_POST['zip'])){
    $url5 = $_POST['url5'];
    	$files_to_zip = $_POST['zip'];
    	$result = create_zip($files_to_zip, 'my-archive.zip', true);
    	//print $url5;
    	header('location:my-archive.zip');
    	//print $files;
    }else{
    header("location:".$_SERVER['HTTP_REFERER']."");
    }
    }
    
    
    
    //THIS IS CREATE_ZIP.PHP
    /* creates a compressed zip file */
    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
    		//echo 'The zip archive contains ',$zip->numFiles,' files with a status of ',$zip->status;
    		
    		//close the zip -- done!
    		$zip->close();
    		
    		//check to make sure the file exists
    		return file_exists($destination);
    	}
    	else
    	{
    		return false;
    	}
    }
    

    This all works off of checkbox inputs from record pulled from a database.
    Hope it helps someone!

  105. Hi, I am just wondering how do you if the files are located in a different host?
    Thanks

  106. Shijin

    Hi David,

    which is the best zip method based on compression size?

  107. JAYDIP

    i want to know that how to set session in all php file.i request you to please tell me or guide me sir.thank you.

  108. Thanks for this great article! It worked like a charm the first time I used it!

  109. gayathri

    Thanks, it helped me a lot.

  110. Haithem

    Nice Work so much helpfull !!!

  111. Hi, nice script.
    I had the problem, that $zip->close(); did not created a file on some servers. This issue occurs often if we created a big zip file with about 35000 files. We made some changes, now it works!

    You should check if file exists and is readable (file_exists($file) and is_readable($file)) before you call $zip->addFile!!!!
    Thanks! And hope this helps a bit ;)

  112. John

    I tried to zip files using absolute paths like this: but doesn’t work. I need to use direct paths as my files are in different locations.

    Any ideas how i can fix this?

    $files_to_zip = array(
        '/var/www/html/pdf/file1.pdf',
        '/var/www/html/pdf/file2.pdf'
    );
    
  113. Brian

    David,

    Nice snippet! This might have been covered in the comments, but I’m not one to fish through comments, especially if there are a lot.

    Your example would give me a empty zip, and I noticed the simple solution, and thought you might want to edit you post to save others time

    addFile was missing basename(), and using the file path for both

    $zip->addFile($file,basename($file));

  114. You can replace

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

    with

    $valid_files = array_filter($files, 'file_exists');
    
  115. Ignacio

    Hi! nice function, in my case I add this line in your function.. otherwise if you add files in different location than the script, you get a strange behavior

    $info=pathinfo($file);
    $zip->addFile($file,$info['basename']);
    
    • $zip->addFile($file,basename($file)); is less code.

  116. I prefer lean code, so I do the same thing in one line:

    exec("zip -r archive.zip /some/folder/* 2>&1 &", $return, $code);
  117. Maria

    Hello! Sorry if I ask something stupid but I am new to PHP. How can I use this? I will write the function inside :

    /* creates a compressed zip file */

    And then how will I call it? I will add this inside body?:
    files_to_zip = array(
    ‘image1.jpg’,
    ‘image2.jpg’
    );
    $result = create_zip($files_to_zip,’my-archive.zip’);

  118. Arpita

    Hi Maria your question is not clear,

    Do you mean You have a file Some thing like as Follows

    //You have your script here
    Function create_zip(){
    // Function to create zip is written here
    }
    // And then  You have following code
    
    
    files_to_zip = array(
    ‘image1.jpg’,
    ‘image2.jpg’
    );
    $result = create_zip($files_to_zip,’my-archive.zip’);
    

    If yes Then this is absolutely correct did you tried executing this code on server?. What happened

  119. Nice snippet David and thank you.
    If you set the $overwrite to true and the file doesn’t exist in the first place it doesn’t get created. No big issue.

    I’d love to see a function that accepts an array of files to go to a folder WITHIN an archive and some files in the parent (root) of the archive.

    Any thoughts???

    • Lance, I kinda solved the first issue you mentioned where the zip file doesn’t get created if overwrite is set to true. Not fancy, but works:

      // FIX : Prevent zip from trying to overwrite an unexisting file
      $overwrite = file_exists($destination)? $overwrite : false;
      if($zip->open($destination,$overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
      	return false;
      }
      
  120. Alex

    Hi,

    I’m new in PHP, and I’m triyng to find a solution to automaticaly put uploaded images in a zip file.

    But not all images sizes, just some image size created by add_image_size.

    For instance I would like to put in a zip file the full_image size but not thumbnail size of a same image. The thumbnail size would be displayed as an attachement on single posts.

    Is your snippet can do that?

    Sorry for this stupid question…

    Alex

  121. Nikola

    Thanks, working great. You save my life.

  122. ben b

    I am hoping to use this but looking for a little insight. My site is WordPress, and I am putting all of the original code from the post in my functions.php file. I’ve added a few files to the array like:

    $files_to_zip = array(
    	'http://tripletigers.com/1662917186196/wp-content/uploads/Same-Truck-CoverNoTitle-1920x1920.jpg',
    	'uploads/Same-Truck-CoverNoTitle-1920x1920.jpg'
    );
    //if true, good; if false, zip creation failed
    $result = create_zip($files_to_zip,'my-archive.zip');
    

    And my question is, should i get this zip created on load of any page in the site? That would be fine for now. And where should the zip file be? I don’t see it anywhere and not sure how to get started.

    My PHP experience is so-so.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!