diff --git a/composer.json b/composer.json
index ec1d512445..bdc9e01290 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
"guzzlehttp/guzzle": "^7.5.1",
"league/oauth2-google": "^4.0.1",
"nikic/php-parser": "^4.14.0",
- "pear/archive_tar": "~1.4.14",
+ "pear/archive_tar": "^1.6.0",
"pelago/emogrifier": "^7.2.0",
"psr/log": "^3.0.0",
"scssphp/scssphp": "^1.12.1",
diff --git a/composer.lock b/composer.lock
index d2d5c710ba..aee9ef9cee 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "0da5da3b165955f386268e6dd8db2a8d",
+ "content-hash": "9225d70a5057480846b969102fc8b814",
"packages": [
{
"name": "apereo/phpcas",
@@ -842,21 +842,21 @@
},
{
"name": "pear/archive_tar",
- "version": "1.4.14",
+ "version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/pear/Archive_Tar.git",
- "reference": "4d761c5334c790e45ef3245f0864b8955c562caa"
+ "reference": "dc3285537f1832da8ddbbe45f5a007248b6cc00e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/4d761c5334c790e45ef3245f0864b8955c562caa",
- "reference": "4d761c5334c790e45ef3245f0864b8955c562caa",
+ "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/dc3285537f1832da8ddbbe45f5a007248b6cc00e",
+ "reference": "dc3285537f1832da8ddbbe45f5a007248b6cc00e",
"shasum": ""
},
"require": {
"pear/pear-core-minimal": "^1.10.0alpha2",
- "php": ">=5.2.0"
+ "php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "*"
@@ -882,7 +882,7 @@
"./"
],
"license": [
- "BSD-3-Clause"
+ "BSD-2-Clause"
],
"authors": [
{
@@ -908,17 +908,7 @@
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Archive_Tar",
"source": "https://github.com/pear/Archive_Tar"
},
- "funding": [
- {
- "url": "https://github.com/mrook",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/michielrook",
- "type": "patreon"
- }
- ],
- "time": "2021-07-20T13:53:39+00:00"
+ "time": "2025-07-19T14:49:16+00:00"
},
{
"name": "pear/console_getopt",
diff --git a/datamodels/2.x/itop-backup/backup.php b/datamodels/2.x/itop-backup/backup.php
index 49c5252e65..d9ed4eee68 100644
--- a/datamodels/2.x/itop-backup/backup.php
+++ b/datamodels/2.x/itop-backup/backup.php
@@ -114,8 +114,7 @@ function ExecuteMainOperation($oP)
exit;
}
- $sDefaultBackupFileName = SetupUtils::GetTmpDir().'/'."__DB__-%Y-%m-%d";
- $sBackupFile = utils::ReadParam('backup_file', $sDefaultBackupFileName, true, 'raw_data');
+ $sBackupFile = utils::ReadParam('backup_file', BACKUP_DEFAULT_FORMAT, true, 'raw_data');
// Interpret strftime specifications (like %Y) and database placeholders
$oBackup = new MyDBBackup($oP);
diff --git a/datamodels/2.x/itop-backup/dbrestore.class.inc.php b/datamodels/2.x/itop-backup/dbrestore.class.inc.php
index ca211cc9c6..5bb0f1ef5b 100644
--- a/datamodels/2.x/itop-backup/dbrestore.class.inc.php
+++ b/datamodels/2.x/itop-backup/dbrestore.class.inc.php
@@ -119,29 +119,25 @@ public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production'
IssueLog::Info('Backup Restore - LOCK acquired, executing...');
$bReadonlyBefore = SetupUtils::EnterMaintenanceMode(MetaModel::GetConfig());
+ $sDataDir = static::GetTmpDir($this->oConfig); // Here is the directory
+
try {
//safe zone for db backup => cron is stopped/ itop in readonly
$this->LogInfo("Starting restore of ".basename($sFile));
$sNormalizedFile = strtolower(basename($sFile));
- if (substr($sNormalizedFile, -4) == '.zip') {
- $this->LogInfo('zip file detected');
- $oArchive = new ZipArchiveEx();
- $oArchive->open($sFile);
- } elseif (substr($sNormalizedFile, -7) == '.tar.gz') {
+ if (str_ends_with($sNormalizedFile, '.tar.gz')) {
$this->LogInfo('tar.gz file detected');
$oArchive = new TarGzArchive($sFile);
+ if (!$oArchive->extractTo($sDataDir)) {
+ throw new BackupException('Failed to extract archive.');
+ }
} else {
throw new BackupException('Unsupported format for a backup file: '.$sFile);
}
// Load the database
//
- $sDataDir = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax());
-
- SetupUtils::builddir($sDataDir); // Here is the directory
- $oArchive->extractTo($sDataDir);
-
$sDataFile = $sDataDir.'/itop-dump.sql';
$this->LoadDatabase($sDataFile);
@@ -177,12 +173,6 @@ public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production'
rename($sSourceFilePath, $sDestinationFilePath);
}
- try {
- SetupUtils::rrmdir($sDataDir);
- } catch (Exception $e) {
- throw new BackupException("Can't remove data dir", 0, $e);
- }
-
$oEnvironment = new RunTimeEnvironment($sEnvironment);
$oEnvironment->CompileFrom($sEnvironment);
} finally {
@@ -192,6 +182,12 @@ public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production'
//we are in the scope of main process that needs to handle/keep readonly mode.
$this->LogInfo("Keep maintenance mode after restore");
}
+
+ try {
+ SetupUtils::rrmdir($sDataDir);
+ } catch (Exception $e) {
+ throw new BackupException("Can't remove tmp folder", previous: $e);
+ }
}
} finally {
IssueLog::Info('Backup Restore - LOCK released.');
diff --git a/datamodels/2.x/itop-backup/module.itop-backup.php b/datamodels/2.x/itop-backup/module.itop-backup.php
index 239156e833..8d2dd0dc88 100644
--- a/datamodels/2.x/itop-backup/module.itop-backup.php
+++ b/datamodels/2.x/itop-backup/module.itop-backup.php
@@ -51,6 +51,7 @@
'retention_count' => 5,
'enabled' => true,
'itop_backup_incident' => '',
+ 'backup_tmpdir' => 'data/',
],
]
);
diff --git a/lib/composer/installed.json b/lib/composer/installed.json
index 7b246762bb..2c85b1e4a1 100644
--- a/lib/composer/installed.json
+++ b/lib/composer/installed.json
@@ -869,22 +869,22 @@
},
{
"name": "pear/archive_tar",
- "version": "1.4.14",
- "version_normalized": "1.4.14.0",
+ "version": "1.6.0",
+ "version_normalized": "1.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/pear/Archive_Tar.git",
- "reference": "4d761c5334c790e45ef3245f0864b8955c562caa"
+ "reference": "dc3285537f1832da8ddbbe45f5a007248b6cc00e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/4d761c5334c790e45ef3245f0864b8955c562caa",
- "reference": "4d761c5334c790e45ef3245f0864b8955c562caa",
+ "url": "https://api.github.com/repos/pear/Archive_Tar/zipball/dc3285537f1832da8ddbbe45f5a007248b6cc00e",
+ "reference": "dc3285537f1832da8ddbbe45f5a007248b6cc00e",
"shasum": ""
},
"require": {
"pear/pear-core-minimal": "^1.10.0alpha2",
- "php": ">=5.2.0"
+ "php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "*"
@@ -894,7 +894,7 @@
"ext-xz": "Lzma2 compression support.",
"ext-zlib": "Gzip compression support."
},
- "time": "2021-07-20T13:53:39+00:00",
+ "time": "2025-07-19T14:49:16+00:00",
"type": "library",
"extra": {
"branch-alias": {
@@ -912,7 +912,7 @@
"./"
],
"license": [
- "BSD-3-Clause"
+ "BSD-2-Clause"
],
"authors": [
{
@@ -938,16 +938,6 @@
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=Archive_Tar",
"source": "https://github.com/pear/Archive_Tar"
},
- "funding": [
- {
- "url": "https://github.com/mrook",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/michielrook",
- "type": "patreon"
- }
- ],
"install-path": "../pear/archive_tar"
},
{
diff --git a/lib/composer/installed.php b/lib/composer/installed.php
index 1a90038ddd..637054cb09 100644
--- a/lib/composer/installed.php
+++ b/lib/composer/installed.php
@@ -3,7 +3,7 @@
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
- 'reference' => 'c88ba664db4ec5622838a0ee00768e3bc3381d4e',
+ 'reference' => 'd92eacce81e5f653ee9fc6fe21724fde392e9865',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -22,7 +22,7 @@
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
- 'reference' => 'c88ba664db4ec5622838a0ee00768e3bc3381d4e',
+ 'reference' => 'd92eacce81e5f653ee9fc6fe21724fde392e9865',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -119,9 +119,9 @@
'dev_requirement' => false,
),
'pear/archive_tar' => array(
- 'pretty_version' => '1.4.14',
- 'version' => '1.4.14.0',
- 'reference' => '4d761c5334c790e45ef3245f0864b8955c562caa',
+ 'pretty_version' => '1.6.0',
+ 'version' => '1.6.0.0',
+ 'reference' => 'dc3285537f1832da8ddbbe45f5a007248b6cc00e',
'type' => 'library',
'install_path' => __DIR__ . '/../pear/archive_tar',
'aliases' => array(),
diff --git a/lib/pear/archive_tar/.travis.yml b/lib/pear/archive_tar/.travis.yml
deleted file mode 100644
index f103381b10..0000000000
--- a/lib/pear/archive_tar/.travis.yml
+++ /dev/null
@@ -1,29 +0,0 @@
-sudo: false
-language: php
-matrix:
- fast_finish: true
- allow_failures:
- - php: nightly
- include:
- - php: 5.2
- dist: precise
- - php: 5.3
- dist: precise
- - php: 5.4
- dist: trusty
- - php: 5.5
- dist: trusty
- - php: 5.6
- - php: 7.0
- - php: 7.1
- - php: 7.2
- - php: 7.3
- - php: 7.4
- - php: nightly
-install:
-# - pear upgrade --force --alldeps pear/pear
- - pear install -f package.xml
-script:
- - pear version
- - pear run-tests -qr tests/
- - for i in `find tests/ -name '*.out'`; do echo "$i"; cat "$i"; done
diff --git a/lib/pear/archive_tar/Archive/Tar.php b/lib/pear/archive_tar/Archive/Tar.php
index 3356ad6ac1..7ce09491de 100644
--- a/lib/pear/archive_tar/Archive/Tar.php
+++ b/lib/pear/archive_tar/Archive/Tar.php
@@ -48,27 +48,6 @@
define('ARCHIVE_TAR_ATT_SEPARATOR', 90001);
define('ARCHIVE_TAR_END_BLOCK', pack("a512", ''));
-if (!function_exists('gzopen') && function_exists('gzopen64')) {
- function gzopen($filename, $mode, $use_include_path = 0)
- {
- return gzopen64($filename, $mode, $use_include_path);
- }
-}
-
-if (!function_exists('gztell') && function_exists('gztell64')) {
- function gztell($zp)
- {
- return gztell64($zp);
- }
-}
-
-if (!function_exists('gzseek') && function_exists('gzseek64')) {
- function gzseek($zp, $offset, $whence = SEEK_SET)
- {
- return gzseek64($zp, $offset, $whence);
- }
-}
-
/**
* Creates a (compressed) Tar archive
*
@@ -244,7 +223,7 @@ public function __construct($p_tarname, $p_compress = null, $buffer_length = 512
"a8checksum/a1typeflag/a100link/a6magic/a2version/" .
"a32uname/a32gname/a8devmajor/a8devminor/a131prefix";
} else {
- $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/Z12size/Z12mtime/" .
+ $this->_fmt = "Z100filename/Z8mode/Z8uid/Z8gid/a12size/Z12mtime/" .
"Z8checksum/Z1typeflag/Z100link/Z6magic/Z2version/" .
"Z32uname/Z32gname/Z8devmajor/Z8devminor/Z131prefix";
}
@@ -280,7 +259,7 @@ public function __destruct()
* single string with names separated by a single
* blank space.
*
- * @return true on success, false on error.
+ * @return bool true on success, false on error.
* @see createModify()
*/
public function create($p_filelist)
@@ -300,7 +279,7 @@ public function create($p_filelist)
* single string with names separated by a single
* blank space.
*
- * @return true on success, false on error.
+ * @return bool true on success, false on error.
* @see createModify()
* @access public
*/
@@ -443,7 +422,7 @@ public function createModify($p_filelist, $p_add_dir, $p_remove_dir = '')
* each element in the list, when
* relevant.
*
- * @return true on success, false on error.
+ * @return bool true on success, false on error.
*/
public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
{
@@ -496,7 +475,7 @@ public function addModify($p_filelist, $p_add_dir, $p_remove_dir = '')
* gid => the group ID of the file
* (default = 0 = root)
*
- * @return true on success, false on error.
+ * @return bool true on success, false on error.
*/
public function addString($p_filename, $p_string, $p_datetime = false, $p_params = array())
{
@@ -622,7 +601,7 @@ public function extractInString($p_filename)
* @param boolean $p_preserve Preserve user/group ownership of files
* @param boolean $p_symlinks Allow symlinks.
*
- * @return true on success, false on error.
+ * @return bool true on success, false on error.
* @see extractModify()
*/
public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_preserve = false, $p_symlinks = true)
@@ -660,7 +639,7 @@ public function extractList($p_filelist, $p_path = '', $p_remove_path = '', $p_p
* list of parameters, in the format attribute code + attribute values :
* $arch->setAttribute(ARCHIVE_TAR_ATT_SEPARATOR, ',');
*
- * @return true on success, false on error.
+ * @return bool true on success, false on error.
*/
public function setAttribute()
{
@@ -991,48 +970,45 @@ public function _writeBlock($p_binary_data, $p_len = null)
{
if (is_resource($this->_file)) {
if ($p_len === null) {
- if ($this->_compress_type == 'gz') {
- @gzputs($this->_file, $p_binary_data);
- } else {
- if ($this->_compress_type == 'bz2') {
- @bzwrite($this->_file, $p_binary_data);
- } else {
- if ($this->_compress_type == 'lzma2') {
- @xzwrite($this->_file, $p_binary_data);
- } else {
- if ($this->_compress_type == 'none') {
- @fputs($this->_file, $p_binary_data);
- } else {
- $this->_error(
- 'Unknown or missing compression type ('
- . $this->_compress_type . ')'
- );
- }
- }
- }
- }
- } else {
- if ($this->_compress_type == 'gz') {
- @gzputs($this->_file, $p_binary_data, $p_len);
- } else {
- if ($this->_compress_type == 'bz2') {
- @bzwrite($this->_file, $p_binary_data, $p_len);
- } else {
- if ($this->_compress_type == 'lzma2') {
- @xzwrite($this->_file, $p_binary_data, $p_len);
- } else {
- if ($this->_compress_type == 'none') {
- @fputs($this->_file, $p_binary_data, $p_len);
- } else {
- $this->_error(
- 'Unknown or missing compression type ('
- . $this->_compress_type . ')'
- );
- }
- }
- }
- }
+ switch ($this->_compress_type)
+ {
+ case 'gz':
+ $bytes = @gzwrite($this->_file, $p_binary_data);
+ break;
+ case 'bz2':
+ $bytes = @bzwrite($this->_file, $p_binary_data);
+ break;
+ case 'lzma2':
+ $bytes = @xzwrite($this->_file, $p_binary_data);
+ break;
+ case 'none':
+ $bytes = @fwrite($this->_file, $p_binary_data);
+ break;
+ default:
+ $this->_error('Unknown or missing compression type (' . $this->_compress_type . ')');
+ return false;
+ }
+ } else {
+ switch ($this->_compress_type)
+ {
+ case 'gz':
+ $bytes = @gzwrite($this->_file, $p_binary_data, $p_len);
+ break;
+ case 'bz2':
+ $bytes = @bzwrite($this->_file, $p_binary_data, $p_len);
+ break;
+ case 'lzma2':
+ $bytes = @xzwrite($this->_file, $p_binary_data, $p_len);
+ break;
+ case 'none':
+ $bytes = @fwrite($this->_file, $p_binary_data, $p_len);
+ break;
+ default:
+ $this->_error('Unknown or missing compression type (' . $this->_compress_type . ')');
+ return false;
+ }
}
+ return $bytes !== false;
}
return true;
}
@@ -1117,7 +1093,7 @@ public function _writeFooter()
if (is_resource($this->_file)) {
// ----- Write the last 0 filled block for end of archive
$v_binary_data = pack('a1024', '');
- $this->_writeBlock($v_binary_data);
+ return $this->_writeBlock($v_binary_data);
}
return true;
}
@@ -1279,7 +1255,9 @@ public function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $v_
$pack_format = sprintf('a%d', $this->buffer_length);
}
$v_binary_data = pack($pack_format, "$v_buffer");
- $this->_writeBlock($v_binary_data);
+ if(!$this->_writeBlock($v_binary_data)) {
+ return false;
+ }
}
fclose($v_file);
@@ -1341,7 +1319,9 @@ public function _addString($p_filename, $p_string, $p_datetime = false, $p_param
$i = 0;
while (($v_buffer = substr($p_string, (($i++) * 512), 512)) != '') {
$v_binary_data = pack("a512", $v_buffer);
- $this->_writeBlock($v_binary_data);
+ if (!$this->_writeBlock($v_binary_data)) {
+ return false;
+ }
}
return true;
@@ -2115,7 +2095,7 @@ public function _extractList(
if ($v_extract_file) {
if ($v_header['typeflag'] == "5") {
if (!@file_exists($v_header['filename'])) {
- if (!@mkdir($v_header['filename'], 0777)) {
+ if (!@mkdir($v_header['filename'], 0775)) {
$this->_error(
'Unable to create directory {'
. $v_header['filename'] . '}'
@@ -2448,7 +2428,7 @@ public function _dirCheck($p_dir)
return false;
}
- if (!@mkdir($p_dir, 0777)) {
+ if (!@mkdir($p_dir, 0775)) {
$this->_error("Unable to create directory '$p_dir'");
return false;
}
diff --git a/lib/pear/archive_tar/SECURITY.md b/lib/pear/archive_tar/SECURITY.md
new file mode 100644
index 0000000000..b34d974fec
--- /dev/null
+++ b/lib/pear/archive_tar/SECURITY.md
@@ -0,0 +1,5 @@
+# Reporting Security Issues
+
+The Archive_Tar team and PEAR community take security bugs seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
+
+To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/pear/Archive_Tar/security/advisories/new) tab.
diff --git a/lib/pear/archive_tar/composer.json b/lib/pear/archive_tar/composer.json
index e464d9d7b7..09c996b1b7 100644
--- a/lib/pear/archive_tar/composer.json
+++ b/lib/pear/archive_tar/composer.json
@@ -7,7 +7,7 @@
"tar"
],
"homepage": "https://github.com/pear/Archive_Tar",
- "license": "BSD-3-Clause",
+ "license": "BSD-2-Clause",
"authors": [
{
"name": "Vincent Blavet",
@@ -23,7 +23,7 @@
}
],
"require": {
- "php": ">=5.2.0",
+ "php": ">=5.4.0",
"pear/pear-core-minimal": "^1.10.0alpha2"
},
"suggest": {
diff --git a/lib/pear/archive_tar/package.xml b/lib/pear/archive_tar/package.xml
index d4f20bd4b0..93ba5d3256 100644
--- a/lib/pear/archive_tar/package.xml
+++ b/lib/pear/archive_tar/package.xml
@@ -24,6 +24,12 @@ Also Lzma2 compressed archives are supported with xz extension.
Michiel Rook
mrook
mrook@php.net
+ no
+
+
+ Drew Webber
+ mcdruid
+ drew@mcdruid.co.uk
yes
@@ -32,11 +38,10 @@ Also Lzma2 compressed archives are supported with xz extension.
stig@php.net
no
- 2021-07-20
-
+ 2025-07-19
- 1.4.14
- 1.4.0
+ 1.6.0
+ 1.6.0
stable
@@ -44,7 +49,11 @@ Also Lzma2 compressed archives are supported with xz extension.
New BSD License
-* Properly fix symbolic link path traversal (CVE-2021-32610)
+This release drops support for PHP 5.4 and 5.5.
+
+* PR #51: big file support
+* PR #53: Fix return value of _writeBlock
+* PR #58: Remove gzopen/gztell/gzseek shim
@@ -65,15 +74,65 @@ Also Lzma2 compressed archives are supported with xz extension.
- 5.2.0
+ 5.6.0
- 1.9.0
+ 1.10.0
+
+
+ 1.6.0
+ 1.6.0
+
+
+ stable
+ stable
+
+ 2025-07-19
+ New BSD License
+
+ This release drops support for PHP 5.4 and 5.5.
+
+ * PR #51: big file support
+ * PR #53: Fix return value of _writeBlock
+ * PR #58: Remove gzopen/gztell/gzseek shim
+
+
+
+
+ 1.5.0
+ 1.5.0
+
+
+ stable
+ stable
+
+ 2024-03-16
+ New BSD License
+
+ * PR #42: fix @return true... to @return bool true... on some functions
+ * PR #46: use 775 default for mkdirs, to avoid world-write
+
+
+
+
+ 1.4.14
+ 1.4.0
+
+
+ stable
+ stable
+
+ 2021-02-16
+ New BSD License
+
+ * Properly fix symbolic link path traversal (CVE-2021-32610)
+
+
1.4.13
diff --git a/setup/backup.class.inc.php b/setup/backup.class.inc.php
index 86edd3e978..b15bce964f 100644
--- a/setup/backup.class.inc.php
+++ b/setup/backup.class.inc.php
@@ -201,20 +201,22 @@ public function CreateCompressedBackup($sTargetFile, $sSourceConfigFile = null)
$oArchive = new ITopArchiveTar($sTargetFile.'.tar.gz');
- $sTmpFolder = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax());
+ $sTmpFolder = static::GetTmpDir($this->oConfig);
$aFiles = $this->PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder);
$sFilesList = var_export($aFiles, true);
$this->LogInfo("backup: adding to archive files '$sFilesList'");
$bArchiveCreationResult = $oArchive->createModify($aFiles, '', $sTmpFolder);
+
+ $this->LogInfo("backup: removing tmp folder '$sTmpFolder'");
+ SetupUtils::rrmdir($sTmpFolder);
+
if (!$bArchiveCreationResult) {
+ @unlink($sTargetFile.'.tar.gz');
$sErrorMsg = 'Cannot backup : unable to create archive';
$this->LogError($sErrorMsg);
throw new BackupException($sErrorMsg);
}
-
- $this->LogInfo("backup: removing tmp folder '$sTmpFolder'");
- SetupUtils::rrmdir($sTmpFolder);
}
/**
@@ -603,6 +605,18 @@ public static function MakeSafeMySQLCommand($sMySQLBinDir, string $sCmd)
return '"'.$sMySQLCommand.'"';
}
+
+ /**
+ * Return a directory name for temporary backup files.
+ */
+ public static function GetTmpDir(Config $oConfig): string
+ {
+ $sTmpDir = @tempnam($oConfig->GetModuleSetting('itop-backup', 'backup_tmpdir', 'data/') , 'itop-backup-');
+ unlink($sTmpDir); // I need a directory, not a file...
+ SetupUtils::builddir($sTmpDir);
+
+ return $sTmpDir;
+ }
}
class TarGzArchive implements BackupArchive
diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php
index ab1eaa1b12..ecfe61393c 100644
--- a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php
+++ b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php
@@ -187,9 +187,7 @@ public static function GetAppRoot()
return APPROOT;
}
- $sAppRootPath = static::GetFirstDirUpContainingFile(__DIR__, 'approot.inc.php');
-
- return $sAppRootPath.'/';
+ return static::GetFirstDirUpContainingFile(__DIR__, 'approot.inc.php');
}
private static function GetFirstDirUpContainingFile(string $sSearchPath, string $sFileToFindGlobPattern): ?string
diff --git a/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php b/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php
index 03e947f6d9..f21f96e793 100644
--- a/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php
+++ b/tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php
@@ -2,6 +2,7 @@
namespace Combodo\iTop\Test\UnitTest\Core;
+use BackupException;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use DBBackup;
use DBRestore;
@@ -80,7 +81,7 @@ public function prepareFilesToBackupProvider()
*/
public function testRestoreListExtraFiles($aFilesToCreate, $aExpectedRelativeExtraFiles)
{
- require_once(APPROOT.'/env-production/itop-backup/dbrestore.class.inc.php');
+ $this->RequireOnceItopFile('/env-production/itop-backup/dbrestore.class.inc.php');
$sTmpDir = sys_get_temp_dir().'/testRestoreListExtraFiles-'.time();
@@ -119,4 +120,19 @@ public function restoreListExtraFilesProvider()
];
}
+ public function testRestoreFromCompressedBackup()
+ {
+ $this->RequireOnceItopFile('env-production/itop-backup/dbrestore.class.inc.php');
+
+ $oConfig = \utils::GetConfig();
+ $oRestore = new DBRestore($oConfig);
+
+ $this->expectException(BackupException::class);
+
+ $this->expectExceptionMessage('Failed to extract archive.');
+ $oRestore->RestoreFromCompressedBackup('nonexistent.tar.gz');
+
+ $this->expectExceptionMessage('Unsupported format for a backup file: very_old_backup.zip');
+ $oRestore->RestoreFromCompressedBackup('very_old_backup.zip');
+ }
}
diff --git a/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php b/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
index 37a582df10..85c96e53b0 100644
--- a/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
+++ b/tests/php-unit-tests/unitary-tests/setup/DBBackupTest.php
@@ -190,4 +190,44 @@ public function MakeNameProvider(): array
],
];
}
+
+ /**
+ * @covers DBBackup::GetTmpDir
+ * @dataProvider GetTmpDirProvider
+ */
+ public function testGetTmpDir(?string $sTmpDir, string $sStartsWith): void
+ {
+ $this->RequireOnceItopFile('setup/setuputils.class.inc.php');
+ $oConfig = \utils::GetConfig(true);
+ $oConfig->SetModuleSetting('itop-backup', 'backup_tmpdir', $sTmpDir);
+
+ $sTestedTmpDir = \DBBackup::GetTmpDir($oConfig);
+
+ $this->assertDirectoryExists($sTestedTmpDir);
+ rmdir($sTestedTmpDir);
+
+ $this->assertStringStartsWith($sStartsWith, $sTestedTmpDir);
+ }
+
+ public function GetTmpDirProvider(): array
+ {
+ return [
+ 'Not configured' => [
+ 'tmp_dir' => null,
+ 'starts_with' => static::GetAppRoot() . 'data/itop-backup',
+ ],
+ 'Empty conf' => [
+ 'tmp_dir' => '',
+ 'starts_with' => static::GetAppRoot() . 'data/itop-backup',
+ ],
+ 'Default settings' => [
+ 'tmp_dir' => 'data/',
+ 'starts_with' => static::GetAppRoot() . 'data/itop-backup',
+ ],
+ 'System temporary directory' => [
+ 'tmp_dir' => '/tmp',
+ 'starts_with' => '/tmp/itop-backup',
+ ],
+ ];
+ }
}