<?php
/**
* @version $Id: zip.helper.php 2301 2019-06-12 18:06:00Z IOS $
* @package Elxis
* @subpackage Helpers / Zip
* @copyright Copyright (c) 2006-2019 Elxis CMS (http://www.elxis.org). All rights reserved.
* @license Elxis Public License ( http://www.elxis.org/elxis-public-license.html )
* @author Elxis Team ( http://www.elxis.org )
* @description Elxis CMS is free software. Read the license for copyright notices and details
*/
defined('_ELXIS_') or die ('Direct access to this location is not allowed');
class elxisZipHelper {
private $zip_support = false;
private $zip = null;
private $errormsg = '';
/***************/
/* CONSTRUCTOR */
/***************/
public function __construct() {
$this->zip_support = class_exists('ZipArchive', false) ? true : false;
}
/******************************************/
/* GENERATE ERROR MESSAGE FROM ERROR CODE */
/******************************************/
private function errorMsgFromCode($res) {
switch ($res) {
case ZIPARCHIVE::ER_EXISTS: return 'Given archive already exists'; break;
case ZIPARCHIVE::ER_INVAL: return 'Invalid argument'; break;
case ZIPARCHIVE::ER_MEMORY: return 'Memory allocation failure'; break;
case ZIPARCHIVE::ER_INCONS: return 'Zip archive inconsistent'; break;
case ZIPARCHIVE::ER_NOENT: return 'No such file'; break;
case ZIPARCHIVE::ER_NOZIP: return 'Not a zip archive'; break;
case ZIPARCHIVE::ER_OPEN: return 'Could not open file'; break;
case ZIPARCHIVE::ER_READ: return 'Read error'; break;
case ZIPARCHIVE::ER_SEEK: return 'Seek error'; break;
case ZIPARCHIVE::ER_CRC: return 'CRC error'; break;
case ZIPARCHIVE::ER_WRITE: return 'Write error'; break;
case ZIPARCHIVE::ER_MULTIDISK : return 'Multi-disk zip archives not supported'; break;
case ZIPARCHIVE::ER_RENAME: return 'Renaming temporary file failed'; break;
case ZIPARCHIVE::ER_CLOSE: return 'Closing zip archive failed'; break;
case ZIPARCHIVE::ER_ZIPCLOSED: return 'Containing zip archive was closed'; break;
case ZIPARCHIVE::ER_TMPOPEN: return 'Failure to create temporary file'; break;
case ZIPARCHIVE::ER_ZLIB: return 'Zlib error'; break;
case ZIPARCHIVE::ER_CHANGED: return 'Entry has been changed'; break;
case ZIPARCHIVE::ER_COMPNOTSUPP: return 'Compression method not supported'; break;
case ZIPARCHIVE::ER_EOF: return 'Premature EOF'; break;
case ZIPARCHIVE::ER_INTERNAL: return 'Internal error'; break;
case ZIPARCHIVE::ER_REMOVE: return 'Could not remove file'; break;
case ZIPARCHIVE::ER_DELETED: return 'Entry has been deleted'; break;
case ZIPARCHIVE::ER_OK: return ''; break; //No error
default: return 'Unknown ZIP error'; break;
}
}
/********************************/
/* EXTRACT ARCHIVE TO DIRECTORY */
/********************************/
public function unzip($archive, $dir) {
if (!$this->zip_support) {
$this->errormsg = 'ZIP is not supported by your PHP installation!';
return false;
}
if (!file_exists($archive)) {
$this->errormsg = 'Given archive '.$archive.' does not exists!';
return false;
}
$dir = rtrim(str_replace("\\", "/", $dir), '/').'/';
if (!file_exists($dir)) {
$ok = @mkdir($dir, 0755);
if (!$ok) {
$this->errormsg = 'Could not create extract directory container '.$dir;
return false;
}
} else if (!is_dir($dir)) {
$this->errormsg = 'Extract path is not a directory '.$dir;
return false;
}
$archive = realpath($archive);
$this->zip = new ZipArchive();
$res = $this->zip->open($archive);
if ($res !== true) {
$this->errormsg = $this->errorMsgFromCode($res);
return false;
}
$ok = $this->zip->extractTo($dir);
$this->zip->close();
$this->zip = null;
if (!$ok) {
$this->errormsg = 'Could not extract zip to '.$dir;
return false;
}
return true;
}
/*********************/
/* GET ERROR MESSAGE */
/*********************/
public function getError() {
return $this->errormsg;
}
/*********************************************************/
/* ZIP FILE(S) OR FOLDER(S) OR BUFFERED DATA AND SAVE IT */
/*********************************************************/
public function zip($archive, $source=null, $data=array(), $paths_exclude=array()) {
if (!$this->zip_support) {
$this->errormsg = 'ZIP is not supported by your PHP installation!';
return false;
}
$topack = array();
if ($source !== null) {
if (is_string($source) && (trim($source) != '')) {
if (!file_exists($source)) {
$this->errormsg = 'Given source '.$source.' does not exists!';
return false;
}
$localname = basename($source);
$type = (is_dir($source)) ? 'folder' : 'file';
$topack[] = array('localname' => $localname, 'type' => $type, 'source' => $source);
} else if (is_array($source) && (count($source) > 0)) {
foreach ($source as $item) {
if (!file_exists($item)) {
$this->errormsg = 'Given source '.$item.' does not exists!';
return false;
}
$localname = basename($item);
if (is_dir($item)) {
$item = rtrim(str_replace(DIRECTORY_SEPARATOR, '/', $item), '/').'/';
$type = 'folder';
} else {
$type = 'file';
}
$topack[] = array('localname' => $localname, 'type' => $type, 'source' => $item);
}
}
}
if (is_array($data) && (count($data) > 0)) {
foreach ($data as $localname => $buffer) {
$topack[] = array('localname' => $localname, 'type' => 'buffer', 'source' => $buffer);
}
}
if (count($topack) == 0) {
$this->errormsg = 'Nothing provided to zip!';
return false;
}
$this->zip = new ZipArchive();
$res = $this->zip->open($archive, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE);
if ($res !== true) {
$this->errormsg = $this->errorMsgFromCode($res);
return false;
}
foreach ($topack as $pack) {
if ($pack['type'] == 'file') {
if ($paths_exclude) {
$exclude = false;
foreach ($paths_exclude as $xpath) {
if (strpos($pack['source'], $xpath) === 0) { $exclude = true; break; }
}
if ($exclude) { continue; }
}
$ok = $this->zip->addFile(realpath($pack['source']), $pack['localname']);
if (!$ok) {
$this->zip->close();
@unlink($archive);
$this->errormsg = 'Could not add '.$pack['source'].' in zip archive!';
return false;
}
} else if ($pack['type'] == 'folder') {
if ($paths_exclude) {
$exclude = false;
foreach ($paths_exclude as $xpath) {
if (strpos($pack['source'], $xpath) === 0) { $exclude = true; break; }
}
if ($exclude) { continue; }
}
$ok = $this->zip->addEmptyDir($pack['localname']);
if (!$ok) {
$this->zip->close();
@unlink($archive);
$this->errormsg = 'Could not create folder '.$pack['localname'].' in zip archive!';
return false;
}
$ok = $this->addFolderRecursive($pack['source'], $pack['localname'].'/', $paths_exclude);
if (!$ok) {
$this->zip->close();
@unlink($archive);
$this->errormsg = 'Could not zip folder '.$pack['source'].'!';
return false;
}
} else if ($pack['type'] == 'buffer') {
$ok = $this->zip->addFromString($pack['localname'], $pack['source']);
if (!$ok) {
$this->zip->close();
@unlink($archive);
$this->errormsg = 'Could not create '.$pack['localname'].' in zip archive!';
return false;
}
} else {
//invalid pack type!
}
}
$this->zip->close();
$this->zip = null;
return true;
}
/*********************************/
/* RECURSIVELY ADD FOLDER TO ZIP */
/*********************************/
private function addFolderRecursive($dir, $path, $paths_exclude=array()) {
$current_dir = @opendir($dir);
while ($entry = readdir($current_dir)) {
if (($entry != '.') && ($entry != '..')) {
if (is_dir($dir.$entry)) {
if ($paths_exclude) {
$exclude = false;
foreach ($paths_exclude as $xpath) {
if (strpos($dir.$entry.'/', $xpath) === 0) { $exclude = true; break; }
}
if ($exclude) { continue; }
}
if (!$this->zip->addEmptyDir($path.$entry.'/')) {
return false;
}
$this->addFolderRecursive($dir.$entry.'/', $path.$entry.'/', $paths_exclude);
} else {
if ($paths_exclude) {
$exclude = false;
foreach ($paths_exclude as $xpath) {
if (strpos($dir.$entry.'/', $xpath) === 0) { $exclude = true; break; }
}
if ($exclude) { continue; }
}
if (!$this->zip->addFile($dir.$entry, $path.$entry)) {
return false;
}
}
}
}
@closedir($current_dir);
return true;
}
}
?>