diff --git a/ChangeLog b/ChangeLog
index 059fc0d145c..4ba65941254 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -105,6 +105,7 @@ NEW: Use an ajax call for the clicktodial feature instead of href link.
NEW: when multiple order linked to facture, show list into note.
NEW: when we delete several objects with massaction, if somes object has child we must see which objects are concerned and nevertheless delete objects which can be deleted
NEW: Editing a page in website module keep old page with name .back
+NEW: External backups can be downloaded from the "About info page".
For developers:
diff --git a/htdocs/admin/modulehelp.php b/htdocs/admin/modulehelp.php
index a3c7c3d5c08..4122e2b56ed 100644
--- a/htdocs/admin/modulehelp.php
+++ b/htdocs/admin/modulehelp.php
@@ -326,6 +326,13 @@ if ($mode == 'desc') {
$textexternal = '';
if ($objMod->isCoreOrExternalModule() == 'external') {
$textexternal .= '
'.$langs->trans("Origin").': '.$langs->trans("ExternalModule").' - '.$langs->trans("InstalledInto", $dirofmodule);
+
+ global $dolibarr_allow_download_external_modules;
+ if (!empty($dolibarr_allow_download_external_modules) && preg_match('/\/custom\//', $dirofmodule)) {
+ // Add a link to download a zip of the module
+ $textexternal .= ' '.img_picto('', 'download').'';
+ }
+
if ($objMod->editor_name != 'dolibarr') {
$textexternal .= '
'.$langs->trans("Publisher").': '.(empty($objMod->editor_name) ? $langs->trans("Unknown") : $objMod->editor_name);
}
diff --git a/htdocs/admin/tools/export_files.php b/htdocs/admin/tools/export_files.php
index ff4b12efc9e..0b9272c2418 100644
--- a/htdocs/admin/tools/export_files.php
+++ b/htdocs/admin/tools/export_files.php
@@ -138,7 +138,23 @@ $dirtocompress = basename($fulldirtocompress);
if ($compression == 'zip') {
$file .= '.zip';
$excludefiles = '/(\.back|\.old|\.log|[\/\\\]temp[\/\\\]|documents[\/\\\]admin[\/\\\]documents[\/\\\])/i';
- $ret = dol_compress_dir($fulldirtocompress, $outputdir."/".$file, $compression, $excludefiles);
+
+ //var_dump($fulldirtocompress);
+ //var_dump($outputdir."/".$file);exit;
+
+ $rootdirinzip = '';
+ if ($export_type == 'externalmodule' && !empty($what)) {
+ $rootdirinzip = $what;
+
+ global $dolibarr_allow_download_external_modules;
+ if (empty($dolibarr_allow_download_external_modules)) {
+ print 'Download of external modules is not allowed by $dolibarr_allow_download_external_modules in conf.php file';
+ $db->close();
+ exit();
+ }
+ }
+
+ $ret = dol_compress_dir($fulldirtocompress, $outputdir."/".$file, $compression, $excludefiles, $rootdirinzip);
if ($ret < 0) {
if ($ret == -2) {
$langs->load("errors");
@@ -183,17 +199,37 @@ if ($compression == 'zip') {
unlink($outputdir."/".$file);
}
}
-}
-
-if ($errormsg) {
- setEventMessages($langs->trans("Error")." : ".$errormsg, null, 'errors');
} else {
- setEventMessages($langs->trans("BackupFileSuccessfullyCreated").'.
'.$langs->trans("YouCanDownloadBackupFile"), null, 'mesgs');
+ $errormsg = 'Bad value for compression method';
+ print $errormsg;
}
-$db->close();
+if ($export_type != 'externalmodule' || empty($what)) {
+ if ($errormsg) {
+ setEventMessages($langs->trans("Error")." : ".$errormsg, null, 'errors');
+ } else {
+ setEventMessages($langs->trans("BackupFileSuccessfullyCreated").'.
'.$langs->trans("YouCanDownloadBackupFile"), null, 'mesgs');
+ }
-// Redirect to calling page
-$returnto = 'dolibarr_export.php';
+ $db->close();
-header("Location: ".$returnto);
+ // Redirect to calling page
+ $returnto = 'dolibarr_export.php';
+
+ header("Location: ".$returnto);
+ exit();
+} else {
+ $zipname = $outputdir."/".$file;
+
+ // Then download the zipped file.
+ header('Content-Type: application/zip');
+ header('Content-disposition: attachment; filename='.basename($zipname));
+ header('Content-Length: '.filesize($zipname));
+ readfile($zipname);
+
+ dol_delete_file($zipname);
+
+ $db->close();
+
+ exit();
+}
diff --git a/htdocs/compta/accounting-files.php b/htdocs/compta/accounting-files.php
index 855505a40ec..1f821bf733b 100644
--- a/htdocs/compta/accounting-files.php
+++ b/htdocs/compta/accounting-files.php
@@ -499,7 +499,7 @@ if ($result && $action == "dl" && !$error) {
$zip->addFromString('transactions.csv', $log);
$zip->close();
- ///Then download the zipped file.
+ // Then download the zipped file.
header('Content-Type: application/zip');
header('Content-disposition: attachment; filename='.basename($zipname));
header('Content-Length: '.filesize($zipname));
diff --git a/htdocs/conf/conf.php.example b/htdocs/conf/conf.php.example
index 71f0a82e32f..7bb58d6b701 100644
--- a/htdocs/conf/conf.php.example
+++ b/htdocs/conf/conf.php.example
@@ -331,6 +331,12 @@ $dolibarr_cron_allow_cli='0';
// Examples:
// $dolibarr_strict_mode=0;
+// dolibarr_allow_download_external_modules
+// Provide a link to download the zip of an external modules installed into custom directory from the web admin.
+// Default value: 0
+// Examples:
+// $dolibarr_allow_download_external_modules=0;
+
//#################################
diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php
index 2bd4ada3ad0..7312faf6b5e 100644
--- a/htdocs/core/lib/files.lib.php
+++ b/htdocs/core/lib/files.lib.php
@@ -2004,11 +2004,15 @@ function dol_compress_file($inputfile, $outputfile, $mode = "gz", &$errorstring
// Skip directories (they would be added automatically)
if (!$file->isDir()) {
// Get real and relative path for current file
- $filePath = $file->getRealPath();
- $relativePath = substr($filePath, strlen($rootPath) + 1);
+ $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
+ $fileName = $file->getFilename();
+ $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
+
+ //$relativePath = substr($fileFullRealPath, strlen($rootPath) + 1);
+ $relativePath = substr(($filePath ? $filePath.'/' : '').$fileName, strlen($rootPath) + 1);
// Add current file to archive
- $zip->addFile($filePath, $relativePath);
+ $zip->addFile($fileFullRealPath, $relativePath);
}
}
@@ -2196,22 +2200,29 @@ function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles =
}
// Create recursive directory iterator
+ // This does not return symbolic links
/** @var SplFileInfo[] $files */
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($inputdir),
RecursiveIteratorIterator::LEAVES_ONLY
);
+ //var_dump($inputdir);
foreach ($files as $name => $file) {
// Skip directories (they would be added automatically)
if (!$file->isDir()) {
// Get real and relative path for current file
- $filePath = $file->getRealPath();
- $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($filePath, strlen($inputdir) + 1);
+ $filePath = $file->getPath(); // the full path with filename using the $inputdir root.
+ $fileName = $file->getFilename();
+ $fileFullRealPath = $file->getRealPath(); // the full path with name and transformed to use real path directory.
- if (empty($excludefiles) || !preg_match($excludefiles, $filePath)) {
+ //$relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr($fileFullRealPath, strlen($inputdir) + 1);
+ $relativePath = ($rootdirinzip ? $rootdirinzip.'/' : '').substr(($filePath ? $filePath.'/' : '').$fileName, strlen($inputdir) + 1);
+
+ //var_dump($filePath);var_dump($fileFullRealPath);var_dump($relativePath);
+ if (empty($excludefiles) || !preg_match($excludefiles, $fileFullRealPath)) {
// Add current file to archive
- $zip->addFile($filePath, $relativePath);
+ $zip->addFile($fileFullRealPath, $relativePath);
}
}
}