Thursday, July 24, 2014

Handling Zip Archives in PHP - I

Handling ZIP archives, like reading an archive, extracting files from it or putting some files into a ZIP archive etc can be done very easily with PHP. PHP provides the ZipArchive class to create and read zip files. Please make sure that ZIP extension is installed with your version of PHP. So, let's just start with a small piece of code which creates a ZIP archive and put some files in it.

So, here is our first code snippet ... which creates a Zip archive and puts some files into it.

<?php
// First Create Object of the class ZipArchive
$archive = new ZipArchive;

// Now create an Archive 
$result = $archive->open("our_zip.zip", ZipArchive::CREATE);

// Check if the Archive was created successfully
if($result == 1)
{
  // Put a file into it
  $archive->addFile('a.txt', 'apple.txt'); 
  
  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

So, here is what we did ..

i. Created an object of the ZipArchive class
ii. Called open() method of that class to create our archive
iii. Added a file into the archive by calling addFile() method
iv. And finally we closed the Archive by calling close() method. 

The open() method takes various FLAGs as second argument. These FLAGs are described below.

ZipArchive::CREATE - Create Archive if it does not exist
ZipArchive::OVERWRITE - Overwrite existing Archive
ZipArchive::EXCL - Return error if the Archive already exists. 
ZipArchive::CHECKCONS - Perform additional consistency checks on Archives. Return Error if these checks fail.

If open() method worked perfectly, it returns 1 otherwise various Error codes/FLAGs described below. "ER_" prefix is for errors.

ZipArchive::ER_EXISTS - File exists - 10
ZipArchive::ER_INCONS - Inconsistent Archive - 21
ZipArchive::ER_INVAL  - Invalid arguments - 18 
ZipArchive::ER_MEMORY - Memory allocation failure - 14
ZipArchive::ER_NOENT  - File does not exist - 9 
ZipArchive::ER_NOZIP  - Not a zip archive - 19
ZipArchive::ER_OPEN   - File opening error - 11
ZipArchive::ER_READ   - File reading error - 5
ZipArchive::ER_SEEK   - Seek Error - 4

Let's complicate stuffs a bit more. In our second example, we add a file "b.txt" to the existing Archive "our_zip.zip" but inside a folder 'balloon'.

<?php
// First Create Object of the class ZipArchive
$archive = new ZipArchive;

// Now use existing Archive our_zip.zip
// See that we dont use any FLAG with open() method
$result = $archive->open("our_zip.zip");

// Check if the Archive Open was success
if($result == 1)
{
  // Put a file inside 'balloon' folder
  $archive->addFile('b.txt', 'balloon/balloon.txt'); 
  
  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

Was not a big deal at all, this piece of code was self-describing... So, now our sample Archive holds the following files ...

apple.txt
balloon/balloon.txt

Let's Add some Content manually to that ZIP archive. We need to use addFromString() method here. See example below..

<?php
// ... create class etc etc

// Build the String
$str = "This is a Sample String, it will be saved in a file called c.txt";

// Write the string as a file c.txt
$archive->addFromString('custom/text/c.txt', 'file content goes here');
?>

The code above would create a file custom/text/c.txt inside that zip archive (in custom/text folder) and write the content of $str variable inside it.

Next, we would browse a folder for some Image files, then put them into a Zip file. This may sometimes come very handy in a situation where a user selects some photos (or PDFs or mixed) on our website and wants them to be downloaded in a zip archive. We would use the ZipArchive class' addGlob() method. 

The scenario :: We have couple of images at the current folder, and we also have some more images in a folder called "test_images". Now, we want to take all the images ( including those in test_images folder ), create a new folder "images" inside the ZIP Archive and put into them. Check out the code below.


<?php
// First Create a new Object of the class ZipArchive
$archive = new ZipArchive;

// Now create an Archive 
$result = $archive->open("our_zip.zip", ZipArchive::OVERWRITE);

// Check if the Archive was created successfully
if($result == 1)
{
  // Set some basic Options for addGlob() method
  $options = array('add_path' => 'images/', 'remove_all_path' => TRUE);
  
  // Now use the Glob() pattern to add all images from current path
  $archive->addGlob('*.{png,jpg,jpeg,gif,bmp}', GLOB_BRACE, $options);
  
  // Add all images under a folder 'test_images'
  $archive->addGlob('test_images/*.{png,jpg,jpeg,gif,bmp}', GLOB_BRACE, $options); 
  
  // Close the Archive
  $archive->close();
}
else
{
  echo "Archive creation Error [Error code : $result]";
}
?>

This code is also very simple. We have used an array $options to create necessary options for the addGlob() method. 

i. 'add_path' => 'images/' means we wanted to create a new path 'images' inside the Archive
ii. 'remove_all_path'=>TRUE means even if we take files from 'folder1' or 'folder2' or 'test_images' ( as found by glob() ), these folder paths will be removed

addGlob() method is taking a pattern as first parameter. Check this statement once again ::

$archive->addGlob('test_images/*.{png,jpg,jpeg,gif,bmp}', GLOB_BRACE, $options); 

GLOB_BRACE flag is used to match any of the extensions provided within the curly braces {}. For more on how Filesystem's glob() function works and glob patterns, check the article Using GLOB in PHP.

We have a ZipArchive method called addEmptyDir() to create empty folders inside the Archive. Check out the statement below :

$archive->addEmptyDir("test_folder");

So, this is actually pretty simple. Check this blog for more on handling ZIP archives in PHP.

In our next article, Handling Zip Archives in PHP - II, we discuss on extracting/renaming/deleting files from the Archive.

No comments: