Commit dbdeb077 authored by Robert Lyon's avatar Robert Lyon Committed by Gerrit Code Review
Browse files

Merge "Use ZipArchive for export and import (Bug #1338381)"

parents 9a495c2f 46d61c4e
...@@ -53,7 +53,6 @@ Mahara 15.10 requires: ...@@ -53,7 +53,6 @@ Mahara 15.10 requires:
** bz2 (optional) ** bz2 (optional)
** imagick (optional) ** imagick (optional)
** openssl and xmlrpc (optional; for networking support) ** openssl and xmlrpc (optional; for networking support)
** zip (optional)
** zlib (optional) ** zlib (optional)
** adodb (optional; improves performance) ** adodb (optional; improves performance)
** enchant or pspell (optional; for TinyMCE spellcheck button) ** enchant or pspell (optional; for TinyMCE spellcheck button)
...@@ -62,8 +61,6 @@ Mahara 15.10 requires: ...@@ -62,8 +61,6 @@ Mahara 15.10 requires:
* OS: Mahara is only officially supported on Debian (5.0/"Lenny" or later) and * OS: Mahara is only officially supported on Debian (5.0/"Lenny" or later) and
Ubuntu (10.04/"Lucid Lynx" or later), however it will probably run in any Ubuntu (10.04/"Lucid Lynx" or later), however it will probably run in any
OS with a suitable web server OS with a suitable web server
** For zip/unzip support, the command-line "zip" and "unzip" utilities must
be installed
* Web Browser: Mahara should be accessible in any modern web browser with * Web Browser: Mahara should be accessible in any modern web browser with
Javascript support. However, it is only actively tested in the most recent Javascript support. However, it is only actively tested in the most recent
......
...@@ -88,24 +88,15 @@ function create_zipfile($listing, $files) { ...@@ -88,24 +88,15 @@ function create_zipfile($listing, $files) {
} }
// zip everything up // zip everything up
$zipfile = $exportdir . 'mahara-bulk-export-' . time() . '.zip'; $filename = 'mahara-bulk-export-' . time() . '.zip';
$cwd = getcwd(); try {
$command = sprintf('%s %s %s %s %s', create_zip_archive($exportdir, $filename, array($listingfile, $usersdir));
get_config('pathtozip'), }
get_config('ziprecursearg'), catch (SystemException $e) {
escapeshellarg($zipfile), throw new SystemException('Failed to zip the export file: ' . $e->getMessage());
escapeshellarg($listingfile), }
escapeshellarg($usersdir)
); return $exportdir . $filename;
$output = array();
chdir($exportdir);
exec($command, $output, $returnvar);
chdir($cwd);
if ($returnvar != 0) {
throw new SystemException('Failed to zip the export file: return code ' . $returnvar);
}
return $zipfile;
} }
function bulkexport_submit(Pieform $form, $values) { function bulkexport_submit(Pieform $form, $values) {
......
...@@ -108,24 +108,14 @@ function bulkimport_validate(Pieform $form, $values) { ...@@ -108,24 +108,14 @@ function bulkimport_validate(Pieform $form, $values) {
throw new SystemException("Couldn't create the temporary export directory $importdir"); throw new SystemException("Couldn't create the temporary export directory $importdir");
} }
$command = sprintf('%s %s %s', $archive = new ZipArchive();
escapeshellcmd(get_config('pathtounzip')), if ($archive->open($zipfile) && $archive->extractTo($importdir)) {
escapeshellarg($zipfile), // successfully extracted
'-d ' . escapeshellarg($importdir) $archive->close();
); log_debug("Unzipped $zipfile into $importdir");
$output = array();
exec($command, $output, $returnvar);
if ($returnvar != 0) {
log_debug("unzip command failed with return value $returnvar");
// Let's make it obvious if the cause is obvious :)
if ($returnvar == 127) {
log_debug("This means that 'unzip' isn't installed, or the config var \$cfg->pathtounzip is not"
. " pointing at unzip (see Mahara's file lib/config-defaults.php)");
}
throw new SystemException(get_string('unzipfailed', 'admin', hsc($zipfile)));
} }
else { else {
log_debug("Unzipped $zipfile into $importdir"); throw new SystemException(get_string('unzipfailed', 'admin', hsc($zipfile)));
} }
$csvfilename = $importdir . '/usernames.csv'; $csvfilename = $importdir . '/usernames.csv';
...@@ -196,17 +186,13 @@ function import_next_user($filename, $username, $authinstance) { ...@@ -196,17 +186,13 @@ function import_next_user($filename, $username, $authinstance) {
check_dir_exists($uploaddir); check_dir_exists($uploaddir);
// Unzip the file // Unzip the file
$command = sprintf('%s %s %s %s', $archive = new ZipArchive();
escapeshellcmd(get_config('pathtounzip')), if ($archive->open($filename) && $archive->extractTo($uploaddir)) {
escapeshellarg($filename), // successfully extracted
get_config('unzipdirarg'), $archive->close();
escapeshellarg($uploaddir) }
); else {
$output = array();
exec($command, $output, $returnvar);
if ($returnvar != 0) {
$FAILEDUSERS[$username] = get_string('unzipfailed', 'admin', hsc($filename)); $FAILEDUSERS[$username] = get_string('unzipfailed', 'admin', hsc($filename));
log_debug("unzip command failed with return value $returnvar");
return; return;
} }
......
...@@ -383,10 +383,6 @@ function send_content_intent($username) { ...@@ -383,10 +383,6 @@ function send_content_intent($username) {
throw new ImportException(null, "Could not find user $username for $REMOTEWWWROOT"); throw new ImportException(null, "Could not find user $username for $REMOTEWWWROOT");
} }
if (!is_executable(get_config('pathtounzip'))) {
throw new ImportException(null, "Cannot find unzip executable");
}
if (!$authinstance->weimportcontent) { if (!$authinstance->weimportcontent) {
$e = new ImportException(null, 'Importing content is disabled'); $e = new ImportException(null, 'Importing content is disabled');
$e->set_log_off(); // we don't want these ones. $e->set_log_off(); // we don't want these ones.
......
...@@ -219,19 +219,11 @@ class PluginExportHtml extends PluginExport { ...@@ -219,19 +219,11 @@ class PluginExportHtml extends PluginExport {
// zip everything up // zip everything up
$this->notify_progress_callback(90, get_string('creatingzipfile', 'export')); $this->notify_progress_callback(90, get_string('creatingzipfile', 'export'));
$cwd = getcwd(); try {
$command = sprintf('%s %s %s %s', create_zip_archive($this->exportdir, $this->zipfile, array($this->rootdir));
get_config('pathtozip'), }
get_config('ziprecursearg'), catch (SystemException $e) {
escapeshellarg($this->exportdir . $this->zipfile), throw new SystemException('Failed to zip the export file: ' . $e->getMessage());
escapeshellarg($this->rootdir)
);
$output = array();
chdir($this->exportdir);
exec($command, $output, $returnvar);
chdir($cwd);
if ($returnvar != 0) {
throw new SystemException('Failed to zip the export file');
} }
$this->notify_progress_callback(100, get_string('Done', 'export')); $this->notify_progress_callback(100, get_string('Done', 'export'));
return $this->zipfile; return $this->zipfile;
......
...@@ -29,11 +29,6 @@ $exportplugins = plugins_installed('export'); ...@@ -29,11 +29,6 @@ $exportplugins = plugins_installed('export');
if (!$exportplugins) { if (!$exportplugins) {
die_info(get_string('noexportpluginsenabled', 'export')); die_info(get_string('noexportpluginsenabled', 'export'));
} }
if (!is_executable(get_config('pathtozip'))) {
log_info("Either you do not have the 'zip' command installed, or the config setting 'pathtozip' is not pointing at your zip command."
. " Until you fix this, you will not be able to use the export system.");
die_info(get_string('zipnotinstalled', 'export'));
}
foreach ($exportplugins as $plugin) { foreach ($exportplugins as $plugin) {
safe_require('export', $plugin->name); safe_require('export', $plugin->name);
......
...@@ -172,20 +172,11 @@ class PluginExportLeap extends PluginExport { ...@@ -172,20 +172,11 @@ class PluginExportLeap extends PluginExport {
$this->notify_progress_callback(95, get_string('creatingzipfile', 'export')); $this->notify_progress_callback(95, get_string('creatingzipfile', 'export'));
// zip everything up // zip everything up
$cwd = getcwd(); try {
$command = sprintf('%s %s %s %s %s', create_zip_archive($this->exportdir, $this->zipfile, array($this->leapfile, $this->filedir));
get_config('pathtozip'), }
get_config('ziprecursearg'), catch (SystemException $e) {
escapeshellarg($this->exportdir . $this->zipfile), throw new SystemException('Failed to zip the export file: ' . $e->getMessage());
escapeshellarg($this->leapfile),
escapeshellarg($this->filedir)
);
$output = array();
chdir($this->exportdir);
exec($command, $output, $returnvar);
chdir($cwd);
if ($returnvar != 0) {
throw new SystemException('Failed to zip the export file: return code ' . $returnvar);
} }
$this->notify_progress_callback(100, get_string('Done', 'export')); $this->notify_progress_callback(100, get_string('Done', 'export'));
return $this->zipfile; return $this->zipfile;
...@@ -1154,4 +1145,4 @@ class LeapExportOutputFilter { ...@@ -1154,4 +1145,4 @@ class LeapExportOutputFilter {
return $matches[0]; return $matches[0];
} }
} }
\ No newline at end of file
...@@ -861,3 +861,50 @@ function submissions_delete_removed_archive() { ...@@ -861,3 +861,50 @@ function submissions_delete_removed_archive() {
db_commit(); db_commit();
} }
} }
/**
* Create a zip file containing the specified files and folders, including subfolders
*
* @param string $exportdir Export directory - files to export will be found here
* and the archive file will be placed here once created
* @param string $filename The desired name of the archive file
* @param array $files An array of files and folders to add to the archive
* (relative to the export directory)
*/
function create_zip_archive($exportdir, $filename, $files) {
$filename = $exportdir . $filename;
$archive = new ZipArchive();
if ($archive->open($filename, ZIPARCHIVE::CREATE)) {
$allfiles = array();
$directories = array();
// add plain files and mark directories to process
foreach ($files as $file) {
if (is_file($exportdir . $file)) {
$archive->addFile($exportdir . $file, $file);
}
else {
$directories[] = $file . '/';
}
}
// add the contents of all directories and subdirectories
while (count($directories) > 0) {
$dir = array_shift($directories);
$files = array_diff(scandir($exportdir . $dir), array('..', '.'));
if (count($files) == 0) {
$archive->addEmptyDir($dir);
}
foreach($files as $file) {
if (is_file($exportdir . $dir . $file)) {
$archive->addFile($exportdir . $dir . $file, $dir . $file);
}
else {
$directories[] = $dir . $file . '/';
}
}
}
$archive->close();
}
else {
throw new SystemException('could not open zip file');
}
}
...@@ -53,11 +53,6 @@ if (!$importplugins) { ...@@ -53,11 +53,6 @@ if (!$importplugins) {
if (!array_key_exists('leap', $importplugins)) { if (!array_key_exists('leap', $importplugins)) {
die_info(get_string('noleapimportpluginsenabled', 'import')); die_info(get_string('noleapimportpluginsenabled', 'import'));
} }
// Check if unzip is available
// This is required for extracting leap2a zip file
if (!is_executable(get_config('pathtounzip'))) {
die_info(get_string('unzipnotinstalled', 'admin'));
}
$action = param_integer('action', PRINTUPLOADFORM_ACT); $action = param_integer('action', PRINTUPLOADFORM_ACT);
......
...@@ -515,25 +515,13 @@ abstract class ImporterTransport { ...@@ -515,25 +515,13 @@ abstract class ImporterTransport {
return; return;
} }
// check that pathtounzip is valid $archive = new ZipArchive();
if (!is_executable(get_config('pathtounzip'))) { if ($archive->open($this->importfile) && $archive->extractTo($todir)) {
throw new ImportException($this, get_string('unzipnotinstalled', 'admin')); // successfully extracted
$archive->close();
} }
else {
$command = sprintf('%s %s %s %s', throw new ImportException($this, 'Failed to unzip the file recieved from the transport object');
get_config('pathtounzip'),
escapeshellarg($this->importfile),
get_config('unzipdirarg'),
escapeshellarg($todir)
);
$output = array();
exec($command, $output, $returnvar);
if ($returnvar != 0) {
if ($returnvar == 1) {
log_warn("Unzipping the zip file caused a warning, but it is recoverable so continuing anyway");
} else {
throw new ImportException($this, 'Failed to unzip the file recieved from the transport object');
}
} }
$this->extracted = true; $this->extracted = true;
} }
......
...@@ -691,7 +691,6 @@ $string['importfilemissinglisting'] = 'The bulk export file is missing a file na ...@@ -691,7 +691,6 @@ $string['importfilemissinglisting'] = 'The bulk export file is missing a file na
$string['importfilenotafile'] = 'Error during form submission: file was not recognised.'; $string['importfilenotafile'] = 'Error during form submission: file was not recognised.';
$string['importfilenotreadable'] = 'Error during form submission: file was not readable.'; $string['importfilenotreadable'] = 'Error during form submission: file was not readable.';
$string['bulkleap2aimportfiledescription'] = 'The ZIP file on your server containing all exported users (in Leap2A format) along with a CSV listing of usernames'; $string['bulkleap2aimportfiledescription'] = 'The ZIP file on your server containing all exported users (in Leap2A format) along with a CSV listing of usernames';
$string['unzipnotinstalled'] = 'Your system does not have the unzip command, or $cfg->pathtounzip is misconfigured. Please install unzip to enable importing a zipped export file or fix the $cfg->pathtounzip setting.';
$string['importednuserssuccessfully'] = 'Imported %d of %d users successfully.'; $string['importednuserssuccessfully'] = 'Imported %d of %d users successfully.';
$string['Import'] = 'Import'; $string['Import'] = 'Import';
$string['bulkimportdirdoesntexist'] = 'The directory %s does not exist.'; $string['bulkimportdirdoesntexist'] = 'The directory %s does not exist.';
......
...@@ -283,20 +283,6 @@ $cfg->pathtoclam = ''; ...@@ -283,20 +283,6 @@ $cfg->pathtoclam = '';
*/ */
$cfg->pathtomagicdb = NULL; $cfg->pathtomagicdb = NULL;
/**
* @global string $cfg->pathtogzip
* @global string $cfg->pathtounzip
* @global string $cfg->pathtozip
* @global string $cfg->ziprecursearg Argument to pass to the zip executable to indicate that it should act recursively
* @global string $cfg->unzipdirarg Argument to pass to the unzip executable to indicate the directory it should unzip into
* @global string $cfg->unziplistarg Argument to pass to the unzip executable to list the contents of the archive
*/
$cfg->pathtogzip = '/bin/gzip';
$cfg->pathtounzip = '/usr/bin/unzip';
$cfg->pathtozip = '/usr/bin/zip';
$cfg->ziprecursearg = '-r';
$cfg->unzipdirarg = '-d';
$cfg->unziplistarg = '-l';
/** /**
* @global string $cfg->unziptempdir some shared hosts have restrictions on where unzip can be used * @global string $cfg->unziptempdir some shared hosts have restrictions on where unzip can be used
* dataroot is often not allowed; but /tmp is. This path should end with a "/" * dataroot is often not allowed; but /tmp is. This path should end with a "/"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment