1 <?php
  2 /**
  3  * @package     Joomla.Platform
  4  * @subpackage  Archive
  5  *
  6  * @copyright   Copyright (C) 2005 - 2017 Open Source Matters, Inc. All rights reserved.
  7  * @license     GNU General Public License version 2 or later; see LICENSE
  8  */
  9 
 10 defined('JPATH_PLATFORM') or die;
 11 
 12 jimport('joomla.filesystem.file');
 13 jimport('joomla.filesystem.stream');
 14 
 15 /**
 16  * Bzip2 format adapter for the JArchive class
 17  *
 18  * @since  11.1
 19  */
 20 class JArchiveBzip2 implements JArchiveExtractable
 21 {
 22     /**
 23      * Bzip2 file data buffer
 24      *
 25      * @var    string
 26      * @since  11.1
 27      */
 28     private $_data = null;
 29 
 30     /**
 31      * Extract a Bzip2 compressed file to a given path
 32      *
 33      * @param   string  $archive      Path to Bzip2 archive to extract
 34      * @param   string  $destination  Path to extract archive to
 35      * @param   array   $options      Extraction options [unused]
 36      *
 37      * @return  boolean  True if successful
 38      *
 39      * @since   11.1
 40      * @throws  RuntimeException
 41      */
 42     public function extract($archive, $destination, array $options = array())
 43     {
 44         $this->_data = null;
 45 
 46         if (!extension_loaded('bz2'))
 47         {
 48             $this->raiseWarning(100, 'The bz2 extension is not available.');
 49         }
 50 
 51         if (isset($options['use_streams']) && $options['use_streams'] != false)
 52         {
 53             return $this->extractStream($archive, $destination, $options);
 54         }
 55 
 56         // Old style: read the whole file and then parse it
 57         $this->_data = file_get_contents($archive);
 58 
 59         if (!$this->_data)
 60         {
 61             return $this->raiseWarning(100, 'Unable to read archive');
 62         }
 63 
 64         $buffer = bzdecompress($this->_data);
 65         unset($this->_data);
 66 
 67         if (empty($buffer))
 68         {
 69             return $this->raiseWarning(100, 'Unable to decompress data');
 70         }
 71 
 72         if (JFile::write($destination, $buffer) === false)
 73         {
 74             return $this->raiseWarning(100, 'Unable to write archive');
 75         }
 76 
 77         return true;
 78     }
 79 
 80     /**
 81      * Method to extract archive using stream objects
 82      *
 83      * @param   string  $archive      Path to Bzip2 archive to extract
 84      * @param   string  $destination  Path to extract archive to
 85      * @param   array   $options      Extraction options [unused]
 86      *
 87      * @return  boolean  True if successful
 88      */
 89     protected function extractStream($archive, $destination, $options = array())
 90     {
 91         // New style! streams!
 92         $input = JFactory::getStream();
 93 
 94         // Use bzip
 95         $input->set('processingmethod', 'bz');
 96 
 97         if (!$input->open($archive))
 98         {
 99             return $this->raiseWarning(100, 'Unable to read archive (bz2)');
100 
101         }
102 
103         $output = JFactory::getStream();
104 
105         if (!$output->open($destination, 'w'))
106         {
107             $input->close();
108 
109             return $this->raiseWarning(100, 'Unable to write archive (bz2)');
110 
111         }
112 
113         do
114         {
115             $this->_data = $input->read($input->get('chunksize', 8196));
116 
117             if ($this->_data && !$output->write($this->_data))
118             {
119                 $input->close();
120 
121                 return $this->raiseWarning(100, 'Unable to write archive (bz2)');
122             }
123         }
124 
125         while ($this->_data);
126 
127         $output->close();
128         $input->close();
129 
130         return true;
131     }
132 
133     /**
134      * Temporary private method to isolate JError from the extract method
135      * This code should be removed when JError is removed.
136      *
137      * @param   int     $code  The application-internal error code for this error
138      * @param   string  $msg   The error message, which may also be shown the user if need be.
139      *
140      * @return  JException  JException instance if JError class exists
141      *
142      * @throws  RuntimeException if JError class does not exist
143      */
144     private function raiseWarning($code, $msg)
145     {
146         if (class_exists('JError'))
147         {
148             return JError::raiseWarning($code, $msg);
149         }
150 
151         throw new RuntimeException($msg);
152     }
153 
154     /**
155      * Tests whether this adapter can unpack files on this computer.
156      *
157      * @return  boolean  True if supported
158      *
159      * @since   11.3
160      */
161     public static function isSupported()
162     {
163         return extension_loaded('bz2');
164     }
165 }
166