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

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

parents 9a495c2f 46d61c4e
......@@ -53,7 +53,6 @@ Mahara 15.10 requires:
** bz2 (optional)
** imagick (optional)
** openssl and xmlrpc (optional; for networking support)
** zip (optional)
** zlib (optional)
** adodb (optional; improves performance)
** enchant or pspell (optional; for TinyMCE spellcheck button)
......@@ -62,8 +61,6 @@ Mahara 15.10 requires:
* 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
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
Javascript support. However, it is only actively tested in the most recent
......
......@@ -88,24 +88,15 @@ function create_zipfile($listing, $files) {
}
// zip everything up
$zipfile = $exportdir . 'mahara-bulk-export-' . time() . '.zip';
$cwd = getcwd();
$command = sprintf('%s %s %s %s %s',
get_config('pathtozip'),
get_config('ziprecursearg'),
escapeshellarg($zipfile),
escapeshellarg($listingfile),
escapeshellarg($usersdir)
);
$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;
$filename = 'mahara-bulk-export-' . time() . '.zip';
try {
create_zip_archive($exportdir, $filename, array($listingfile, $usersdir));
}
catch (SystemException $e) {
throw new SystemException('Failed to zip the export file: ' . $e->getMessage());
}
return $exportdir . $filename;
}
function bulkexport_submit(Pieform $form, $values) {
......
......@@ -108,24 +108,14 @@ function bulkimport_validate(Pieform $form, $values) {
throw new SystemException("Couldn't create the temporary export directory $importdir");
}
$command = sprintf('%s %s %s',
escapeshellcmd(get_config('pathtounzip')),
escapeshellarg($zipfile),
'-d ' . escapeshellarg($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)));
$archive = new ZipArchive();
if ($archive->open($zipfile) && $archive->extractTo($importdir)) {
// successfully extracted
$archive->close();
log_debug("Unzipped $zipfile into $importdir");
}
else {
log_debug("Unzipped $zipfile into $importdir");
throw new SystemException(get_string('unzipfailed', 'admin', hsc($zipfile)));
}
$csvfilename = $importdir . '/usernames.csv';
......@@ -196,17 +186,13 @@ function import_next_user($filename, $username, $authinstance) {
check_dir_exists($uploaddir);
// Unzip the file
$command = sprintf('%s %s %s %s',
escapeshellcmd(get_config('pathtounzip')),
escapeshellarg($filename),
get_config('unzipdirarg'),
escapeshellarg($uploaddir)
);
$output = array();
exec($command, $output, $returnvar);
if ($returnvar != 0) {
$archive = new ZipArchive();
if ($archive->open($filename) && $archive->extractTo($uploaddir)) {
// successfully extracted
$archive->close();
}
else {
$FAILEDUSERS[$username] = get_string('unzipfailed', 'admin', hsc($filename));
log_debug("unzip command failed with return value $returnvar");
return;
}
......
......@@ -383,10 +383,6 @@ function send_content_intent($username) {
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) {
$e = new ImportException(null, 'Importing content is disabled');
$e->set_log_off(); // we don't want these ones.
......
......@@ -219,19 +219,11 @@ class PluginExportHtml extends PluginExport {
// zip everything up
$this->notify_progress_callback(90, get_string('creatingzipfile', 'export'));
$cwd = getcwd();
$command = sprintf('%s %s %s %s',
get_config('pathtozip'),
get_config('ziprecursearg'),
escapeshellarg($this->exportdir . $this->zipfile),
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');
try {
create_zip_archive($this->exportdir, $this->zipfile, array($this->rootdir));
}
catch (SystemException $e) {
throw new SystemException('Failed to zip the export file: ' . $e->getMessage());
}
$this->notify_progress_callback(100, get_string('Done', 'export'));
return $this->zipfile;
......
......@@ -29,11 +29,6 @@ $exportplugins = plugins_installed('export');
if (!$exportplugins) {
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) {
safe_require('export', $plugin->name);
......
......@@ -172,20 +172,11 @@ class PluginExportLeap extends PluginExport {
$this->notify_progress_callback(95, get_string('creatingzipfile', 'export'));
// zip everything up
$cwd = getcwd();
$command = sprintf('%s %s %s %s %s',
get_config('pathtozip'),
get_config('ziprecursearg'),
escapeshellarg($this->exportdir . $this->zipfile),
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);
try {
create_zip_archive($this->exportdir, $this->zipfile, array($this->leapfile, $this->filedir));
}
catch (SystemException $e) {
throw new SystemException('Failed to zip the export file: ' . $e->getMessage());
}
$this->notify_progress_callback(100, get_string('Done', 'export'));
return $this->zipfile;
......@@ -1154,4 +1145,4 @@ class LeapExportOutputFilter {
return $matches[0];
}
}
\ No newline at end of file
}
......@@ -861,3 +861,50 @@ function submissions_delete_removed_archive() {
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) {
if (!array_key_exists('leap', $importplugins)) {
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);
......
......@@ -515,25 +515,13 @@ abstract class ImporterTransport {
return;
}
// check that pathtounzip is valid
if (!is_executable(get_config('pathtounzip'))) {
throw new ImportException($this, get_string('unzipnotinstalled', 'admin'));
$archive = new ZipArchive();
if ($archive->open($this->importfile) && $archive->extractTo($todir)) {
// successfully extracted
$archive->close();
}
$command = sprintf('%s %s %s %s',
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');
}
else {
throw new ImportException($this, 'Failed to unzip the file recieved from the transport object');
}
$this->extracted = true;
}
......
......@@ -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['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['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['Import'] = 'Import';
$string['bulkimportdirdoesntexist'] = 'The directory %s does not exist.';
......
......@@ -283,20 +283,6 @@ $cfg->pathtoclam = '';
*/
$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
* 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