summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2009-10-15 17:55:55 +0000
committerDries Buytaert <dries@buytaert.net>2009-10-15 17:55:55 +0000
commit2fb451c87241b5dfb44b45129978e1bb9b971a26 (patch)
treefaca7f0132377c12a8a9f4397e5d4d91fdc0fd99
parent977d635bb1705ecebae8783a5e629214986eaddf (diff)
downloadbrdo-2fb451c87241b5dfb44b45129978e1bb9b971a26.tar.gz
brdo-2fb451c87241b5dfb44b45129978e1bb9b971a26.tar.bz2
- Patch #604618 by Crell, JacobSingh: create a common interface for Archive operations so we can handle .zip, .tar.gz.
-rw-r--r--includes/archiver.inc67
-rw-r--r--includes/common.inc50
-rw-r--r--modules/system/system.api.php28
-rw-r--r--modules/system/system.archiver.inc67
-rw-r--r--modules/system/system.info1
-rw-r--r--modules/system/system.module12
6 files changed, 225 insertions, 0 deletions
diff --git a/includes/archiver.inc b/includes/archiver.inc
new file mode 100644
index 000000000..8d514794a
--- /dev/null
+++ b/includes/archiver.inc
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Shared classes and interfaces for the archiver system.
+ */
+
+/**
+ * Common interface for all Archiver classes.
+ */
+interface ArchiverInterface {
+
+ /**
+ * Contructor for a new archiver instance.
+ *
+ * @param $file_path
+ * The full system path of the archive to manipulate. Only local files
+ * are supported. If the file does not yet exist, it will be created if
+ * appropriate.
+ */
+ public function __construct($file_path);
+
+ /**
+ * Add the specified file or directory to the archive.
+ *
+ * @param $file_path
+ * The full system path of the file or directory to add. Only local files
+ * and directories are supported.
+ * @return
+ * The called object.
+ */
+ public function add($file_path);
+
+ /**
+ * Remove the specified file from the archive.
+ *
+ * @param $path
+ * The file name relative to the root of the archive to remove.
+ * @return
+ * The called object.
+ */
+ public function remove($path);
+
+ /**
+ * Extract multiple files in the archive to the specified path.
+ *
+ * @param $path
+ * A full system path of the directory to which to extract files.
+ * @param $files
+ * Optionally specify a list of files to be extracted. Files are
+ * relative to the root of the archive. If not specified, all files
+ * in the archive will be extracted
+ * @return
+ * The called object.
+ */
+ public function extract($path, Array $files = array());
+
+ /**
+ * List all files in the archive.
+ *
+ * @return
+ * An array of file names relative to the root of the archive, or
+ * an iteratable object that resolves to such a list.
+ */
+ public function listContents();
+}
+
diff --git a/includes/common.inc b/includes/common.inc
index c3939b9cb..a72039566 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -5939,3 +5939,53 @@ function xmlrpc($url) {
return call_user_func_array('_xmlrpc', $args);
}
+/**
+ * Retrieve a list of all available archivers.
+ */
+function archiver_get_info() {
+ $archiver_info = &drupal_static(__FUNCTION__, array());
+
+ if (empty($archiver_info)) {
+ $cache = cache_get('archiver_info');
+ if ($cache === FALSE) {
+ // Rebuild the cache and save it.
+ $archiver_info = module_invoke_all('archiver_info');
+ drupal_alter('archiver_info', $archiver_info);
+ uasort($archiver_info, 'drupal_sort_weight');
+ cache_set('archiver_info', $archiver_info);
+ }
+ else {
+ $archiver_info = $cache->data;
+ }
+ }
+
+ return $archiver_info;
+}
+
+/**
+ * Create the appropriate archiver for the specified file.
+ *
+ * @param $file
+ * The full path of the archive file. Note that stream wrapper
+ * paths are supported.
+ * @return
+ * A newly created instance of the archiver class appropriate
+ * for the specified file, already bound to that file.
+ */
+function archiver_get_archiver($file) {
+ $archiver_info = archiver_get_info();
+
+ foreach ($archiver_info as $implementation) {
+ foreach ($implementation['extensions'] as $extension) {
+ // Because extensions may be multi-part, such as .tar.gz,
+ // we cannot use simpler approaches like substr() or pathinfo().
+ // This method isn't quite as clean but gets the job done.
+ // Also note that the file may not yet exist, so we cannot rely
+ // on fileinfo() or other disk-level utilities.
+ if (strrpos($file, '.' . $extension) === strlen($file) - strlen('.' . $extension)) {
+ return new $implementation['class']($file);
+ }
+ }
+ }
+}
+
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index c1f597855..1f4d1d394 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -2399,6 +2399,34 @@ function hook_action_info_alter(&$actions) {
}
/**
+ * Declare archivers to the system.
+ *
+ * An archiver is a class that is able to package and unpackage one or more files
+ * into a single possibly compressed file. Common examples of such files are
+ * zip files and tar.gz files. All archiver classes must implement
+ * ArchiverInterface.
+ *
+ * When mapping a
+ *
+ * Each entry should be keyed on a unique value, and specify three
+ * additional keys:
+ * - class: The name of the PHP class for this archiver.
+ * - extensions: An array of file extensions that this archiver supports.
+ * - weight: This optional key specifies the weight of this archiver.
+ * When mapping file extensions to archivers, the first archiver by
+ * weight found that supports the requested extension will be used.
+ */
+function system_archiver_info() {
+ return array(
+ 'tar' => array(
+ 'class' => 'ArchiverTar',
+ 'extensions' => array('tar', 'tar.gz', 'tar.bz2'),
+ ),
+ );
+}
+
+
+/**
* Defines additional date types.
*
* Next to the 'long', 'medium' and 'short' date types defined in core, any
diff --git a/modules/system/system.archiver.inc b/modules/system/system.archiver.inc
new file mode 100644
index 000000000..65bf63e3a
--- /dev/null
+++ b/modules/system/system.archiver.inc
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Archiver implementations provided by the system module.
+ */
+
+/**
+ * Archiver for .tar files.
+ */
+class ArchiverTar implements ArchiverInterface {
+
+ /**
+ * The underlying Archive_Tar instance that does the heavy lifting.
+ *
+ * @var Archive_Tar
+ */
+ protected $tar;
+
+ public function __construct($file_path) {
+ $this->tar = new Archive_Tar($file_path);
+ }
+
+ public function add($file_path) {
+ $this->tar->add($file_path);
+
+ return $this;
+ }
+
+ public function remove($path) {
+ // @todo Archive_Tar doesn't have a remove operation
+ // so we'll have to simulate it somehow, probably by
+ // creating a new archive with everything but the removed
+ // file.
+
+ return $this;
+ }
+
+ public function extract($path, Array $files = array()) {
+ if ($files) {
+ $this->tar->extractList($files, $path);
+ }
+ else {
+ $this->tar->extract($path);
+ }
+
+ return $this;
+ }
+
+ public function listContents() {
+ return $this->tar->listContent();
+ }
+
+ /**
+ * Retrieve the tar engine itself.
+ *
+ * In some cases it may be necessary to directly access the underlying
+ * Archive_Tar object for implementation-specific logic. This is for advanced
+ * use only as it is not shared by other implementations of ArchiveInterface.
+ *
+ * @return
+ * The Archive_Tar object used by this object.
+ */
+ public function getArchive() {
+ return $this->tar;
+ }
+}
diff --git a/modules/system/system.info b/modules/system/system.info
index fa9a77d59..2f288d9d7 100644
--- a/modules/system/system.info
+++ b/modules/system/system.info
@@ -6,6 +6,7 @@ version = VERSION
core = 7.x
files[] = system.module
files[] = system.admin.inc
+files[] = system.archiver.inc
files[] = system.queue.inc
files[] = image.gd.inc
files[] = system.install
diff --git a/modules/system/system.module b/modules/system/system.module
index 70c789f8b..e89eb625b 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -3380,6 +3380,18 @@ function system_date_format_delete($dfid) {
}
/**
+ * Implement hook_archiver_info().
+ */
+function system_archiver_info() {
+ return array(
+ 'tar' => array(
+ 'class' => 'ArchiverTar',
+ 'extensions' => array('tar', 'tar.gz', 'tar.bz2'),
+ ),
+ );
+}
+
+/**
* Theme confirmation forms.
*
* By default this does not alter the appearance of a form at all,