Browse files

Merge pull request #89 from dongilbert/ArchiveRefactor

Refactor Archive to be OO and add Documentation
  • Loading branch information...
2 parents 27d0fe6 + 73fca8c commit 5d5383f2893d0e41dd3ea0b3c0dae8116a38bd56 @eddieajau eddieajau committed Mar 25, 2013
View
200 vendor/Joomla/Archive/Archive.php
@@ -8,8 +8,6 @@
namespace Joomla\Archive;
-use Joomla\Factory;
-use Joomla\Filesystem\Path;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
@@ -26,7 +24,31 @@ class Archive
* @var array
* @since 1.0
*/
- protected static $adapters = array();
+ protected $adapters = array();
+
+ /**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ public $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ // Make sure we have a tmp directory.
+ isset($options['tmp_path']) or $options['tmp_path'] = realpath(sys_get_temp_dir());
+
+ $this->options = $options;
+ }
+
/**
* Extract an archive file to a directory.
@@ -39,126 +61,81 @@ class Archive
* @since 1.0
* @throws \InvalidArgumentException
*/
- public static function extract($archivename, $extractdir)
+ public function extract($archivename, $extractdir)
{
- $untar = false;
$result = false;
- $ext = File::getExt(strtolower($archivename));
-
- // Check if a tar is embedded...gzip/bzip2 can just be plain files!
- if (File::getExt(File::stripExt(strtolower($archivename))) == 'tar')
- {
- $untar = true;
- }
+ $ext = pathinfo($archivename, PATHINFO_EXTENSION);
+ $path = pathinfo($archivename, PATHINFO_DIRNAME);
+ $filename = pathinfo($archivename, PATHINFO_FILENAME);
switch ($ext)
{
case 'zip':
- $adapter = self::getAdapter('zip');
-
- if ($adapter)
- {
- $result = $adapter->extract($archivename, $extractdir);
- }
+ $result = $this->getAdapter('zip')->extract($archivename, $extractdir);
break;
case 'tar':
- $adapter = self::getAdapter('tar');
-
- if ($adapter)
- {
- $result = $adapter->extract($archivename, $extractdir);
- }
+ $result = $this->getAdapter('tar')->extract($archivename, $extractdir);
break;
case 'tgz':
- // This format is a tarball gzip'd
- $untar = true;
-
case 'gz':
case 'gzip':
// This may just be an individual file (e.g. sql script)
- $adapter = self::getAdapter('gzip');
+ $tmpfname = $this->options['tmp_path'] . '/' . uniqid('gzip');
+ $gzresult = $this->getAdapter('gzip')->extract($archivename, $tmpfname);
- if ($adapter)
+ if ($gzresult instanceof \Exception)
{
- $config = Factory::getConfig();
- $tmpfname = $config->get('tmp_path') . '/' . uniqid('gzip');
- $gzresult = $adapter->extract($archivename, $tmpfname);
-
- if ($gzresult instanceof \Exception)
- {
- @unlink($tmpfname);
-
- return false;
- }
-
- if ($untar)
- {
- // Try to untar the file
- $tadapter = self::getAdapter('tar');
-
- if ($tadapter)
- {
- $result = $tadapter->extract($tmpfname, $extractdir);
- }
- }
- else
- {
- $path = Path::clean($extractdir);
- Folder::create($path);
- $result = File::copy($tmpfname, $path . '/' . File::stripExt(basename(strtolower($archivename))), null, 1);
- }
-
@unlink($tmpfname);
+
+ return false;
+ }
+
+ if ($ext === 'tgz' || stripos($filename, '.tar') !== false)
+ {
+ $result = $this->getAdapter('tar')->extract($tmpfname, $extractdir);
+ }
+ else
+ {
+ Folder::create($path);
+ $result = File::copy($tmpfname, $extractdir, null, 0);
}
+
+ @unlink($tmpfname);
+
break;
case 'tbz2':
- // This format is a tarball bzip2'd
- $untar = true;
-
case 'bz2':
case 'bzip2':
// This may just be an individual file (e.g. sql script)
- $adapter = self::getAdapter('bzip2');
+ $tmpfname = $this->options['tmp_path'] . '/' . uniqid('bzip2');
+ $bzresult = $this->getAdapter('bzip2')->extract($archivename, $tmpfname);
- if ($adapter)
+ if ($bzresult instanceof \Exception)
{
- $config = Factory::getConfig();
- $tmpfname = $config->get('tmp_path') . '/' . uniqid('bzip2');
- $bzresult = $adapter->extract($archivename, $tmpfname);
-
- if ($bzresult instanceof \Exception)
- {
- @unlink($tmpfname);
-
- return false;
- }
-
- if ($untar)
- {
- // Try to untar the file
- $tadapter = self::getAdapter('tar');
-
- if ($tadapter)
- {
- $result = $tadapter->extract($tmpfname, $extractdir);
- }
- }
- else
- {
- $path = Path::clean($extractdir);
- Folder::create($path);
- $result = File::copy($tmpfname, $path . '/' . File::stripExt(basename(strtolower($archivename))), null, 1);
- }
-
@unlink($tmpfname);
+
+ return false;
}
+
+ if ($ext === 'tbz2' || stripos($filename, '.tar') !== false)
+ {
+ $result = $this->getAdapter('tar')->extract($tmpfname, $extractdir);
+ }
+ else
+ {
+ Folder::create($path);
+ $result = File::copy($tmpfname, $extractdir, null, 0);
+ }
+
+ @unlink($tmpfname);
+
break;
default:
- throw new \InvalidArgumentException('Unknown Archive Type');
+ throw new \InvalidArgumentException(sprintf('Unknown archive type: %s', $ext));
}
if (!$result || $result instanceof \Exception)
@@ -170,6 +147,33 @@ public static function extract($archivename, $extractdir)
}
/**
+ * Method to override the provided adapter with your own implementation.
+ *
+ * @param string $type Name of the adapter to set.
+ * @param string $class FQCN of your class which implements ExtractableInterface.
+ * @param object $override True to force override the adapter type.
+ *
+ * @return Archive This object for chaining.
+ *
+ * @since 1.0
+ * @throws \InvalidArgumentException
+ */
+ public function setAdapter($type, $class, $override = true)
+ {
+ if (!($class instanceof ExtractableInterface))
+ {
+ throw new \InvalidArgumentException(sprintf('The provided %s adapter %s must implement Joomla\\Archive\\ExtractableInterface', $type), 500);
+ }
+
+ if ($override || !isset($this->adapters[$type]))
+ {
+ $this->adapters[$type] = new $class($this->options);
+ }
+
+ return $this;
+ }
+
+ /**
* Get a file compression adapter.
*
* @param string $type The type of adapter (bzip2|gzip|tar|zip).
@@ -179,21 +183,23 @@ public static function extract($archivename, $extractdir)
* @since 1.0
* @throws \UnexpectedValueException
*/
- public static function getAdapter($type)
+ public function getAdapter($type)
{
- if (!isset(self::$adapters[$type]))
+ $type = strtolower($type);
+
+ if (!isset($this->adapters[$type]))
{
// Try to load the adapter object
$class = 'Joomla\\Archive\\' . ucfirst($type);
- if (!class_exists($class))
+ if (!class_exists($class) || !$class::isSupported())
{
- throw new \UnexpectedValueException(sprintf('Unable to load archive adapter %s.', $type) , 500);
+ throw new \UnexpectedValueException(sprintf('Archive adapter %s not found or supported.', $type), 500);
}
- self::$adapters[$type] = new $class;
+ $this->adapters[$type] = new $class($this->options);
}
- return self::$adapters[$type];
+ return $this->adapters[$type];
}
}
View
30 vendor/Joomla/Archive/Bzip2.php
@@ -27,27 +27,41 @@ class Bzip2 implements ExtractableInterface
private $data = null;
/**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ protected $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ $this->options = $options;
+ }
+
+ /**
* Extract a Bzip2 compressed file to a given path
*
* @param string $archive Path to Bzip2 archive to extract
* @param string $destination Path to extract archive to
- * @param array $options Extraction options [unused]
*
* @return boolean True if successful
*
* @since 1.0
* @throws \RuntimeException
*/
- public function extract($archive, $destination, array $options = array ())
+ public function extract($archive, $destination)
{
$this->data = null;
- if (!extension_loaded('bz2'))
- {
- throw new \RuntimeException('The bz2 extension is not available.');
- }
-
- if (!isset($options['use_streams']) || $options['use_streams'] == false)
+ if (!isset($this->options['use_streams']) || $this->options['use_streams'] == false)
{
// Old style: read the whole file and then parse it
$this->data = file_get_contents($archive);
View
2 vendor/Joomla/Archive/ExtractableInterface.php
@@ -26,7 +26,7 @@
*
* @since 1.0
*/
- public function extract($archive, $destination, array $options = array());
+ public function extract($archive, $destination);
/**
* Tests whether this adapter can unpack files on this computer.
View
31 vendor/Joomla/Archive/Gzip.php
@@ -41,27 +41,41 @@ class Gzip implements ExtractableInterface
private $data = null;
/**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ protected $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ $this->options = $options;
+ }
+
+ /**
* Extract a Gzip compressed file to a given path
*
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive to
- * @param array $options Extraction options [unused]
*
* @return boolean True if successful
*
* @since 1.0
* @throws \RuntimeException
*/
- public function extract($archive, $destination, array $options = array ())
+ public function extract($archive, $destination)
{
$this->data = null;
- if (!extension_loaded('zlib'))
- {
- throw new \RuntimeException('The zlib extension is not available.');
- }
-
- if (!isset($options['use_streams']) || $options['use_streams'] == false)
+ if (!isset($this->options['use_streams']) || $this->options['use_streams'] == false)
{
$this->data = file_get_contents($archive);
@@ -124,6 +138,7 @@ public function extract($archive, $destination, array $options = array ())
$output->close();
$input->close();
}
+
return true;
}
View
55 vendor/Joomla/Archive/README.md
@@ -1 +1,56 @@
# The Archive Package
+
+The archive package will intelligently load the correct adapter for the specified archive type. It knows how to properly handle the following archive types:
+
+- zip
+- tar | tgz | tbz2
+- gz | gzip
+- bz2 | bzip2
+
+Loading files of the `t*` archive type will uncompress the archive using the appropriate adapter, and then extract via tar.
+
+## Requirements
+
+- PHP 5.3+
+- zlib extension for GZip support
+- bz2 extension for BZip2 support
+
+## Usage
+
+```php
+
+$options = array('tmp_path' => '/tmp');
+
+$archive = new Archive($options)
+
+$archive->extract(__DIR__ . '/archive.zip', __DIR__ . '/destination');
+```
+
+## Overriding Adapters
+
+If you have a custom adapter you would like to use for extracting, this package allows you to override the defaults. Just implement `ExtractableInterface` when creating your adapter, and then use the `setAdapter` method to override.
+
+```php
+
+class MyZipAdapter implements \Joomla\Archive\ExtractableInterface
+{
+ public static function isSupported()
+ {
+ // Do you test
+ return true;
+ }
+
+ public function extract($archive, $destination)
+ {
+ // Your code
+ }
+}
+
+$archive = new Archive;
+
+// You need to pass the fully qualified class name.
+$archive->setAdapter('zip', '\\MyZipAdapter');
+
+// This will use your
+$archive->extract('archive.zip', 'destination');
+```
View
23 vendor/Joomla/Archive/Tar.php
@@ -59,18 +59,37 @@ class Tar implements ExtractableInterface
private $metadata = null;
/**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ protected $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ $this->options = $options;
+ }
+
+ /**
* Extract a ZIP compressed file to a given path
*
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive into
- * @param array $options Extraction options [unused]
*
* @return boolean True if successful
*
* @since 1.0
* @throws \RuntimeException
*/
- public function extract($archive, $destination, array $options = array())
+ public function extract($archive, $destination)
{
$this->data = null;
$this->metadata = null;
View
66 vendor/Joomla/Archive/Tests/ArchiveTest.php
@@ -11,7 +11,6 @@
use Joomla\Archive\Tar as ArchiveTar;
use Joomla\Archive\Gzip as ArchiveGzip;
use Joomla\Archive\Bzip2 as ArchiveBzip2;
-use Joomla\Factory;
/**
* Test class for Joomla\Archive\Archive.
@@ -20,7 +19,8 @@
*/
class ArchiveTest extends \PHPUnit_Framework_TestCase
{
- protected static $outputPath;
+ protected $fixture;
+ protected $outputPath;
/**
* Sets up the fixture.
@@ -33,12 +33,14 @@ protected function setUp()
{
parent::setUp();
- self::$outputPath = __DIR__ . '/output';
+ $this->outputPath = __DIR__ . '/output';
- if (!is_dir(self::$outputPath))
+ if (!is_dir($this->outputPath))
{
- mkdir(self::$outputPath, 0777);
+ mkdir($this->outputPath, 0777);
}
+
+ $this->fixture = new Archive;
}
/**
@@ -50,7 +52,7 @@ protected function setUp()
*/
public function testExtractZip()
{
- if (!is_dir(self::$outputPath))
+ if (!is_dir($this->outputPath))
{
$this->markTestSkipped("Couldn't create folder.");
@@ -64,12 +66,12 @@ public function testExtractZip()
return;
}
- Archive::extract(__DIR__ . '/logo.zip', self::$outputPath);
- $this->assertTrue(is_file(self::$outputPath . '/logo-zip.png'));
+ $this->fixture->extract(__DIR__ . '/logo.zip', $this->outputPath);
+ $this->assertTrue(is_file($this->outputPath . '/logo-zip.png'));
- if (is_file(self::$outputPath . '/logo-zip.png'))
+ if (is_file($this->outputPath . '/logo-zip.png'))
{
- unlink(self::$outputPath . '/logo-zip.png');
+ unlink($this->outputPath . '/logo-zip.png');
}
}
@@ -82,7 +84,7 @@ public function testExtractZip()
*/
public function testExtractTar()
{
- if (!is_dir(self::$outputPath))
+ if (!is_dir($this->outputPath))
{
$this->markTestSkipped("Couldn't create folder.");
@@ -96,12 +98,12 @@ public function testExtractTar()
return;
}
- Archive::extract(__DIR__ . '/logo.tar', self::$outputPath);
- $this->assertTrue(is_file(self::$outputPath . '/logo-tar.png'));
+ $this->fixture->extract(__DIR__ . '/logo.tar', $this->outputPath);
+ $this->assertTrue(is_file($this->outputPath . '/logo-tar.png'));
- if (is_file(self::$outputPath . '/logo-tar.png'))
+ if (is_file($this->outputPath . '/logo-tar.png'))
{
- unlink(self::$outputPath . '/logo-tar.png');
+ unlink($this->outputPath . '/logo-tar.png');
}
}
@@ -114,14 +116,14 @@ public function testExtractTar()
*/
public function testExtractGzip()
{
- if (!is_dir(self::$outputPath))
+ if (!is_dir($this->outputPath))
{
$this->markTestSkipped("Couldn't create folder.");
return;
}
- if (!is_writable(self::$outputPath) || !is_writable(Factory::getConfig()->get('tmp_path')))
+ if (!is_writable($this->outputPath) || !is_writable($this->fixture->options['tmp_path']))
{
$this->markTestSkipped("Folder not writable.");
@@ -135,12 +137,12 @@ public function testExtractGzip()
return;
}
- Archive::extract(__DIR__ . '/logo.gz', self::$outputPath . '/logo-gz.png');
- $this->assertTrue(is_file(self::$outputPath . '/logo-gz.png'));
+ $this->fixture->extract(__DIR__ . '/logo.gz', $this->outputPath . '/logo-gz.png');
+ $this->assertTrue(is_file($this->outputPath . '/logo-gz.png'));
- if (is_file(self::$outputPath . '/logo-gz.png'))
+ if (is_file($this->outputPath . '/logo-gz.png'))
{
- unlink(self::$outputPath . '/logo-gz.png');
+ unlink($this->outputPath . '/logo-gz.png');
}
}
@@ -153,14 +155,14 @@ public function testExtractGzip()
*/
public function testExtractBzip2()
{
- if (!is_dir(self::$outputPath))
+ if (!is_dir($this->outputPath))
{
$this->markTestSkipped("Couldn't create folder.");
return;
}
- if (!is_writable(self::$outputPath) || !is_writable(Factory::getConfig()->get('tmp_path')))
+ if (!is_writable($this->outputPath) || !is_writable($this->fixture->options['tmp_path']))
{
$this->markTestSkipped("Folder not writable.");
@@ -174,12 +176,12 @@ public function testExtractBzip2()
return;
}
- Archive::extract(__DIR__ . '/logo.bz2', self::$outputPath . '/logo-bz2.png');
- $this->assertTrue(is_file(self::$outputPath . '/logo-bz2.png'));
+ $this->fixture->extract(__DIR__ . '/logo.bz2', $this->outputPath . '/logo-bz2.png');
+ $this->assertTrue(is_file($this->outputPath . '/logo-bz2.png'));
- if (is_file(self::$outputPath . '/logo-bz2.png'))
+ if (is_file($this->outputPath . '/logo-bz2.png'))
{
- unlink(self::$outputPath . '/logo-bz2.png');
+ unlink($this->outputPath . '/logo-bz2.png');
}
}
@@ -192,13 +194,13 @@ public function testExtractBzip2()
*/
public function testGetAdapter()
{
- $zip = Archive::getAdapter('zip');
+ $zip = $this->fixture->getAdapter('zip');
$this->assertInstanceOf('Joomla\\Archive\\Zip', $zip);
- $bzip2 = Archive::getAdapter('bzip2');
+ $bzip2 = $this->fixture->getAdapter('bzip2');
$this->assertInstanceOf('Joomla\\Archive\\Bzip2', $bzip2);
- $gzip = Archive::getAdapter('gzip');
+ $gzip = $this->fixture->getAdapter('gzip');
$this->assertInstanceOf('Joomla\\Archive\\Gzip', $gzip);
- $tar = Archive::getAdapter('tar');
+ $tar = $this->fixture->getAdapter('tar');
$this->assertInstanceOf('Joomla\\Archive\\Tar', $tar);
}
@@ -212,6 +214,6 @@ public function testGetAdapter()
*/
public function testGetAdapterException()
{
- $zip = Archive::getAdapter('unknown');
+ $zip = $this->fixture->getAdapter('unknown');
}
}
View
40 vendor/Joomla/Archive/Zip.php
@@ -42,8 +42,16 @@ class Zip implements ExtractableInterface
* @var array
* @since 1.0
*/
- private $methods = array(0x0 => 'None', 0x1 => 'Shrunk', 0x2 => 'Super Fast', 0x3 => 'Fast', 0x4 => 'Normal', 0x5 => 'Maximum', 0x6 => 'Imploded',
- 0x8 => 'Deflated');
+ private $methods = array(
+ 0x0 => 'None',
+ 0x1 => 'Shrunk',
+ 0x2 => 'Super Fast',
+ 0x3 => 'Fast',
+ 0x4 => 'Normal',
+ 0x5 => 'Maximum',
+ 0x6 => 'Imploded',
+ 0x8 => 'Deflated'
+ );
/**
* Beginning of central directory record.
@@ -86,6 +94,26 @@ class Zip implements ExtractableInterface
private $metadata = null;
/**
+ * Holds the options array.
+ *
+ * @var mixed Array or object that implements \ArrayAccess
+ * @since 1.0
+ */
+ protected $options = array();
+
+ /**
+ * Create a new Archive object.
+ *
+ * @param mixed $options An array of options or an object that implements \ArrayAccess
+ *
+ * @since 1.0
+ */
+ public function __construct($options = array())
+ {
+ $this->options = $options;
+ }
+
+ /**
* Create a ZIP compressed file from an array of file data.
*
* @param string $archive Path to save archive.
@@ -115,14 +143,13 @@ public function create($archive, $files)
*
* @param string $archive Path to ZIP archive to extract
* @param string $destination Path to extract archive into
- * @param array $options Extraction options [unused]
*
* @return boolean True if successful
*
* @since 1.0
* @throws \RuntimeException
*/
- public function extract($archive, $destination, array $options = array())
+ public function extract($archive, $destination)
{
if (!is_file($archive))
{
@@ -200,11 +227,6 @@ protected function extractCustom($archive, $destination)
$this->data = null;
$this->metadata = null;
- if (!extension_loaded('zlib'))
- {
- throw new \RuntimeException('Zlib not supported');
- }
-
$this->data = file_get_contents($archive);
if (!$this->data)

0 comments on commit 5d5383f

Please sign in to comment.