18Dec/110
PHP Managing zip files with ZipArchive
Requirements
- PHP 5.2 or greater (would be a bit sad to know that someone is still using PHP 4)
- Upgrade PEAR to latest version
- Upgrade PECL to latest version
- Installing PHP ZipArchive library by using PECL's zip package
Installation
I will use pecl to install ZipArchive PHP library.
- Open terminal and execute pecl install zip
- Updating your php.ini:
- Linux: find your php.ini file and add "extension=zip.so"
- Windows: same as one, just add "extension=zip.dll"
- Restart httpd\apache
- service httpd restart
- apache2ctl restart
- or any other way that you like
Usage Example
There are many different ways to use and build Zip helpers. I will just demonstrate an example for using ZipArchive.
Pastebin: http://pastebin.com/J2M0jjQG
Inline...
/**
* ZipArchiveHelper class
*/
class ZipArchiveHelper {
/**
* @var ZipArchive $_zipArchive
*/
private $_zipArchive;
/**
* @var array $_excludeList
*/
private $_excludeList;
const TIMEOUT = 5000;
/**
* Get files list by path
* @param string $sourcePath
* @return RecursiveIteratorIterator
*/
private function _getFilesList($sourcePath){
$dirlist = new RecursiveDirectoryIterator($sourcePath);
$filelist = new RecursiveIteratorIterator($dirlist);
return $filelist;
}
/**
* Create Zip File
* @param string $zipFileName
* @param string $sourcePath
* @param array[optional] $excludeList
* @return string|false
*/
public function createZipFile($zipFileName,$sourcePath,array $excludeList = array()){
//Set PHP timeout
ini_set('max_execution_time', self::TIMEOUT);
//set exclude list
$this----->_excludeList = $excludeList;
//set new zip archive object
$this->_setZipArchive();
//generate new file
$this->_newZipFile($zipFileName);
//compress
$this->_compress($sourcePath);
//get status
$retValue = $this->_zipArchive->getStatusString();
//close zip archive manager
$this->_zipArchive->close();
return $retValue;
}
/**
* Set new ZipArchive instance
* Seperated and protected for future unit tests
* @return void
*/
protected function _setZipArchive(){
$this->_zipArchive = new ZipArchive;
}
/**
* Open new|existing zip file
* @param int $type - Overwrite by default. (you may use other options, e.g ZipArchive::CREATE)
* @throw Exception
* @return void
*/
protected function _newZipFile($zipFileName,$type=ZipArchive::OVERWRITE){
if ($this->_zipArchive->open("$zipFileName", $type) !== TRUE) {
throw new Exception("Could not open archive");
}
}
/**
* Validate file by checking if exists and not excluded type
* @param string $fileName
* @return bool
*/
private function _isValidFile($fileName){
if (!is_file($fileName)){
return false ;
}
foreach($this->_excludeList as $toExclude){
if (strpos($fileName,$toExclude) !== false){
return false;
}
}
return true;
}
/**
* Compress to ZIP file
* @return bool
*/
private function _compress($sourcePath){
//get file list
$filelist = $this->_getFilesList($sourcePath);
//add files to new zip file
foreach ($filelist as $fileName=>$value) {
if(!$this->_isValidFile($fileName)){
continue ;
}
//you should use sprintf for this to work on both *NIX and Windows OS
//note that str_replace is just for my example, you don't really have to use it.
$value = sprintf("%s",str_replace($sourcePath,'',$value));
if (!$this->_zipArchive->addFile($fileName,$value)){
throw new Exception("ERROR: Could not add file: $fileName");
}
}
return true;
}
}
//PHP >= 5.3 just throws this annoying warning
date_default_timezone_set('Asia/Jerusalem');
$zipHelper = new ZipArchiveHelper();
try {
var_dump($zipHelper->createZipFile(
'shakedos.zip',
'/tmp/zend_debug',
array('.svn')
));
} catch (Exception $e){
var_dump($e->getMessage());
}
Known Issues
- Did you define your PHP extension directory correct ?
- Windows and *NIX system works different by using the opposite slash "/"(*NIX) or "\"(Windows) - my solution is to use sprintf()
http://stackoverflow.com/questions/4620205/php-ziparchive-corrupt-in-windows - Downloading the script sometimes requires to send some different header, the following example was taken from the stackoverflow link above:
header("Cache-Control: public");
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public");
//header("Content-Description: File Transfer");
//header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=\"YOUR_FILE_NAME_HERE.zip\"");
//header("Content-Transfer-Encoding: binary");
header("Content-length: " . filesize($filename));
Hope I helped,