File indexing completed on 2024-12-22 05:36:41

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Filter
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 /**
0023  * @see Zend_Filter_Compress_CompressAbstract
0024  */
0025 // require_once 'Zend/Filter/Compress/CompressAbstract.php';
0026 
0027 /**
0028  * Compression adapter for zip
0029  *
0030  * @category   Zend
0031  * @package    Zend_Filter
0032  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0033  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0034  */
0035 class Zend_Filter_Compress_Zip extends Zend_Filter_Compress_CompressAbstract
0036 {
0037     /**
0038      * Compression Options
0039      * array(
0040      *     'archive'  => Archive to use
0041      *     'password' => Password to use
0042      *     'target'   => Target to write the files to
0043      * )
0044      *
0045      * @var array
0046      */
0047     protected $_options = array(
0048         'archive' => null,
0049         'target'  => null,
0050     );
0051 
0052     /**
0053      * Class constructor
0054      *
0055      * @param string|array $options (Optional) Options to set
0056      */
0057     public function __construct($options = null)
0058     {
0059         if (!extension_loaded('zip')) {
0060             // require_once 'Zend/Filter/Exception.php';
0061             throw new Zend_Filter_Exception('This filter needs the zip extension');
0062         }
0063         parent::__construct($options);
0064     }
0065 
0066     /**
0067      * Returns the set archive
0068      *
0069      * @return string
0070      */
0071     public function getArchive()
0072     {
0073         return $this->_options['archive'];
0074     }
0075 
0076     /**
0077      * Sets the archive to use for de-/compression
0078      *
0079      * @param string $archive Archive to use
0080      * @return Zend_Filter_Compress_Rar
0081      */
0082     public function setArchive($archive)
0083     {
0084         $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $archive);
0085         $this->_options['archive'] = (string) $archive;
0086 
0087         return $this;
0088     }
0089 
0090     /**
0091      * Returns the set targetpath
0092      *
0093      * @return string
0094      */
0095     public function getTarget()
0096     {
0097         return $this->_options['target'];
0098     }
0099 
0100     /**
0101      * Sets the target to use
0102      *
0103      * @param string $target
0104      * @return Zend_Filter_Compress_Rar
0105      */
0106     public function setTarget($target)
0107     {
0108         if (!file_exists(dirname($target))) {
0109             // require_once 'Zend/Filter/Exception.php';
0110             throw new Zend_Filter_Exception("The directory '$target' does not exist");
0111         }
0112 
0113         $target = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $target);
0114         $this->_options['target'] = (string) $target;
0115         return $this;
0116     }
0117 
0118     /**
0119      * Compresses the given content
0120      *
0121      * @param  string $content
0122      * @return string Compressed archive
0123      */
0124     public function compress($content)
0125     {
0126         $zip = new ZipArchive();
0127         $res = $zip->open($this->getArchive(), ZipArchive::CREATE | ZipArchive::OVERWRITE);
0128 
0129         if ($res !== true) {
0130             // require_once 'Zend/Filter/Exception.php';
0131             throw new Zend_Filter_Exception($this->_errorString($res));
0132         }
0133 
0134         if (file_exists($content)) {
0135             $content  = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content));
0136             $basename = substr($content, strrpos($content, DIRECTORY_SEPARATOR) + 1);
0137             if (is_dir($content)) {
0138                 $index    = strrpos($content, DIRECTORY_SEPARATOR) + 1;
0139                 $content .= DIRECTORY_SEPARATOR;
0140                 $stack    = array($content);
0141                 while (!empty($stack)) {
0142                     $current = array_pop($stack);
0143                     $files   = array();
0144 
0145                     $dir = dir($current);
0146                     while (false !== ($node = $dir->read())) {
0147                         if (($node == '.') || ($node == '..')) {
0148                             continue;
0149                         }
0150 
0151                         if (is_dir($current . $node)) {
0152                             array_push($stack, $current . $node . DIRECTORY_SEPARATOR);
0153                         }
0154 
0155                         if (is_file($current . $node)) {
0156                             $files[] = $node;
0157                         }
0158                     }
0159 
0160                     $local = substr($current, $index);
0161                     $zip->addEmptyDir(substr($local, 0, -1));
0162 
0163                     foreach ($files as $file) {
0164                         $zip->addFile($current . $file, $local . $file);
0165                         if ($res !== true) {
0166                             // require_once 'Zend/Filter/Exception.php';
0167                             throw new Zend_Filter_Exception($this->_errorString($res));
0168                         }
0169                     }
0170                 }
0171             } else {
0172                 $res = $zip->addFile($content, $basename);
0173                 if ($res !== true) {
0174                     // require_once 'Zend/Filter/Exception.php';
0175                     throw new Zend_Filter_Exception($this->_errorString($res));
0176                 }
0177             }
0178         } else {
0179             $file = $this->getTarget();
0180             if (!is_dir($file)) {
0181                 $file = basename($file);
0182             } else {
0183                 $file = "zip.tmp";
0184             }
0185 
0186             $res = $zip->addFromString($file, $content);
0187             if ($res !== true) {
0188                 // require_once 'Zend/Filter/Exception.php';
0189                 throw new Zend_Filter_Exception($this->_errorString($res));
0190             }
0191         }
0192 
0193         $zip->close();
0194         return $this->_options['archive'];
0195     }
0196 
0197     /**
0198      * Decompresses the given content
0199      *
0200      * @param  string $content
0201      * @return string
0202      */
0203     public function decompress($content)
0204     {
0205         $archive = $this->getArchive();
0206         if (file_exists($content)) {
0207             $archive = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, realpath($content));
0208         } elseif (empty($archive) || !file_exists($archive)) {
0209             // require_once 'Zend/Filter/Exception.php';
0210             throw new Zend_Filter_Exception('ZIP Archive not found');
0211         }
0212 
0213         $zip = new ZipArchive();
0214         $res = $zip->open($archive);
0215 
0216         $target = $this->getTarget();
0217 
0218         if (!empty($target) && !is_dir($target)) {
0219             $target = dirname($target);
0220         }
0221 
0222         if (!empty($target)) {
0223             $target = rtrim($target, '/\\') . DIRECTORY_SEPARATOR;
0224         }
0225 
0226         if (empty($target) || !is_dir($target)) {
0227             // require_once 'Zend/Filter/Exception.php';
0228             throw new Zend_Filter_Exception('No target for ZIP decompression set');
0229         }
0230 
0231         if ($res !== true) {
0232             // require_once 'Zend/Filter/Exception.php';
0233             throw new Zend_Filter_Exception($this->_errorString($res));
0234         }
0235 
0236         if (version_compare(PHP_VERSION, '5.2.8', '<')) {
0237             for ($i = 0; $i < $zip->numFiles; $i++) {
0238                 $statIndex = $zip->statIndex($i);
0239                 $currName = $statIndex['name'];
0240                 if (($currName{0} == '/') ||
0241                     (substr($currName, 0, 2) == '..') ||
0242                     (substr($currName, 0, 4) == './..')
0243                     )
0244                 {
0245                     // require_once 'Zend/Filter/Exception.php';
0246                     throw new Zend_Filter_Exception('Upward directory traversal was detected inside ' . $archive
0247                         . ' please use PHP 5.2.8 or greater to take advantage of path resolution features of '
0248                         . 'the zip extension in this decompress() method.'
0249                         );
0250                 }
0251             }
0252         }
0253 
0254         $res = @$zip->extractTo($target);
0255         if ($res !== true) {
0256             // require_once 'Zend/Filter/Exception.php';
0257             throw new Zend_Filter_Exception($this->_errorString($res));
0258         }
0259 
0260         $zip->close();
0261         return $target;
0262     }
0263 
0264     /**
0265      * Returns the proper string based on the given error constant
0266      *
0267      * @param string $error
0268      */
0269     protected function _errorString($error)
0270     {
0271         switch($error) {
0272             case ZipArchive::ER_MULTIDISK :
0273                 return 'Multidisk ZIP Archives not supported';
0274 
0275             case ZipArchive::ER_RENAME :
0276                 return 'Failed to rename the temporary file for ZIP';
0277 
0278             case ZipArchive::ER_CLOSE :
0279                 return 'Failed to close the ZIP Archive';
0280 
0281             case ZipArchive::ER_SEEK :
0282                 return 'Failure while seeking the ZIP Archive';
0283 
0284             case ZipArchive::ER_READ :
0285                 return 'Failure while reading the ZIP Archive';
0286 
0287             case ZipArchive::ER_WRITE :
0288                 return 'Failure while writing the ZIP Archive';
0289 
0290             case ZipArchive::ER_CRC :
0291                 return 'CRC failure within the ZIP Archive';
0292 
0293             case ZipArchive::ER_ZIPCLOSED :
0294                 return 'ZIP Archive already closed';
0295 
0296             case ZipArchive::ER_NOENT :
0297                 return 'No such file within the ZIP Archive';
0298 
0299             case ZipArchive::ER_EXISTS :
0300                 return 'ZIP Archive already exists';
0301 
0302             case ZipArchive::ER_OPEN :
0303                 return 'Can not open ZIP Archive';
0304 
0305             case ZipArchive::ER_TMPOPEN :
0306                 return 'Failure creating temporary ZIP Archive';
0307 
0308             case ZipArchive::ER_ZLIB :
0309                 return 'ZLib Problem';
0310 
0311             case ZipArchive::ER_MEMORY :
0312                 return 'Memory allocation problem while working on a ZIP Archive';
0313 
0314             case ZipArchive::ER_CHANGED :
0315                 return 'ZIP Entry has been changed';
0316 
0317             case ZipArchive::ER_COMPNOTSUPP :
0318                 return 'Compression method not supported within ZLib';
0319 
0320             case ZipArchive::ER_EOF :
0321                 return 'Premature EOF within ZIP Archive';
0322 
0323             case ZipArchive::ER_INVAL :
0324                 return 'Invalid argument for ZLIB';
0325 
0326             case ZipArchive::ER_NOZIP :
0327                 return 'Given file is no zip archive';
0328 
0329             case ZipArchive::ER_INTERNAL :
0330                 return 'Internal error while working on a ZIP Archive';
0331 
0332             case ZipArchive::ER_INCONS :
0333                 return 'Inconsistent ZIP archive';
0334 
0335             case ZipArchive::ER_REMOVE :
0336                 return 'Can not remove ZIP Archive';
0337 
0338             case ZipArchive::ER_DELETED :
0339                 return 'ZIP Entry has been deleted';
0340 
0341             default :
0342                 return 'Unknown error within ZIP Archive';
0343         }
0344     }
0345 
0346     /**
0347      * Returns the adapter name
0348      *
0349      * @return string
0350      */
0351     public function toString()
0352     {
0353         return 'Zip';
0354     }
0355 }