mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 15:34:12 +01:00
206 lines
7.0 KiB
PHP
206 lines
7.0 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Copyright (C) 2010-2024 Combodo SAS
|
|
*
|
|
* This file is part of iTop.
|
|
*
|
|
* iTop is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* iTop is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
*/
|
|
|
|
use Combodo\iTop\Application\WebPage\AjaxPage;
|
|
use Combodo\iTop\Application\WebPage\JsonPage;
|
|
use Combodo\iTop\Application\WebPage\WebPage;
|
|
|
|
if (!defined('APPROOT')) {
|
|
require_once(__DIR__.'/../../approot.inc.php');
|
|
}
|
|
require_once(APPROOT.'/application/application.inc.php');
|
|
|
|
require_once(APPROOT.'core/mutex.class.inc.php');
|
|
|
|
/**
|
|
* @param WebPage $oPage
|
|
* @param string $sHtmlErrorMessage the whole HTML error, cinluding div/p/...
|
|
* @param int|string $exitCode
|
|
*
|
|
* @uses \die() https://www.php.net/manual/fr/function.die.php
|
|
*
|
|
* @since 2.6.5 2.7.1 N°2989
|
|
*/
|
|
function DisplayErrorAndDie($oPage, $sHtmlErrorMessage, $exitCode = null)
|
|
{
|
|
$oPage->add($sHtmlErrorMessage);
|
|
$oPage->output();
|
|
|
|
die($exitCode);
|
|
}
|
|
|
|
$sOperation = utils::ReadParam('operation', '');
|
|
|
|
$oPage = new AjaxPage('');
|
|
$oPage->SetContentType('text/html');
|
|
|
|
/**
|
|
* Check security
|
|
*/
|
|
switch ($sOperation) {
|
|
/**
|
|
* Can't use normal check methods (DoLogin for ex) as the datamodel can't be loaded here
|
|
* So we're only using a token generated in the restore_token operation
|
|
*/
|
|
case 'restore_exec':
|
|
IssueLog::Enable(APPROOT.'log/error.log');
|
|
if (utils::GetConfig()->Get('demo_mode')) {
|
|
DisplayErrorAndDie(
|
|
$oPage,
|
|
'<div data-error-stimulus="Error">Sorry, '.ITOP_APPLICATION_SHORT.' is in <b>demonstration mode</b>: the feature is disabled.</div>'
|
|
);
|
|
}
|
|
|
|
$sToken = utils::ReadParam('token', '', false, 'raw_data');
|
|
$sBasePath = APPROOT.'/data/';
|
|
$sTokenFile = $sBasePath.'restore.'.$sToken.'.tok';
|
|
$tokenRealPath = utils::RealPath($sTokenFile, $sBasePath);
|
|
if (($tokenRealPath === false) || (!is_file($tokenRealPath))) {
|
|
IssueLog::Error("ajax.backup.php operation=$sOperation ERROR = inexisting token $sToken");
|
|
$sEscapedToken = utils::HtmlEntities($sToken);
|
|
DisplayErrorAndDie($oPage, "<p>Error: missing token file: '$sEscapedToken'</p>");
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
require_once(APPROOT.'/application/startup.inc.php');
|
|
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
|
|
|
LoginWebPage::DoLogin();
|
|
|
|
$sTransactionId = utils::ReadParam('transaction_id', '', true, 'transaction_id');
|
|
// the consumer page is not reloaded after download, we need to keep the transaction_id
|
|
$bRemoveTransactionId = ($sOperation !== 'download');
|
|
if (!utils::IsTransactionValid($sTransactionId, $bRemoveTransactionId)) {
|
|
$sEscapedOperation = utils::HtmlEntities($sOperation);
|
|
DisplayErrorAndDie($oPage, "<div data-error-stimulus=\"Error\">Error: invalid Transaction ID. The operation '$sEscapedOperation' was NOT performed!</div>");
|
|
}
|
|
|
|
ApplicationMenu::CheckMenuIdEnabled('BackupStatus');
|
|
|
|
if (utils::GetConfig()->Get('demo_mode')) {
|
|
DisplayErrorAndDie($oPage, '<div data-error-stimulus="Error">Sorry, '.ITOP_APPLICATION_SHORT.' is in <b>demonstration mode</b>: the feature is disabled.</div>');
|
|
}
|
|
break;
|
|
}
|
|
|
|
/**
|
|
* Backup from an interactive session
|
|
*/
|
|
try {
|
|
switch ($sOperation) {
|
|
case 'backup':
|
|
try {
|
|
set_time_limit(0);
|
|
$oBB = new BackupExec(utils::GetDataPath().'backups/manual/', 0 /*iRetentionCount*/);
|
|
$sRes = $oBB->Process(time() + 36000); // 10 hours to complete should be sufficient!
|
|
} catch (Exception $e) {
|
|
$oPage->p('Error: '.$e->getMessage());
|
|
IssueLog::Error($sOperation.' - '.$e->getMessage());
|
|
}
|
|
|
|
$oPage->output();
|
|
break;
|
|
|
|
/*
|
|
* Fix a specific token :
|
|
* We can't load the MetaModel because in DBRestore, after restore is done we're launching a compile !
|
|
* So as LoginWebPage::DoLogin needs a loaded DataModel, we can't use it
|
|
* Also, we can't use \utils::IsTransactionValid as it uses \MetaModel::GetConfig
|
|
* As a result we're setting a token file to make sure the restore is called by an authenticated user with the correct rights !
|
|
*/
|
|
case 'restore_get_token':
|
|
$oPage = new JsonPage();
|
|
$oPage->SetOutputDataOnly(true);
|
|
|
|
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
|
|
$oRestoreMutex = new iTopMutex('restore.'.$sEnvironment);
|
|
if ($oRestoreMutex->IsLocked()) {
|
|
DisplayErrorAndDie($oPage, '<p>'.Dict::S('bkp-restore-running').'</p>');
|
|
}
|
|
|
|
$sFile = utils::ReadParam('file', '', false, 'raw_data');
|
|
$sToken = str_replace(' ', '', (string)microtime()).$sTransactionId;
|
|
$sTokenFile = APPROOT.'/data/restore.'.$sToken.'.tok';
|
|
file_put_contents($sTokenFile, $sFile);
|
|
|
|
$oPage->SetData(['token' => $sToken]);
|
|
$oPage->output();
|
|
break;
|
|
|
|
/*
|
|
* We can't call \LoginWebPage::DoLogin because DBRestore will do a compile after restoring the DB
|
|
* Authentication is checked with a token file (see $sOperation='restore_get_token')
|
|
*/
|
|
case 'restore_exec':
|
|
require_once(APPROOT."setup/runtimeenv.class.inc.php");
|
|
require_once(APPROOT.'/application/utils.inc.php');
|
|
require_once(APPROOT.'/setup/backup.class.inc.php');
|
|
require_once(__DIR__.'/dbrestore.class.inc.php');
|
|
|
|
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
|
|
try {
|
|
set_time_limit(0);
|
|
|
|
// Get the file and destroy the token (single usage)
|
|
$sFile = file_get_contents($tokenRealPath);
|
|
|
|
// Loading config file : we don't have the MetaModel but we have the current env !
|
|
$sConfigFilePath = utils::GetConfigFilePath($sEnvironment);
|
|
$oItopConfig = new Config($sConfigFilePath, true);
|
|
$sMySQLBinDir = $oItopConfig->GetModuleSetting('itop-backup', 'mysql_bindir', '');
|
|
|
|
$oDBRS = new DBRestore($oItopConfig);
|
|
$oDBRS->SetMySQLBinDir($sMySQLBinDir);
|
|
|
|
$sBackupDir = utils::GetDataPath().'backups/';
|
|
$sBackupFile = $sBackupDir.$sFile;
|
|
$sRes = $oDBRS->RestoreFromCompressedBackup($sBackupFile, $sEnvironment);
|
|
|
|
IssueLog::Info('Backup Restore - Done, releasing the LOCK');
|
|
} catch (Exception $e) {
|
|
$oPage->p('Error: '.$e->getMessage());
|
|
IssueLog::Error($sOperation.' - '.$e->getMessage());
|
|
} finally {
|
|
unlink($tokenRealPath);
|
|
}
|
|
|
|
$oPage->output();
|
|
break;
|
|
|
|
case 'download':
|
|
while (ob_get_level() > 0) {
|
|
ob_end_clean();
|
|
}
|
|
$sFile = utils::ReadParam('file', '', false, 'raw_data');
|
|
$oBackup = new DBBackupScheduled();
|
|
$sBackupDir = utils::GetDataPath().'backups/';
|
|
$sBackupFilePath = utils::RealPath($sBackupDir.$sFile, $sBackupDir);
|
|
if ($sBackupFilePath === false) {
|
|
throw new CoreUnexpectedValue('Invalid file path');
|
|
}
|
|
$oBackup->DownloadBackup($sBackupFilePath);
|
|
break;
|
|
}
|
|
} catch (Exception $e) {
|
|
IssueLog::Error($sOperation.' - '.$e->getMessage());
|
|
}
|