diff --git a/src/_h5ai/client/js/inc/ext/download.js b/src/_h5ai/client/js/inc/ext/download.js index 0acbb58b..bb882992 100644 --- a/src/_h5ai/client/js/inc/ext/download.js +++ b/src/_h5ai/client/js/inc/ext/download.js @@ -70,6 +70,25 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co } }, + onClick = function (event) { + + var exe = settings.execution.toUpperCase(); + + if (exe === 'PHP') { + + event.preventDefault(); + requestArchive(selectedHrefsStr); + + } else if (exe === 'SHELL') { + + var query = '?action=passArchive'; + query += '&as=' + (settings.packageName || location.getItem().label) + '.' + settings.format; + query += '&format=' + settings.format; + query += '&hrefs=' + selectedHrefsStr; + window.location = query; + } + }, + init = function () { if (!settings.enabled || !server.api) { @@ -77,11 +96,7 @@ modulejs.define('ext/download', ['_', '$', 'core/settings', 'core/resource', 'co } $download = $(downloadBtnTemplate) - .find('a').on('click', function (event) { - - event.preventDefault(); - requestArchive(selectedHrefsStr); - }).end() + .find('a').on('click', onClick).end() .appendTo('#navbar'); $img = $download.find('img'); diff --git a/src/_h5ai/conf/options.json b/src/_h5ai/conf/options.json index c2dc439a..deb35704 100644 --- a/src/_h5ai/conf/options.json +++ b/src/_h5ai/conf/options.json @@ -106,7 +106,7 @@ Options "download": { "enabled": true, "execution": "shell", - "format": "zip", + "format": "tar", "packageName": null }, diff --git a/src/_h5ai/server/php/inc/Api.php b/src/_h5ai/server/php/inc/Api.php index 6f7c8c08..63a3ed7d 100644 --- a/src/_h5ai/server/php/inc/Api.php +++ b/src/_h5ai/server/php/inc/Api.php @@ -104,13 +104,13 @@ class Api { json_fail(1, "downloads disabled", !$options["download"]["enabled"]); - list($execution, $format, $hrefs) = use_request_params(array("execution", "format", "hrefs")); + list($format, $hrefs) = use_request_params(array("format", "hrefs")); normalized_require_once("/server/php/inc/Archive.php"); $archive = new Archive($this->app); $hrefs = explode(":", trim($hrefs)); - $target = $archive->create($execution, $format, $hrefs); + $target = $archive->create($format, $hrefs); if (!is_string($target)) { json_fail($target, "package creation failed"); @@ -154,6 +154,29 @@ class Api { } + else if ($action === "passArchive") { + + json_fail(1, "downloads disabled", !$options["download"]["enabled"]); + + list($as, $format, $hrefs) = use_request_params(array("as", "format", "hrefs")); + + normalized_require_once("/server/php/inc/Archive.php"); + $archive = new Archive($this->app); + + $hrefs = explode(":", trim($hrefs)); + + header("Content-Type: application/octet-stream"); + header("Content-Disposition: attachment; filename=\"$as\""); + header("Connection: close"); + $rc = $archive->shell_passthru($format, $hrefs); + + if ($rc !== 0) { + json_fail($target, "package creation failed"); + } + exit; + } + + else if ($action === "upload") { list($href) = use_request_params(array("href")); diff --git a/src/_h5ai/server/php/inc/Archive.php b/src/_h5ai/server/php/inc/Archive.php index 2d6ab6fc..2068775e 100644 --- a/src/_h5ai/server/php/inc/Archive.php +++ b/src/_h5ai/server/php/inc/Archive.php @@ -2,11 +2,10 @@ class Archive { - private static $TAR_CMD = "$(cd [ROOTDIR] && tar --no-recursion -cf [TARGET] [DIRS] [FILES])"; - private static $ZIP_CMD = "$(cd [ROOTDIR] && zip [TARGET] [FILES])"; + private static $TAR_PASSTHRU_CMD = "cd [ROOTDIR] && tar --no-recursion -c -- [DIRS] [FILES]"; + private static $ZIP_PASSTHRU_CMD = "cd [ROOTDIR] && zip - -- [FILES]"; - - private $app, $dirs, $files, $sc401; + private $app, $dirs, $files; public function __construct($app) { @@ -15,7 +14,7 @@ class Archive { } - public function create($execution, $format, $hrefs) { + public function create($format, $hrefs) { $this->dirs = array(); $this->files = array(); @@ -29,33 +28,12 @@ class Archive { $target = $this->app->get_cache_abs_path() . "/package-" . sha1(microtime(true) . rand()) . "." . $format; try { - if ($execution === "shell") { - - if ($format === "tar") { - $cmd = Archive::$TAR_CMD; - } else if ($format === "zip") { - $cmd = Archive::$ZIP_CMD; - } else { - return null; - } - // $cmd = str_replace("[ROOTDIR]", "\"" . $this->app->get_root_abs_path() . "\"", $cmd); - $cmd = str_replace("[ROOTDIR]", "\"" . $this->app->get_abs_path() . "\"", $cmd); - $cmd = str_replace("[TARGET]", "\"" . $target . "\"", $cmd); - $cmd = str_replace("[DIRS]", count($this->dirs) ? "\"" . implode("\" \"", array_values($this->dirs)) . "\"" : "", $cmd); - $cmd = str_replace("[FILES]", count($this->files) ? "\"" . implode("\" \"", array_values($this->files)) . "\"" : "", $cmd); - - shell_exec($cmd); - - } else if ($execution === "php") { - - $archive = new PharData($target); - foreach ($this->dirs as $archived_dir) { - $archive->addEmptyDir($archived_dir); - } - foreach ($this->files as $real_file => $archived_file) { - $archive->addFile($real_file, $archived_file); // very, very slow :/ - } - + $archive = new PharData($target); + foreach ($this->dirs as $archived_dir) { + $archive->addEmptyDir($archived_dir); + } + foreach ($this->files as $real_file => $archived_file) { + $archive->addFile($real_file, $archived_file); // very, very slow :/ } } catch (Exeption $err) { return 500; @@ -65,6 +43,40 @@ class Archive { } + public function shell_passthru($format, $hrefs) { + + $this->dirs = array(); + $this->files = array(); + + $this->add_hrefs($hrefs); + + if (count($this->dirs) === 0 && count($this->files) === 0) { + return 500; + } + + try { + + if ($format === "tar") { + $cmd = Archive::$TAR_PASSTHRU_CMD; + } else if ($format === "zip") { + $cmd = Archive::$ZIP_PASSTHRU_CMD; + } else { + return 500; + } + $cmd = str_replace("[ROOTDIR]", "\"" . $this->app->get_abs_path() . "\"", $cmd); + $cmd = str_replace("[DIRS]", count($this->dirs) ? "\"" . implode("\" \"", array_values($this->dirs)) . "\"" : "", $cmd); + $cmd = str_replace("[FILES]", count($this->files) ? "\"" . implode("\" \"", array_values($this->files)) . "\"" : "", $cmd); + + passthru($cmd); + + } catch (Exeption $err) { + return 500; + } + + return 0; + } + + private function add_hrefs($hrefs) { foreach ($hrefs as $href) { @@ -77,7 +89,6 @@ class Archive { if ($code == App::$MAGIC_SEQUENCE && !$this->app->is_ignored($n)) { $real_file = $this->app->get_abs_path($href); - // $archived_file = preg_replace("!^" . normalize_path($this->app->get_root_abs_path(), true) . "!", "", $real_file); $archived_file = preg_replace("!^" . normalize_path($this->app->get_abs_path(), true) . "!", "", $real_file); if (is_dir($real_file)) {