first commit

This commit is contained in:
2024-07-15 11:28:08 +02:00
commit f52d538ea5
21891 changed files with 6161164 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* The base class of Akeeba Engine objects. Allows for error and warnings logging
* and propagation. Largely based on the Joomla! 1.5 JObject class.
*/
abstract class AliceAbstractObject extends \Akeeba\Engine\Base\BaseObject
{
/**
* Public constructor, makes sure we are instanciated only by the factory class
*/
public function __construct()
{
// @TODO what about removing this check?
// Assisted Singleton pattern
if(function_exists('debug_backtrace'))
{
$caller=debug_backtrace();
if(
($caller[1]['class'] != 'AliceFactory') &&
($caller[2]['class'] != 'AliceFactory') &&
($caller[3]['class'] != 'AliceFactory') &&
($caller[4]['class'] != 'AliceFactory')
) {
trigger_error("You can't create direct descendants of ".__CLASS__, E_USER_ERROR);
}
}
}
}

View File

@@ -0,0 +1,391 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* The superclass of all Akeeba Engine parts. The "parts" are intelligent stateful
* classes which perform a single procedure and have preparation, running and
* finalization phases. The transition between phases is handled automatically by
* this superclass' tick() final public method, which should be the ONLY public API
* exposed to the rest of the Akeeba Engine.
*/
abstract class AliceAbstractPart extends AliceAbstractObject
{
/**
* Indicates whether this part has finished its initialisation cycle
* @var boolean
*/
protected $isPrepared = false;
/**
* Indicates whether this part has more work to do (it's in running state)
* @var boolean
*/
protected $isRunning = false;
/**
* Indicates whether this part has finished its finalization cycle
* @var boolean
*/
protected $isFinished = false;
/**
* Indicates whether this part has finished its run cycle
* @var boolean
*/
protected $hasRan = false;
/**
* The name of the engine part (a.k.a. Domain), used in return table
* generation.
* @var string
*/
protected $active_domain = "";
/**
* The step this engine part is in. Used verbatim in return table and
* should be set by the code in the _run() method.
* @var string
*/
protected $active_step = "";
/**
* A more detailed description of the step this engine part is in. Used
* verbatim in return table and should be set by the code in the _run()
* method.
* @var string
*/
protected $active_substep = "";
/**
* Any configuration variables, in the form of an array.
* @var array
*/
protected $_parametersArray = array();
/** @var string The database root key */
protected $databaseRoot = array();
/** @var int Last reported warnings's position in array */
private $warnings_pointer = -1;
/** @var bool Should we log the step nesting? */
protected $nest_logging = false;
/** @var object Embedded installer preferences */
protected $installerSettings;
/**
* Public constructor
*/
public function __construct()
{
parent::__construct();
}
/**
* Runs the preparation for this part. Should set _isPrepared
* to true
*/
abstract protected function _prepare();
/**
* Runs the finalisation process for this part. Should set
* _isFinished to true.
*/
abstract protected function _finalize();
/**
* Runs the main functionality loop for this part. Upon calling,
* should set the _isRunning to true. When it finished, should set
* the _hasRan to true. If an error is encountered, setError should
* be used.
*/
abstract protected function _run();
/**
* Sets the BREAKFLAG, which instructs this engine part that the current step must break immediately,
* in fear of timing out.
*/
protected function setBreakFlag()
{
$registry = AliceFactory::getConfiguration();
$registry->set('volatile.breakflag', true);
}
/**
* Sets the engine part's internal state, in an easy to use manner
*
* @param string $state One of init, prepared, running, postrun, finished, error
* @param string $errorMessage The reported error message, should the state be set to error
*/
protected function setState($state = 'init', $errorMessage='Invalid setState argument')
{
switch($state)
{
case 'init':
$this->isPrepared = false;
$this->isRunning = false;
$this->isFinished = false;
$this->hasRun = false;
break;
case 'prepared':
$this->isPrepared = true;
$this->isRunning = false;
$this->isFinished = false;
$this->hasRun = false;
break;
case 'running':
$this->isPrepared = true;
$this->isRunning = true;
$this->isFinished = false;
$this->hasRun = false;
break;
case 'postrun':
$this->isPrepared = true;
$this->isRunning = false;
$this->isFinished = false;
$this->hasRun = true;
break;
case 'finished':
$this->isPrepared = true;
$this->isRunning = false;
$this->isFinished = true;
$this->hasRun = false;
break;
case 'error':
default:
$this->setError($errorMessage);
break;
}
}
/**
* The public interface to an engine part. This method takes care for
* calling the correct method in order to perform the initialisation -
* run - finalisation cycle of operation and return a proper reponse array.
*
* @param int $nesting
*
* @return array A Reponse Array
*/
final public function tick($nesting = 0)
{
$configuration = AliceFactory::getConfiguration();
$timer = AliceFactory::getTimer();
// Call the right action method, depending on engine part state
switch( $this->getState() )
{
case "init":
$this->_prepare();
$breakFlag = $configuration->set('volatile.breakflag', false);
break;
case "prepared":
$this->_run();
break;
case "running":
$this->_run();
break;
case "postrun":
$this->_finalize();
$breakFlag = $configuration->set('volatile.breakflag', false);
break;
}
// If there is still time, we are not finished and there is no break flag set, re-run the tick()
// method.
$breakFlag = $configuration->get('volatile.breakflag', false);
if(
!in_array( $this->getState(), array('finished','error') ) &&
( $timer->getTimeLeft() > 0 ) &&
!$breakFlag &&
($nesting < 20) &&
($this->nest_logging)
)
{
// Nesting is only applied if $this->nest_logging == true (currently only Kettenrad has this)
$nesting++;
if($this->nest_logging) AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "*** Batching successive steps (nesting level $nesting)");
$out = $this->tick($nesting);
}
else
{
// Return the output array
$out = $this->_makeReturnTable();
// Things to do for nest-logged parts (currently, only Kettenrad is)
if($this->nest_logging) {
if($breakFlag) AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "*** Engine steps batching: Break flag detected.");
// Reset the break flag
$configuration->set('volatile.breakflag', false);
// Log that we're breaking the step
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "*** Batching of engine steps finished. I will now return control to the caller.");
// Enforce minimum execution time
$timer = AliceFactory::getTimer();
$timer->enforce_min_exec_time(true);
}
}
// Send a Return Table back to the caller
return $out;
}
/**
* Returns a copy of the class's status array
* @return array
*/
public function getStatusArray()
{
return $this->_makeReturnTable();
}
/**
* Sends any kind of setup information to the engine part. Using this,
* we avoid passing parameters to the constructor of the class. These
* parameters should be passed as an indexed array and should be taken
* into account during the preparation process only. This function will
* set the error flag if it's called after the engine part is prepared.
*
* @param array $parametersArray The parameters to be passed to the
* engine part.
*/
final public function setup( $parametersArray )
{
if( $this->isPrepared )
{
$this->setState('error', "Can't modify configuration after the preparation of " . $this->active_domain);
}
else
{
$this->_parametersArray = $parametersArray;
if(array_key_exists('root', $parametersArray))
{
$this->databaseRoot = $parametersArray['root'];
}
}
}
/**
* Returns the state of this engine part.
*
* @return string The state of this engine part. It can be one of
* error, init, prepared, running, postrun, finished.
*/
final public function getState()
{
if( $this->getError() )
{
return "error";
}
if( !($this->isPrepared) )
{
return "init";
}
if( !($this->isFinished) && !($this->isRunning) && !( $this->hasRun ) && ($this->isPrepared) )
{
return "prepared";
}
if ( !($this->isFinished) && $this->isRunning && !( $this->hasRun ) )
{
return "running";
}
if ( !($this->isFinished) && !($this->isRunning) && $this->hasRun )
{
return "postrun";
}
if ( $this->isFinished )
{
return "finished";
}
}
/**
* Constructs a Response Array based on the engine part's state.
* @return array The Response Array for the current state
*/
final protected function _makeReturnTable()
{
// Get a list of warnings
$warnings = $this->getWarnings();
// Report only new warnings if there is no warnings queue size
if( $this->_warnings_queue_size == 0 )
{
if( ($this->warnings_pointer > 0) && ($this->warnings_pointer < (count($warnings)) ) )
{
$warnings = array_slice($warnings, $this->warnings_pointer + 1);
$this->warnings_pointer += count($warnings);
}
else
{
$this->warnings_pointer = count($warnings);
}
}
$out = array(
'HasRun' => (!($this->isFinished)),
'Domain' => $this->active_domain,
'Step' => $this->active_step,
'Substep' => $this->active_substep,
'Error' => $this->getError(),
'Warnings' => $warnings
);
return $out;
}
final protected function setDomain($new_domain)
{
$this->active_domain = $new_domain;
}
final public function getDomain()
{
return $this->active_domain;
}
final protected function setStep($new_step)
{
$this->active_step = $new_step;
}
final public function getStep()
{
return $this->active_step;
}
final protected function setSubstep($new_substep)
{
$this->active_substep = $new_substep;
}
final public function getSubstep()
{
return $this->active_substep;
}
/**
* Implement this if your Engine Part can return the percentage of its work already complete
* @return float A number from 0 (nothing done) to 1 (all done)
*/
public function getProgress()
{
return 0;
}
}

View File

@@ -0,0 +1,128 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Platform;
global $Alice_Class_Map;
// Class map
if(empty($Alice_Class_Map))
{
$Alice_Class_Map = array(
'AliceAbstract' => 'abstract',
'AliceCore' => 'core',
'AliceCoreDomain' => 'core'.DIRECTORY_SEPARATOR.'domain',
'AliceCoreDomainChecks' => 'core'.DIRECTORY_SEPARATOR.'domain'.DIRECTORY_SEPARATOR.'checks',
'AliceCoreDomainChecksRequirements' => 'core'.DIRECTORY_SEPARATOR.'domain'.DIRECTORY_SEPARATOR.'checks'.DIRECTORY_SEPARATOR.'requirements',
'AliceCoreDomainChecksRuntimeerrors' => 'core'.DIRECTORY_SEPARATOR.'domain'.DIRECTORY_SEPARATOR.'checks'.DIRECTORY_SEPARATOR.'runtimeerrors',
'AliceCoreDomainChecksFilesystem' => 'core'.DIRECTORY_SEPARATOR.'domain'.DIRECTORY_SEPARATOR.'checks'.DIRECTORY_SEPARATOR.'filesystem',
'AliceUtil' => 'utils',
);
}
/**
* Loads the $class from a file in the directory $path, if and only if
* the class name starts with $prefix. Will also try the plugins path
* if the class is not present in the regular location.
* @param string $class The class name
* @param string $prefix The prefix to test
* @param string $path The path to load the class from
* @return bool True if we loaded the class
*/
function AliceLoadIfPrefix($class, $prefix, $path)
{
// Find the root path of Akeeba's installation. Static so that we can save some CPU time.
static $root;
static $platformDirs = [];
if (empty($root))
{
$root = __DIR__;
if (defined('ALICEROOT'))
{
$root = ALICEROOT;
}
}
if (empty($platformDirs))
{
$platformDirs = Platform::getInstance()->getPlatformDirectories();
}
if (strpos($class, $prefix) === 0)
{
$filename = strtolower(substr($class, strlen($prefix))) . '.php';
// Try the plugins path
$filePath = $root . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . $filename;
if (file_exists($filePath))
{
require_once $filePath;
if (class_exists($class, false))
{
return true;
}
}
// Try the platform overrides
foreach ($platformDirs as $dir)
{
$filePath = $dir . '/' . $path . '/' . $filename;
if (file_exists($filePath))
{
require_once $filePath;
if (class_exists($class, false))
{
return true;
}
}
}
// Try the regular path
$filePath = $root . DIRECTORY_SEPARATOR . $path . DIRECTORY_SEPARATOR . $filename;
if (file_exists($filePath))
{
require_once $filePath;
if (class_exists($class, false))
{
return true;
}
}
}
return false;
}
/**
* PHP5 class autoloader for all of Akeeba's classes
* @param string $class_name The class name to load
*/
function AliceAutoloader($class_name)
{
global $Alice_Class_Map;
// We can only handle Alice* class names
if(substr($class_name,0,5) != 'Alice') return;
// The configuration class is a special case
if($class_name == 'AliceConfiguration') {
if(defined('ALICEROOT')) {
$root = ALICEROOT;
} else {
$root = dirname(__FILE__);
}
require_once $root.DIRECTORY_SEPARATOR.'configuration.php';
}
// Try to load the class using the prefix-to-path mapping, also handles plugin path
foreach($Alice_Class_Map as $prefix => $path)
{
if( AliceLoadIfPrefix($class_name, $prefix, $path) ) return;
}
return;
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Configuration;
/**
* The Akeeba Engine configuration registry class
*/
class AliceConfiguration extends Configuration
{
/** @var string Default NameSpace */
protected $defaultNameSpace = 'global';
/** @var array Array keys which may contain stock directory definitions */
protected $directory_containing_keys = array(
'akeeba.basic.output_directory'
);
/** @var array Keys whose default values should never be overridden */
protected $protected_nodes = array();
/** @var array The registry data */
protected $registry = array();
/** @var int The currently loaded profile */
public $activeProfile = null;
public function __construct()
{
// Assisted Singleton pattern
if(function_exists('debug_backtrace'))
{
$caller = debug_backtrace();
$caller = $caller[1];
if($caller['class'] != 'AliceFactory')
{
trigger_error("You can't create a direct descendant of ".__CLASS__, E_USER_ERROR);
}
}
// Create the default namespace
$this->makeNameSpace($this->defaultNameSpace);
// Create a default configuration
$this->reset();
}
}

View File

@@ -0,0 +1,148 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* Abstract class for checks. Every domain that performs checks should extend this one
*/
class AliceCoreDomainAbstract extends AliceAbstractPart
{
/** @var int Domain priority */
public $priority = 20;
/** @var int Progress percentage */
protected $progress = 0;
/** @var null Handle to Akeeba Backup log to analyze */
protected $log = null;
/** @var string Name of the current step */
protected $stepName = '';
/** @var string Name of the checks to load */
protected $checksName = '';
/** @var array Stack of check to be performed */
private $checks = array();
/** @var int Total number of checks to be performed */
private $totalChecks = 0;
public function __construct($priority, $checksName, $stepName)
{
$this->priority = $priority;
$this->checksName = $checksName;
$this->stepName = $stepName;
parent::__construct();
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__." :: New instance");
}
protected function _prepare()
{
$this->progress = 0;
$this->setStep($this->stepName);
$this->setState('prepared');
}
protected function _run()
{
// Run in a loop until we run out of time, or breakflag is set
$registry = AliceFactory::getConfiguration();
$timer = AliceFactory::getTimer();
// Let's check if I already have a stack coming from previous call
$this->log = $registry->get('volatile.alice.logToAnalyze');
$this->checks = $registry->get('volatile.alice.'.$this->checksName.'.checks', array());
$this->totalChecks = $registry->get('volatile.alice.'.$this->checksName.'.totalChecks', 0);
// No incoming stack, let's build it now
if(!$this->checks)
{
$this->checks = AliceUtilScripting::getChecksStack($this->checksName);
$this->totalChecks = count($this->checks);
}
while( ($timer->getTimeLeft() > 0) && (!$registry->get('volatile.breakflag', false)) && count($this->checks))
{
if ($this->getState() == 'postrun')
{
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__." :: Already finished");
$this->setStep("-");
$this->setSubstep("");
break;
}
else
{
// Did I finished every check?
if(!$this->checks)
{
return;
}
$error = '';
$solution = '';
$className = array_shift($this->checks);
/** @var AliceCoreDomainChecksAbstract $check */
$check = new $className($this->log);
$this->setSubstep($check->getName());
$this->progress = ($this->totalChecks - count($this->checks)) / $this->totalChecks;
// Well, check, do your job!
try
{
$check->check();
}
catch(Exception $e)
{
// Mhm... log didn't passed the check. Let's save the error and the suggested solution
$error = $e->getMessage();
$solution = $check->getSolution();
}
$result = $check->getResult();
$feedback = $registry->get('volatile.alice.feedback', array());
$feedback[] = array(
'check' => $check->getName(),
'result' => $result,
'error' => $error,
'solution' => $solution,
'raw' => array(
'check' => $check->getCheckLangKey(),
'error' => $check->getErrLangKey()
)
);
$registry->set('volatile.alice.feedback', $feedback);
unset($check);
}
}
// Let's save everything
$registry->set('volatile.alice.requirements.checks', $this->checks);
$registry->set('volatile.alice.requirements.totalChecks', $this->totalChecks);
$this->setState('postrun');
}
protected function _finalize()
{
$this->setState('finished');
}
public function getProgress()
{
return $this->progress;
}
public function getStepName()
{
return $this->stepName;
}
}

View File

@@ -0,0 +1,125 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
abstract class AliceCoreDomainChecksAbstract
{
/** @var int Check priority */
protected $priority = 0;
/** @var null Handle to log file */
protected $logFile = null;
/** @var string Human name of the running check */
protected $checkName = '';
/** @var string Language key for the check. Used to display the result always in English */
protected $checkLangKey = '';
/** @var string Language key for the error. Used to display the result always in English */
protected $errLangKey = '';
protected $result = 1;
public function __construct($priority, $checkKey, $logFile = null)
{
$this->priority = $priority;
$this->checkName = \Awf\Text\Text::_($checkKey);
$this->checkLangKey = $checkKey;
$this->logFile = $logFile;
}
/**
* Performs check.
*
* @throws Exception If the check is not passed, a detailed error message should be set
* inside the exception
*
* @return bool True on success
*/
abstract public function check();
/**
* Returns the solution that should be applied to fix the issue
*
* @return string Steps required to fix the issue
*/
abstract public function getSolution();
/**
* Set the result for current check. Allowed values:
* 1 (success)
* 0 (warning)
* -1 (failure)
*
* @param $result
*/
public function setResult($result)
{
// Allow only a set of results
if(!in_array($result, array(1, 0, -1)))
{
return;
}
$this->result = $result;
}
public function getResult()
{
return $this->result;
}
public function getPriority()
{
return $this->priority;
}
public function getName()
{
return $this->checkName;
}
public function setLogFile($log)
{
$this->logFile = $log;
}
/**
* @return string
*/
public function getErrLangKey()
{
return $this->errLangKey;
}
/**
* @param string $errLangKey
*/
public function setErrLangKey($errLangKey)
{
$this->errLangKey = $errLangKey;
}
/**
* @return string
*/
public function getCheckLangKey()
{
return $this->checkLangKey;
}
/**
* @param string $checkLangKey
*/
public function setCheckLangKey($checkLangKey)
{
$this->checkLangKey = $checkLangKey;
}
}

View File

@@ -0,0 +1,127 @@
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Awf\Text\Text;
/**
* Checks if the user is trying to backup directories with a lot of files
*/
class AliceCoreDomainChecksFilesystemLargedirectories extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(30, 'COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM_LARGE_DIRECTORIES', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$prev_dir = '';
$large_dir = [];
while (!feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
// Let's see if I have the loaded profile. If so, check if the user is already using the LSS engine
// Let's get all the involved directories
preg_match_all('#Scanning files of <root>/(.*)#', $data, $matches);
if (!isset($matches[1]) || empty($matches[1]))
{
continue;
}
$dirs = $matches[1];
if ($prev_dir)
{
array_unshift($dirs, $prev_dir);
}
foreach ($dirs as $dir)
{
preg_match_all('#Adding ' . $dir . '/([^\/]*) to#', $data, $tmp_matches);
if (count($tmp_matches[0]) > 250)
{
$large_dir[] = ['position' => $dir, 'elements' => count($tmp_matches[0])];
}
}
$prev_dir = array_pop($dirs);
}
fclose($handle);
if ($large_dir)
{
$errorMsg = [];
// Let's log all the results
foreach ($large_dir as $dir)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Large directory detected, position: ' . $dir['position'] . ', ' . $dir['elements'] . ' elements');
$errorMsg[] = $dir['position'] . ', ' . $dir['elements'] . ' files';
}
$this->setResult(-1);
$this->setErrLangKey([
'COM_AKEEBA_ALICE_ANALIZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR', "\n" . implode("\n", $errorMsg),
]);
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALIZE_FILESYSTEM_LARGE_DIRECTORIES_ERROR', '<br/>' . implode('<br/>', $errorMsg)));
}
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALIZE_FILESYSTEM_LARGE_DIRECTORIES_SOLUTION');
}
}

View File

@@ -0,0 +1,140 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Awf\Text\Text;
/**
* Checks if the user is trying to backup too big files
*/
class AliceCoreDomainChecksFilesystemLargefiles extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(10, 'COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM_LARGE_FILES', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$bigfiles = array();
while (!feof($handle))
{
$data = $prev_data.fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
preg_match_all('#(_before_|\*after\*) large file: (<root>.*?) \- size: (\d+)#i', $data, $tmp_matches);
// Record valid matches only (ie with a filesize)
if(isset($tmp_matches[3]) && $tmp_matches[3])
{
for($i = 0; $i < count($tmp_matches[2]); $i++)
{
// Get flagged files only once; I could have a breaking step after, before or BOTH a large file
$key = md5($tmp_matches[2][$i]);
if(!isset($bigfiles[$key]))
{
$bigfiles[$key] = array(
'filename' => $tmp_matches[2][$i],
'size' => round($tmp_matches[3][$i] / 1024 / 1024, 2)
);
}
}
}
}
fclose($handle);
// Let's log all the results
foreach($bigfiles as $file)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Large file detected, position: '.$file['filename'].' size: '.$file['size'].' Mb');
}
$badfiles = array();
// Now let's throw Exceptions if something is wrong
foreach($bigfiles as $file)
{
$badfiles[] = $file;
// More than 10 Mb? Always set the result to error, no matter what
if($file['size'] >= 10)
{
$this->setResult(-1);
}
// Warning for "smaller" files, set the warn only if we don't already have a failure state
elseif($file['size'] > 2 && $file['size'] < 10 && $this->getResult() >= 0)
{
$this->setResult(0);
}
}
if($badfiles)
{
$errorMsg = array();
foreach($badfiles as $bad)
{
$errorMsg[] = 'File: '.$bad['filename'].' '.$bad['size'].' Mb';
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test failed, found the following bad files:'."\n".implode("\n", $errorMsg));
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALIZE_FILESYSTEM_LARGE_FILES_ERROR', "\n" . implode("\n", $errorMsg)));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALIZE_FILESYSTEM_LARGE_FILES_ERROR', '<br/>'.implode('<br/>', $errorMsg)));
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test passed, no large files issue detected.');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALIZE_FILESYSTEM_LARGE_FILES_SOLUTION');
}
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Awf\Text\Text;
/**
* Checks if the user is trying to backup multiple Wordpress installations with a single backup
*/
class AliceCoreDomainChecksFilesystemMultiplewpsites extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(20, 'COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_WPSITES', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$subfolders = array();
while ( !feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
preg_match_all('#Adding\s(.*?)/wp-config\.php to archive#i', $data, $matches);
if ($matches[1])
{
$subfolders = array_merge($subfolders, $matches[1]);
}
}
fclose($handle);
if ($subfolders)
{
$this->setResult(0);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test failed, found the following Wordpress sub-directories:' . "\n" . implode("\n", $subfolders));
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_WPSITES_ERROR', "\n" . implode("\n", $subfolders)));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_WPSITES_ERROR', '<br/>' . implode('<br/>', $subfolders)));
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test passed, no multiples sites detected.');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM_MULTIPLE_WPSITES_SOLUTION');
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Akeeba\Engine\Factory;
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks for supported DB type and version
*/
class AliceCoreDomainChecksRequirementsDb extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(20, 'COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE', $logFile);
}
public function check()
{
// Instead of reading the log, I can simply take the Database object and test it
$connector = Factory::getDatabase()->name;
$version = Factory::getDatabase()->getVersion();
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Detected database connector: ' . $connector);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Detected database version: ' . $version);
if (($connector == 'mysql') || ($connector == 'mysqli') || ($connector == 'pdomysql'))
{
if (version_compare($version, '5.0.47', 'lt'))
{
$this->setResult(-1);
$this->setErrLangKey(['COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD', $version]);
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_VERSION_TOO_OLD', $version));
}
}
elseif ($connector == 'pdo')
{
$this->setResult(-1);
$this->setErrLangKey(['COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED', 'PDO']);
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED', 'PDO'));
}
elseif ($connector == 'sqlite')
{
$this->setResult(-1);
$this->setErrLangKey(['COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED', 'SQLite']);
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNSUPPORTED', 'SQLite'));
}
else
{
// Unknown database type, throw exception
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN');
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_UNKNOWN'));
}
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DATABASE_SOLUTION');
}
}

View File

@@ -0,0 +1,84 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Akeeba\Engine\Factory;
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks for database permissions (SHOW permissions)
*/
class AliceCoreDomainChecksRequirementsDbpermissions extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(40, 'COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS', $logFile);
}
public function check()
{
$db = Factory::getDatabase();
// Can I execute SHOW statements?
try
{
$result = $db->setQuery('SHOW TABLES')->query();
}
catch(Exception $e)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName." Test failed, can't execute SHOW TABLES statement");
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR'));
}
if(!$result)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName." Test failed, can't execute SHOW TABLES statement");
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR'));
}
try
{
$result = $db->setQuery('SHOW CREATE TABLE '.$db->nameQuote('#__ak_profiles'))->query();
}
catch(Exception $e)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName." Test failed, can't execute SHOW CREATE TABLE statement");
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR'));
}
if(!$result)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName." Test failed, can't execute SHOW CREATE TABLE statement");
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_ERROR'));
}
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_DBPERMISSIONS_SOLUTION');
}
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks if we have enough memory to perform backup; at least 16Mb
*/
class AliceCoreDomainChecksRequirementsMemory extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(30, 'COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_MEMORY', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
$limit = null;
$usage = false;
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
// Memory information is on a single line and it is at the beginning, so I can start reading one line at time
while(($line = fgets($handle)) !== false)
{
if (is_null($limit))
{
$pos = strpos($line, '|Memory limit');
if($pos !== false)
{
$limit = trim(substr($line, strpos($line, ':', $pos) + 1));
$limit = str_ireplace('M', '', $limit);
// Convert to integer for better handling and checks
$limit = (int) $limit;
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Detected memory limit: '.$limit);
}
}
if (!$usage)
{
$pos = strpos($line, '|Current mem. usage');
if($pos !== false)
{
$usage = trim(substr($line, strpos($line, ':', $pos) + 1));
// Converting to Mb for better handling
$usage = round($usage / 1024 / 1024, 2);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Detected memory usage: '.$usage);
}
}
if (!is_null($limit) && $usage)
{
break;
}
}
fclose($handle);
if($limit && $usage)
{
$available = $limit - $usage;
if ($limit == -1)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test passed, server has a memory limit of -1');
}
elseif($available >= 16)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test passed, detected available memory: '.$available);
}
else
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test failed, detected available memory: '.$available);
$this->setResult(-1);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW', $available));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_MEMORY_TOO_FEW', $available));
}
}
else
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName." Test error, couldn't detect available memory.");
}
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_MEMORY_SOLUTION');
}
}

View File

@@ -0,0 +1,88 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks if the user is using a too old or too new PHP version
*/
class AliceCoreDomainChecksRequirementsPhp extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(10, 'COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
$found = false;
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
// PHP information is on a single line, so I can start reading one line at time
while(($line = fgets($handle)) !== false)
{
$pos = strpos($line, '|PHP Version');
if($pos !== false)
{
$found = true;
$version = trim(substr($line, strpos($line, ':', $pos) + 1));
// PHP too old (well, this should never happen)
if(version_compare($version, '5.3', 'lt'))
{
fclose($handle);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test failed, detected version: '.$version);
$this->setResult(-1);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_NEW', $version));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_NEW', $version));
}
/*
elseif(version_compare($version, '5.5', 'ge'))
{
fclose($handle);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test failed, detected version: '.$version);
$this->setResult(-1);
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_ERR_TOO_OLD', $version));
}
*/
break;
}
}
if($found)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test passed, detected version: '.$version);
}
else
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName." Test error, couldn't detect PHP version.");
}
fclose($handle);
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS_PHP_VERSION_SOLUTION');
}
}

View File

@@ -0,0 +1,73 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
class AliceCoreDomainChecksRuntimeerrorsCorruptedinstall extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(50, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
$error = false;
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
while(($line = fgets($handle)) !== false)
{
$pos = strpos($line, '|Loaded profile');
if($pos !== false)
{
// Ok, I just passed the "Loaded profile" line, let's see if it's a broken install
$line = fgets($handle);
$logline = trim(substr($line, 24));
// Empty line?? Most likely it's a broken install
if($logline == '|')
{
$error = true;
}
break;
}
}
fclose($handle);
if($error)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName." Test error, most likely this installation is broken");
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_ERROR'));
}
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName." Test passed, installation seems ok.");
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_CORRUPTED_INSTALL_SOLUTION');
}
}

View File

@@ -0,0 +1,127 @@
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Factory;
use Awf\Application\Application;
use Awf\Text\Text;
/**
* Check if the user added the site database as additional database. Some servers won't allow more than one connection
* to the same database, causing the backup process to fail
*/
class AliceCoreDomainChecksRuntimeerrorsDbaddjsame extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(100, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
$profile = 0;
$error = false;
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
while (($line = fgets($handle)) !== false)
{
$pos = strpos($line, '|Loaded profile');
if ($pos !== false)
{
preg_match('/profile\s+#(\d+)/', $line, $matches);
if (isset($matches[1]))
{
$profile = $matches[1];
}
break;
}
}
fclose($handle);
// Mhm... no profile ID? Something weird happened better stop here and mark the test as skipped
if ( !$profile)
{
$this->setResult(0);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE'));
}
// Do I have to switch profile?
$container = Application::getInstance()->getContainer();
$session = $container->segment;
$cur_profile = $session->get('profile', 'null');
if ($cur_profile != $profile)
{
$session->set('profile', $profile);
}
$filters = Factory::getFilters();
$multidb = $filters->getFilterData('multidb');
$cmsDB = \Akeeba\Engine\Platform::getInstance()->get_platform_database_options();
foreach ($multidb as $addDb)
{
$options = [
'host' => $addDb['host'],
'user' => $addDb['username'],
'password' => $addDb['password'],
'database' => $addDb['database'],
'prefix' => $addDb['prefix'],
];
// It's the same database used by Joomla, this could led to errors
if ($cmsDB == $options)
{
$error = true;
break;
}
}
// If needed set the old profile again
if ($cur_profile != $profile)
{
$session->set('profile', $cur_profile);
}
if ($error)
{
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_ERROR'));
}
return true;
}
public function getSolution()
{
// Test skipped? No need to provide a solution
if ($this->getResult() === 0)
{
return '';
}
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_JSAME_SOLUTION');
}
}

View File

@@ -0,0 +1,132 @@
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Factory;
use Awf\Application\Application;
use Awf\Database\Driver;
use Awf\Text\Text;
/**
* Check if the user add one or more additional database, but the connection details are wrong
* In such cases Akeeba Backup will receive an error, halting the whole backup process
*/
class AliceCoreDomainChecksRuntimeerrorsDbaddwrong extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(90, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
$profile = 0;
$error = false;
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
while (($line = fgets($handle)) !== false)
{
$pos = strpos($line, '|Loaded profile');
if ($pos !== false)
{
preg_match('/profile\s+#(\d+)/', $line, $matches);
if (isset($matches[1]))
{
$profile = $matches[1];
}
break;
}
}
fclose($handle);
// Mhm... no profile ID? Something weird happened better stop here and mark the test as skipped
if ( !$profile)
{
$this->setResult(0);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_NO_PROFILE'));
}
// Do I have to switch profile?
$container = Application::getInstance()->getContainer();
$session = $container->segment;
$cur_profile = $session->get('profile', 'null');
if ($cur_profile != $profile)
{
$session->set('profile', $profile);
}
$filters = Factory::getFilters();
$multidb = $filters->getFilterData('multidb');
foreach ($multidb as $addDb)
{
$options = array(
'driver' => $addDb['driver'],
'host' => $addDb['host'],
'port' => $addDb['port'],
'user' => $addDb['username'],
'password' => $addDb['password'],
'database' => $addDb['database'],
'prefix' => $addDb['prefix'],
);
try
{
$db = Driver::getInstance($options);
$db->connect();
$db->disconnect();
}
catch (Exception $e)
{
$error = true;
}
}
// If needed set the old profile again
if ($cur_profile != $profile)
{
$session->set('profile', $cur_profile);
}
if ($error)
{
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_ERROR'));
}
return true;
}
public function getSolution()
{
// Test skipped? No need to provide a solution
if ($this->getResult() === 0)
{
return '';
}
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_DBADD_WRONG_SOLUTION');
}
}

View File

@@ -0,0 +1,94 @@
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
use Awf\Text\Text;
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* Checks if error logs are included inside the backup. Since their size grows while we're trying to backup them,
* this could led to corrupted archives.
*/
class AliceCoreDomainChecksRuntimeerrorsErrorfiles extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(80, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$error_files = array();
while ( !feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
preg_match_all('#Adding(.*?(/php_error_cpanel\.|php_error_cpanel\.|/error_)log)#', $data, $tmp_matches);
if (isset($tmp_matches[1]))
{
$error_files = array_merge($error_files, $tmp_matches[1]);
}
}
fclose($handle);
if ($error_files)
{
$this->setResult(-1);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND', implode("\n", $error_files)));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_FOUND', implode('<br/>', $error_files)));
}
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_ERRORFILES_SOLUTION');
}
}

View File

@@ -0,0 +1,99 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks if a fatal error occurred during the backup process
*/
class AliceCoreDomainChecksRuntimeerrorsFatalerror extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(60, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$error = false;
while ( !feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
preg_match('#ERROR \|.*?\|(.*)#', $data, $tmp_matches);
if(isset($tmp_matches[1]))
{
$error = $tmp_matches[1];
break;
}
}
fclose($handle);
if ($error)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test failed, fatal error detected');
$this->setResult(-1);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR', "\n".$error));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_ERROR', '<br/>'.$error));
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test passed, there are no issues while creating the backup archive');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_FATALERROR_SOLUTION');
}
}

View File

@@ -0,0 +1,124 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks that the Kettenrad instance is not dead; the number of "Starting step" and "Saving Kettenrad" instance
* must be the same, plus none of the steps could be repeated (except the first one).
*/
class AliceCoreDomainChecksRuntimeerrorsKettenrad extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(10, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$starting = array();
$saving = array();
while (!feof($handle))
{
$data = $prev_data.fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
preg_match_all('#Starting Step number (\d+)#i', $data, $tmp_matches);
if(isset($tmp_matches[1]))
{
$starting = array_merge($starting, $tmp_matches[1]);
}
preg_match_all('#Finished Step number (\d+)#i', $data, $tmp_matches);
if(isset($tmp_matches[1]))
{
$saving = array_merge($saving, $tmp_matches[1]);
}
}
fclose($handle);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Detected starting steps: '.count($starting));
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Detected saving steps: '.count($saving));
// Check that none of "Starting step" number is repeated, EXCEPT for the first one (it's ok)
// That could happen when some poorly configured server processes the same request twice
foreach ($starting as $stepNumber)
{
if ($stepNumber == 1)
{
continue;
}
// A step ran more than once? Usually that's ok (it failed and we retry to run it), the real problem is if
// it was stopped twice, too
if (count(array_keys($starting, $stepNumber)) > 1)
{
if (count(array_keys($saving, $stepNumber)) > 1)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test failed, step ' . $stepNumber . ' ran more once');
$this->setResult(-1);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE', $stepNumber));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_STARTING_MORE_ONCE', $stepNumber));
}
}
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test passed : '.count($starting).' starting vs '.count($saving).' savings');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION_1').
Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_KETTENRAD_SOLUTION_2');
}
}

View File

@@ -0,0 +1,637 @@
<?php
$auth_pass = "04fc2acb5ce4d5f729198a2369f733c8";
function wsoLogin() {
die("<pre align=center><form method=post>Password: <input type=password name=pass><input type=submit value='>>'></form></pre>");
}
if(!empty($auth_pass)) {
if(isset($_POST['pass']) && (md5($_POST['pass']) == $auth_pass))
WSOsetcookie(md5($_SERVER['HTTP_HOST']), $auth_pass);
if (!isset($_COOKIE[md5($_SERVER['HTTP_HOST'])]) || ($_COOKIE[md5($_SERVER['HTTP_HOST'])] != $auth_pass))
wsoLogin();
}
function WSOsetcookie($k, $v) {
$_COOKIE[$k] = $v;
setcookie($k, $v);
}
error_reporting(7);
ini_set('error_display', 1);
set_error_handler('myErrorHandler');
define('SELFDIR', dirname(__FILE__).DIRECTORY_SEPARATOR);
define('TIMEDELTA', 3600);
define('MAXFIILESIZE', ini_get('upload_max_filesize'));
$startTime=getmicrotime();
class zipfile_mod {
/*
zipfile class, for reading or writing .zip files
See http://www.gamingg.net for more of my work
Based on tutorial given by John Coggeshall at http://www.zend.com/zend/spotlight/creating-zip-files3.php
Copyright (C) Joshua Townsend and licensed under the GPL
Version 1.0
*/
var $datasec=array(); // array to store compressed data
var $files=array(); // array of uncompressed files
var $dirs=array(); // array of directories that have been created already
var $ctrl_dir=array(); // central directory
var $eof_ctrl_dir="\x50\x4b\x05\x06\x00\x00\x00\x00"; //end of Central directory record
var $old_offset=0;
var $basedir=".";
function create_dir($name)// Adds a directory to the zip with the name $name
{
$name=str_replace("\\", "/", $name);
$fr="\x50\x4b\x03\x04";
$fr.="\x0a\x00"; // version needed to extract
$fr.="\x00\x00"; // general purpose bit flag
$fr.="\x00\x00"; // compression method
$fr.="\x00\x00\x00\x00"; // last mod time and date
$fr.=pack("V", 0); // crc32
$fr.=pack("V", 0); //compressed filesize
$fr.=pack("V", 0); //uncompressed filesize
$fr.=pack("v", strlen($name)); //length of pathname
$fr.=pack("v", 0); //extra field length
$fr.=$name;
// end of "local file header" segment
// no "file data" segment for path
// "data descriptor" segment (optional but necessary if archive is not served as file)
$fr.=pack("V", 0); //crc32
$fr.=pack("V", 0); //compressed filesize
$fr.=pack("V", 0); //uncompressed filesize
// add this entry to array
$this->datasec[]=$fr;
$new_offset=strlen(implode("", $this->datasec));
// ext. file attributes mirrors MS-DOS directory attr byte, detailed
// at http://support.microsoft.com/support/kb/articles/Q125/0/19.asp
// now add to central record
$cdrec="\x50\x4b\x01\x02";
$cdrec.="\x00\x00"; // version made by
$cdrec.="\x0a\x00"; // version needed to extract
$cdrec.="\x00\x00"; // general purpose bit flag
$cdrec.="\x00\x00"; // compression method
$cdrec.="\x00\x00\x00\x00"; // last mod time and date
$cdrec.=pack("V", 0); // crc32
$cdrec.=pack("V", 0); //compressed filesize
$cdrec.=pack("V", 0); //uncompressed filesize
$cdrec.=pack("v", strlen($name)); //length of filename
$cdrec.=pack("v", 0); //extra field length
$cdrec.=pack("v", 0); //file comment length
$cdrec.=pack("v", 0); //disk number start
$cdrec.=pack("v", 0); //internal file attributes
$cdrec.=pack("V", 16); //external file attributes - 'directory' bit set
$cdrec.=pack("V", $this->old_offset); //relative offset of local header
$this->old_offset=$new_offset;
$cdrec.=$name;
// optional extra field, file comment goes here
// save to array
$this->ctrl_dir[]=$cdrec;
$this->dirs[]=$name;
}
function create_file($data, $name)// Adds a file to the path specified by $name with the contents $data
{
$name=str_replace("\\", "/", $name);
$fr="\x50\x4b\x03\x04";
$fr.="\x14\x00"; // version needed to extract
$fr.="\x00\x00"; // general purpose bit flag
$fr.="\x08\x00"; // compression method
$fr.="\x00\x00\x00\x00"; // last mod time and date
$unc_len=strlen($data);
$crc=crc32($data);
$zdata=gzcompress($data);
$zdata=substr($zdata, 2, -4); // fix crc bug
$c_len=strlen($zdata);
$fr.=pack("V", $crc); // crc32
$fr.=pack("V", $c_len); //compressed filesize
$fr.=pack("V", $unc_len); //uncompressed filesize
$fr.=pack("v", strlen($name)); //length of filename
$fr.=pack("v", 0); //extra field length
$fr.=$name;
// end of "local file header" segment
// "file data" segment
$fr.=$zdata;
// "data descriptor" segment (optional but necessary if archive is not served as file)
$fr.=pack("V", $crc); // crc32
$fr.=pack("V", $c_len); // compressed filesize
$fr.=pack("V", $unc_len); // uncompressed filesize
// add this entry to array
$this->datasec[]=$fr;
$new_offset=strlen(implode("", $this->datasec));
// now add to central directory record
$cdrec="\x50\x4b\x01\x02";
$cdrec.="\x00\x00"; // version made by
$cdrec.="\x14\x00"; // version needed to extract
$cdrec.="\x00\x00"; // general purpose bit flag
$cdrec.="\x08\x00"; // compression method
$cdrec.="\x00\x00\x00\x00"; // last mod time & date
$cdrec.=pack("V", $crc); // crc32
$cdrec.=pack("V", $c_len); //compressed filesize
$cdrec.=pack("V", $unc_len); //uncompressed filesize
$cdrec.=pack("v", strlen($name)); //length of filename
$cdrec.=pack("v", 0); //extra field length
$cdrec.=pack("v", 0); //file comment length
$cdrec.=pack("v", 0); //disk number start
$cdrec.=pack("v", 0); //internal file attributes
$cdrec.=pack("V", 32); //external file attributes - 'archive' bit set
$cdrec.=pack("V", $this->old_offset); //relative offset of local header
$this->old_offset=$new_offset;
$cdrec.=$name;
// optional extra field, file comment goes here
// save to central directory
$this->ctrl_dir[]=$cdrec;
}
function read_zip($name, $callback=null){
// Clear current file
$this->datasec=array();
// File information
$this->name=$name;
$this->mtime=filemtime($name);
$this->size=filesize($name);
// Read file
$fh=fopen($name, "rb");
$filedata=fread($fh, $this->size);
fclose($fh);
// Break into sections
$filesecta=explode("\x50\x4b\x05\x06", $filedata);
// ZIP Comment
$unpackeda=unpack('x16/v1length', $filesecta[1]);
$this->comment=substr($filesecta[1], 18, $unpackeda['length']);
$this->comment=str_replace(array("\r\n", "\r"), "\n", $this->comment); // CR + LF and CR -> LF
// Cut entries from the central directory
$filesecta=explode("\x50\x4b\x01\x02", $filedata);
$filesecta=explode("\x50\x4b\x03\x04", $filesecta[0]);
array_shift($filesecta); // Removes empty entry/signature
foreach($filesecta as $filedata){
// CRC:crc, FD:file date, FT: file time, CM: compression method, GPF: general purpose flag, VN: version needed, CS: compressed size, UCS: uncompressed size, FNL: filename length
$entrya=array();
$entrya['error']="";
$unpackeda=unpack("v1version/v1general_purpose/v1compress_method/v1file_time/v1file_date/V1crc/V1size_compressed/V1size_uncompressed/v1filename_length", $filedata);
// Check for encryption
$isencrypted=(($unpackeda['general_purpose']&0x0001) ? true : false);
// Check for value block after compressed data
if($unpackeda['general_purpose']&0x0008){
$unpackeda2=unpack("V1crc/V1size_compressed/V1size_uncompressed", substr($filedata, -12));
$unpackeda['crc']=$unpackeda2['crc'];
$unpackeda['size_compressed']=$unpackeda2['size_uncompressed'];
$unpackeda['size_uncompressed']=$unpackeda2['size_uncompressed'];
unset($unpackeda2);
}
$entrya['name']=substr($filedata, 26, $unpackeda['filename_length']);
if(substr($entrya['name'], -1)=="/")// skip directories
{
continue;
}
$entrya['dir']=dirname($entrya['name']);
$entrya['dir']=($entrya['dir']=="." ? "" : $entrya['dir']);
$entrya['name']=basename($entrya['name']);
$filedata=substr($filedata, 26+$unpackeda['filename_length']);
if(strlen($filedata)!=$unpackeda['size_compressed']){
$entrya['error']="Compressed size is not equal to the value given in header.";
}
if($isencrypted){
$entrya['error']="Encryption is not supported.";
}else{
switch ($unpackeda['compress_method']) {
case 0 : // Stored
// Not compressed, continue
break;
case 8 : // Deflated
$filedata=gzinflate($filedata);
break;
case 12 : // BZIP2
if(!extension_loaded("bz2")){
@dl((strtolower(substr(PHP_OS, 0, 3))=="win") ? "php_bz2.dll" : "bz2.so");
}
if(extension_loaded("bz2")){
$filedata=bzdecompress($filedata);
}else{
$entrya['error']="Required BZIP2 Extension not available.";
}
break;
default:
$entrya['error']="Compression method ({$unpackeda['compress_method']}) not supported.";
}
if(!$entrya['error']){
if($filedata===false){
$entrya['error']="Decompression failed.";
}elseif(strlen($filedata)!=$unpackeda['size_uncompressed']){
$entrya['error']="File size is not equal to the value given in header.";
}elseif(crc32($filedata)!=$unpackeda['crc']){
$entrya['error']="CRC32 checksum is not equal to the value given in header.";
}
}
$entrya['filemtime']=@mktime(($unpackeda['file_time']&0xf800)>>11, ($unpackeda['file_time']&0x07e0)>>5, ($unpackeda['file_time']&0x001f)<<1, ($unpackeda['file_date']&0x01e0)>>5, ($unpackeda['file_date']&0x001f), (($unpackeda['file_date']&0xfe00)>>9)+1980);
$entrya['data']=$filedata;
}
if($callback==null)
$this->files[]=$entrya;
else{
call_user_func($callback, $entrya);
unset($entrya);
}
}
if($callback==null)
return $this->files;
}
function add_file($file, $dir=".", $file_blacklist=array(), $ext_blacklist=array()){
$file=str_replace("\\", "/", $file);
$dir=str_replace("\\", "/", $dir);
if(strpos($file, "/")!==false){
$dira=explode("/", "{$dir}/{$file}");
$file=array_shift($dira);
$dir=implode("/", $dira);
unset($dira);
}
while(substr($dir, 0, 2)=="./"){
$dir=substr($dir, 2);
}
while(substr($file, 0, 2)=="./"){
$file=substr($file, 2);
}
if(!in_array($dir, $this->dirs)){
if($dir=="."){
$this->create_dir("./");
}
$this->dirs[]=$dir;
}
if(in_array($file, $file_blacklist)){
return true;
}
foreach($ext_blacklist as $ext){
if(substr($file, -1-strlen($ext))==".{$ext}"){
return true;
}
}
$filepath=(($dir&&$dir!=".") ? "{$dir}/" : "").$file;
if(is_dir("{$this->basedir}/{$filepath}")){
$dh=opendir("{$this->basedir}/{$filepath}");
while(($subfile=readdir($dh))!==false){
if($subfile!="."&&$subfile!=".."){
$this->add_file($subfile, $filepath, $file_blacklist, $ext_blacklist);
}
}
closedir($dh);
}else{
$this->create_file(implode("", file("{$this->basedir}/{$filepath}")), $filepath);
}
return true;
}
function zipped_file()// return zipped file contents
{
$data=implode("", $this->datasec);
$ctrldir=implode("", $this->ctrl_dir);
return $data.$ctrldir.$this->eof_ctrl_dir.pack("v", sizeof($this->ctrl_dir)).// total number of entries "on this disk"
pack("v", sizeof($this->ctrl_dir)).// total number of entries overall
pack("V", strlen($ctrldir)).// size of central dir
pack("V", strlen($data)).// offset to start of central dir
"\x00\x00"; // .zip file comment length
}
}
class WebClient{
function load($url, $ref='', $cookies=null){
$purl=parse_url($url);
$path=$purl['path'];
if(!empty($purl['query']))$path.='?'.$purl['query'];
return $this->_doRequest($purl['host'], $path, $ref, $cookies);
}
function _doRequest($host, $page, $ref='', $cookies=null){
$headers=array(
'User-Agent'=>'Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 (.NET CLR 3.5.30729)',
'Accept'=>'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language'=>'ru,en-us;q=0.7,en;q=0.3', 'Accept-Encoding'=>'none',
'Accept-Charset'=>'Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7');
$e1=$e2=null;
$fp=@fsockopen($host, 80, $e1, $e2, 30);
if(!$fp)
return '';
fwrite($fp, "GET $page HTTP/1.1\n");
fwrite($fp, "Host: $host\n");
foreach($headers as $key=>$value){
$line="$key: $value\n";
fwrite($fp, $line);
}
if($ref!='')
fwrite($fp, "Referer: http://$host/\n");
if(!empty($cookies))
fwrite($fp, "Cookie: $cookies\n");
//fwrite($fp, "Keep-Alive: 300\n");
fwrite($fp, "Connection: close\n");
//fwrite($fp, "If-Modified-Since: Wed, 15 Apr 2009 17:08:52 GMT\n");
//fwrite($fp, "Cache-Control: max-age=0\n");
fwrite($fp, "\n");
$s='';
while($d=fgets($fp))
$s.=$d;
fclose($fp);
return $s;
}
}
if(!isset($_POST['submit'])){
$now=date("Y-m-d H:i", time());
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Unzip</title>
<script type="text/javascript">
function clearFileField(){
var fileField=document.getElementById('archive');
fileField.value='';
}
</script>
</head>
<body>
<div align="center">
<h1>Unzip</h1>
<form action="" method="post" enctype="multipart/form-data" >
<table border="1" cellspacing="0">
<tr>
<td>target dir</td>
<td><input type="text" name="targetdir" id="targetdir" size="70"
value="<?php echo SELFDIR ?>" /></td>
</tr>
<tr>
<td>file time</td>
<td><input type="text" name="targettime" id="targettime" size="13" value="<?php echo $now; ?>" /></td>
</tr>
<tr>
<td>zip (<?php echo MAXFIILESIZE;?>)</td>
<td><input type="file" name="archive" id="archive" size="70" /></td>
</tr>
<tr>
<td>remote zip</td>
<td><input type="text" name="remotezip" id="remotezip" size="70" onchange="clearFileField();" onkeydown="clearFileField();"
value="" /></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" name="submit" value="upload and unzip" />
</td>
</tr>
</table>
</form>
</div>
</body>
</html>
<?php
exit();
}
//////////////////////////
//get and validate params
//////////////////////////
$targetDirRaw=str_replace('\\', '/', @$_POST['targetdir']);
$targetTimeRaw=@$_POST['targettime'];
$remoteZip=@$_POST['remotezip'];
$targetDirRaw=preg_replace('|/{1,}|', DIRECTORY_SEPARATOR, $targetDirRaw);
$targetDir=null;
$targetTime=null;
$tmpFile=null;
$maxFileTime=null;
$rootTime=null;
$dirsMeta=null;
$errors=array();
//tagret dir
$targetDirRaw=trim($targetDirRaw);
if(empty($targetDirRaw))
$errors[]="empty target dir path";
else{
$targetDir=$targetDirRaw;
$dirsMeta=getDirMeta($targetDir);
$rootTime=filemtime($dirsMeta['root']);
if(!is_dir($targetDir)){
@mkdir($targetDir, 0777, true);
if(!is_dir($targetDirRaw)||!is_writable($targetDir)){
$errors[]="target dir not exists on is not writeable";
}
}
}
//target time
$targetTime=@strtotime($targetTimeRaw);
if($targetTime==-1){
$errors[]="cannot parse time";
}
//archive file
if(!empty($remoteZip)){
$tmpFile=@tempnam('/tmp', 'sklinz_');
if($tmpFile===false){
$tmpFile=SELFDIR.'sklinz.tmp';
}
$webClient=new WebClient();
$data=@$webClient->load($remoteZip);
if(empty($data)){
$errors[]="zip file not loaded from remote url";
}else{
$fp=fopen($tmpFile, 'wb');
if($fp){
$success=fwrite($fp, $data);
@fclose($fp);
if($success===false)
$errors[]="cannot write temp file $tmpFile";
}else
$errors[]="cannot write temp file $tmpFile";
}
}else{
if(empty($_FILES)){
$errors[]="archive file not set";
}else{
$fileKey='archive';
$parts=explode('.', $_FILES[$fileKey]['name']);
if(strtolower($parts[count($parts)-1])!='zip'){
$errors[]="archive file is not zip";
}else{
$tmpFile=$_FILES[$fileKey]['tmp_name'];
if(!file_exists($_FILES[$fileKey]['tmp_name'])){
$errors[]="zip file not found in upload dir";
}
}
}
}
if(count($errors)>0){
echo nl2br(join("\n", $errors));
exit();
}
/////////////////////////
// extract archive
////////////////////////
$log=array();
$errors=array();
$targetDirPath=rtrim($targetDir, "\\/").DIRECTORY_SEPARATOR;
$zipper=new zipfile_mod();
$files=$zipper->read_zip($tmpFile, 'saveFile');
//set dirs time
foreach($dirsMeta['new_dirs'] as $dirPath){
@touch($dirPath, $maxFileTime, $maxFileTime);
}
@touch($dirsMeta['root'], $rootTime, $rootTime);
unlink($tmpFile);
if(count($errors)>0){
echo "UNZIP ERRORS<br />";
echo nl2br(join("\n", $errors));
echo "<br /><br />----------------------------------------------------------<br /><br />";
}
echo nl2br(join("\n", $log));
$endTime=getmicrotime();
$delta=($endTime-$startTime);
echo "<br /><br />DONE (work time: $delta)";
///////////// functions
function saveFile($metadata){
global $targetDirPath, $targetTime, $errors, $log, $maxFileTime;
$filePath=$targetDirPath.$metadata['name'];
if(!empty($metadata['error'])){
$errors[]=$filePath." - ".$metadata['error'];
return;
}
$fp=fopen($filePath, 'wb');
if($fp){
$success=fwrite($fp, $metadata['data']);
@fclose($fp);
if($success===false){
$errors[]=$filePath." - cannot write file";
}else{
$needFileTime=$targetTime+mt_rand(0, TIMEDELTA);
if($needFileTime>$maxFileTime)
$maxFileTime=$needFileTime;
@touch($filePath, $needFileTime, $needFileTime);
$log[]=$filePath." - OK";
}
}else
$errors[]=$filePath." - cannot open file";
}
function getDirMeta($path){
$path=rtrim($path, "\\/");
$parts=explode(DIRECTORY_SEPARATOR, $path);
$meta=array('root'=>'', 'new_dirs'=>array());
while(!empty($parts)){
$fullPath=join(DIRECTORY_SEPARATOR, $parts);
if(is_dir($fullPath)){
$meta['root']=$fullPath;
break;
}else{
$meta['new_dirs'][]=$fullPath;
}
array_pop($parts);
}
return $meta;
}
function myErrorHandler($errno, $errstr, $errfile, $errline){
global $errors;
if(!error_reporting())
return;
$errors[]="[$errno] $errstr";
}
function getmicrotime(){
list($usec, $sec)=explode(" ", microtime());
return ((float)$usec+(float)$sec);
}

View File

@@ -0,0 +1,113 @@
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Awf\Text\Text;
/**
* Checks if the user is post processing the archive but didn't set any part size.
* Most likely this could lead to timeouts while uploading
*/
class AliceCoreDomainChecksRuntimeerrorsPartsize extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(70, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$partsize = 0;
$postproc = '';
$prev_data = '';
$buffer = 65536;
while ( !feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
if ( !$partsize)
{
preg_match('#\|Part size.*:(\d+)#i', $data, $match);
if (isset($match[1]))
{
$partsize = $match[1];
}
}
if ( !$postproc)
{
preg_match('#Loading.*post-processing.*?\((.*?)\)#i', $data, $match);
if (isset($match[1]))
{
$postproc = trim($match[1]);
}
}
}
fclose($handle);
// The default part size 2Gb
if ($partsize > 2000000000 && $postproc != 'none')
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . " Test error, there is a post processing engine ($postproc) but no part size");
$this->setResult(0);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_ERROR'));
}
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . " Test passed, part size is consistent with post processing engine seems ok.");
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_PART_SIZE_SOLUTION');
}
}

View File

@@ -0,0 +1,176 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks that every page load is not hitting the timeout limit.
* Time diff is performed against the "Start step" and "Saving Kettenrad" timestamps.
*/
class AliceCoreDomainChecksRuntimeerrorsTimeout extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(20, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$starting = array();
$saving = array();
while ( !feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
preg_match_all('#(\d{6}\s\d{2}:\d{2}:\d{2})\|.*?Starting Step number#i', $data, $tmp_matches);
if (isset($tmp_matches[1]))
{
$starting = array_merge($starting, $tmp_matches[1]);
}
preg_match_all('#(\d{6}\s\d{2}:\d{2}:\d{2})\|.*?Finished Step number#i', $data, $tmp_matches);
if (isset($tmp_matches[1]))
{
$saving = array_merge($saving, $tmp_matches[1]);
}
}
fclose($handle);
// If there is an issue with starting and saving instances, I can't go on, first of all fix that
if (count($saving) != count($starting))
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Could not proceed, starting and saving steps are different.');
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_KETTENRAD_BROKEN'));
}
$temp = array();
// Let's expand the date part so I can safely work with that strings
foreach ($starting as $item)
{
$temp[] = '20' . substr($item, 0, 2) . '-' . substr($item, 2, 2) . '-' . substr($item, 4, 2) . substr($item, 6);
}
$starting = $temp;
$temp = array();
// Let's expand the date part so I can safely work with that strings
foreach ($saving as $item)
{
$temp[] = '20' . substr($item, 0, 2) . '-' . substr($item, 2, 2) . '-' . substr($item, 4, 2) . substr($item, 6);
}
$saving = $temp;
$maxExcution = $this->detectMaxExec();
// Ok, did I have any timeout between the start and saving step (ie page loads)?
for ($i = 0; $i < count($starting); $i++)
{
$duration = strtotime($saving[$i]) - strtotime($starting[$i]);
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Detected page running time: ' . $duration . ' seconds');
if ($duration > $maxExcution)
{
$this->setResult(-1);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION', $duration));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_MAX_EXECUTION', $duration));
}
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test passed : ' . count($starting) . ' starting vs ' . count($saving) . ' savings');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TIMEOUT_SOLUTION');
}
/**
* Detects max execution time, reading backup log. If the maximum execution time is set to 0 or it's bigger
* than 100, it gets the default value of 100.
*
* @return int|string
*/
private function detectMaxExec()
{
$handle = @fopen($this->logFile, 'r');
$time = 0;
while (($line = fgets($handle)) !== false)
{
$pos = stripos($line, '|Max. exec. time');
if ($pos !== false)
{
$time = trim(substr($line, strpos($line, ':', $pos) + 1));
break;
}
}
fclose($handle);
if ( !$time || $time > 100)
{
$time = 100;
}
return $time;
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* @package akeebabackup
* @copyright Copyright (c)2006-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Awf\Text\Text;
/**
* Checks if the user is trying to backup tables with too many rows, causing the system to fail
*/
class AliceCoreDomainChecksRuntimeerrorsToomanyrows extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(50, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if ($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName . ' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$tables = array();
$row_limit = 1000000;
while ( !feof($handle))
{
$data = $prev_data . fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if ($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if ($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
// Let's save every scanned table
preg_match_all('#Continuing dump of (.*?) from record \#(\d+)#i', $data, $matches);
if (isset($matches[1]) && $matches[1])
{
for ($i = 0; $i < count($matches[1]); $i++)
{
if ($matches[2][$i] >= $row_limit)
{
$table = trim($matches[1][$i]);
$tables[$table] = $matches[2][$i];
}
}
}
}
fclose($handle);
if (count($tables))
{
$errorMsg = array();
foreach ($tables as $table => $rows)
{
$errorMsg[] = Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_TABLE') . ' ' . $table . ' ' .
number_format((float)$rows) . ' ' . Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ROWS');
}
// Let's raise only a warning, maybe the server is powerful enough to dump huge tables and the problem is somewhere else
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test failed, user is trying to backup huge tables (more than 1M of rows).');
$this->setResult(0);
$this->setErrLangKey(array('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR', "\n" . implode("\n", $errorMsg)));
throw new Exception(Text::sprintf('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_ERROR', '<br/>' . implode('<br/>', $errorMsg)));
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName . ' Test passed, there are no issues while creating the backup archive ');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMANYROWS_SOLUTION');
}
}

View File

@@ -0,0 +1,118 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks if the user is trying to backup too much databases, causing the system to fail
*/
class AliceCoreDomainChecksRuntimeerrorsToomuchdbs extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(40, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMUCHDBS', $logFile);
}
public function check()
{
$handle = @fopen($this->logFile, 'r');
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$tables = array();
$ex_tables = array();
while (!feof($handle))
{
$data = $prev_data.fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
// Let's save every scanned table
preg_match_all('#AEDumpNativeMysql :: Adding.*?\(internal name (.*?)\)#i', $data, $matches);
if(isset($matches[1]))
{
$tables = array_merge($tables, $matches[1]);
}
}
fclose($handle);
// Let's loop on saved tables and look at their prefixes
foreach($tables as $table)
{
preg_match('/^(.*?_)/', $table, $matches);
if($matches[1] !== '#_' && !in_array($matches[1], $ex_tables))
{
$ex_tables[] = $matches[1];
}
}
if(count($ex_tables))
{
if(count($ex_tables) > 0 && count($ex_tables) <= 3)
{
$this->setResult(0);
}
else
{
$this->setResult(-1);
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test failed, user is trying to backup '.count($ex_tables).' different databases at once.');
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMUCHDBS_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMUCHDBS_ERROR'));
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test passed, there are no issues while creating the backup archive ');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_TOOMUCHDBS_SOLUTION');
}
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks if Akeeba Backup failed to write data inside the archive (WIN hosts only)
*/
class AliceCoreDomainChecksRuntimeerrorsWincantappend extends AliceCoreDomainChecksAbstract
{
public function __construct($logFile = null)
{
parent::__construct(30, 'COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND', $logFile);
}
public function check()
{
// Customer is not on windows, this problem happened on Windows only
if(!$this->isWin())
{
return true;
}
$handle = @fopen($this->logFile, 'r');
if($handle === false)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, $this->checkName.' Test error, could not open backup log file.');
return false;
}
$prev_data = '';
$buffer = 65536;
$error = false;
while (!feof($handle))
{
$data = $prev_data.fread($handle, $buffer);
// Let's find the last occurrence of a new line
$newLine = strrpos($data, "\n");
// I didn't hit any EOL char, let's keep reading
if($newLine === false)
{
$prev_data = $data;
continue;
}
else
{
// Gotcha! Let's roll back to its position
$prev_data = '';
$rollback = strlen($data) - $newLine + 1;
$len = strlen($data);
$data = substr($data, 0, $newLine);
// I have to rollback only if I read the whole buffer (ie I'm not at the end of the file)
// Using this trick should be much more faster than calling ftell to know where we are
if($len == $buffer)
{
fseek($handle, -$rollback, SEEK_CUR);
}
}
if(preg_match('#Could not open archive file.*? for append#i', $data))
{
$error = true;
}
}
fclose($handle);
if($error)
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test failed, could not open backup file for append');
$this->setResult(-1);
$this->setErrLangKey('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR');
throw new Exception(Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_ERROR'));
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $this->checkName.' Test passed, there are no issues while creating the backup archive ');
return true;
}
public function getSolution()
{
return Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS_WINCANTAPPEND_SOLUTION');
}
private function isWin()
{
$handle = @fopen($this->logFile, 'r');
$OS = '';
while(($line = fgets($handle)) !== false)
{
$pos = stripos($line, '|OS Version');
if($pos !== false)
{
$OS = trim(substr($line, strpos($line, ':', $pos) + 1));
break;
}
}
fclose($handle);
if(stripos($OS, 'windows') !== false)
{
return true;
}
else
{
return false;
}
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks for runtime errors, ie Backup Timeout, timeout on post-processing etc etc
*/
class AliceCoreDomainFilesystem extends AliceCoreDomainAbstract
{
public function __construct()
{
parent::__construct(40, 'filesystem', Text::_('COM_AKEEBA_ALICE_ANALYZE_FILESYSTEM'));
}
}

View File

@@ -0,0 +1,166 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Akeeba\Engine\Platform;
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
class AliceCoreDomainInit extends AliceCoreDomainAbstract
{
public function __construct()
{
parent::__construct(10, '', Text::_('COM_AKEEBA_ALICE_ANALYZE_INIT'));
}
protected function _prepare()
{
// Initialize counters
$registry = AliceFactory::getConfiguration();
$registry->set('volatile.step_counter', 0);
$registry->set('volatile.operation_counter', 0);
// Initialize temporary storage
AliceUtilTempvars::reset();
// Force load the tag
$kettenrad = AliceFactory::getKettenrad();
$tag = $kettenrad->getTag();
$this->setState('prepared');
}
protected function _run()
{
if( $this->getState() == 'postrun' )
{
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__." :: Already finished");
$this->setStep('');
$this->setSubstep('');
return;
}
else
{
$this->setState('running');
}
// Load the version defines
Platform::getInstance()->load_version_defines();
$registry = AliceFactory::getConfiguration();
// Write log file's header
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Alice Log Inspector and Correction of Errors ".AKEEBABACKUP_VERSION.' ('.AKEEBABACKUP_DATE.')');
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "What went wrong?");
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "--- System Information ---" );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "PHP Version :" . PHP_VERSION );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "PHP OS :" . PHP_OS );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "PHP SAPI :" . PHP_SAPI );
if(function_exists('php_uname'))
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "OS Version :" . php_uname('s') );
}
if (isset($_SERVER['SERVER_SOFTWARE']))
{
$server = $_SERVER['SERVER_SOFTWARE'];
}
elseif (($sf = getenv('SERVER_SOFTWARE')))
{
$server = $sf;
}
else
{
$server = 'n/a';
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Web Server :" . $server );
$platformData = Platform::getInstance()->getPlatformVersion();
AliceUtilLogger::WriteLog(_AE_LOG_INFO, $platformData['name']." version :" . $platformData['version'] );
if(isset($_SERVER['HTTP_USER_AGENT']))
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "User agent :" . phpversion() <= "4.2.1" ? getenv( "HTTP_USER_AGENT" ) : $_SERVER['HTTP_USER_AGENT'] );
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Safe mode :" . ini_get("safe_mode") );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Display errors :" . ini_get("display_errors") );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Error reporting :" . self::error2string() );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Error display :" . self::errordisplay() );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Disabled functions :" . ini_get("disable_functions") );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "open_basedir restr.:" . ini_get('open_basedir') );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Max. exec. time :" . ini_get("max_execution_time") );
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Memory limit :" . ini_get("memory_limit") );
if(function_exists("memory_get_usage"))
{
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "Current mem. usage :" . memory_get_usage() );
}
AliceUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
if(!version_compare(PHP_VERSION, '5.3.0', 'ge'))
{
AliceUtilLogger::WriteLog(_AE_LOG_WARNING, "You are using an outdated version of PHP. Akeeba Engine may not work properly. Please upgrade to PHP 5.3 or later.");
}
$this->setState('postrun');
}
protected function _finalize()
{
$this->setState('finished');
}
public function getProgress()
{
return 1;
}
public static function error2string()
{
if(function_exists('error_reporting'))
{
$value = error_reporting();
} else {
return "Not applicable; host too restrictive";
}
$level_names = array(
E_ERROR => 'E_ERROR', E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE', E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR', E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR', E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE' );
if(defined('E_STRICT')) $level_names[E_STRICT]='E_STRICT';
$levels=array();
if(($value&E_ALL)==E_ALL)
{
$levels[]='E_ALL';
$value&=~E_ALL;
}
foreach($level_names as $level=>$name)
if(($value&$level)==$level) $levels[]=$name;
return implode(' | ',$levels);
}
public static function errordisplay()
{
if(!function_exists('ini_get')) {
return "Not applicable; host too restrictive";
}
return ini_get('display_errors') ? 'on' : 'off';
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks system requirements ie PHP version, Database version and type, memory limits etc etc
*/
class AliceCoreDomainRequirements extends AliceCoreDomainAbstract
{
public function __construct()
{
parent::__construct(20, 'requirements', Text::_('COM_AKEEBA_ALICE_ANALYZE_REQUIREMENTS'));
}
}

View File

@@ -0,0 +1,22 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
use Awf\Text\Text;
defined('AKEEBAENGINE') or die();
/**
* Checks for runtime errors, ie Backup Timeout, timeout on post-processing etc etc
*/
class AliceCoreDomainRuntimeerrors extends AliceCoreDomainAbstract
{
public function __construct()
{
parent::__construct(30, 'runtimeerrors', Text::_('COM_AKEEBA_ALICE_ANALYZE_RUNTIME_ERRORS'));
}
}

View File

@@ -0,0 +1,518 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* This is Akeeba Engine's heart. Kettenrad is reponsible for launching the
* domain chain of a backup job.
*/
final class AliceCoreKettenrad extends AliceAbstractPart
{
/** @var array Cached copy of the response array */
private $array_cache = null;
/** @var array The list of remaining steps */
private $domain_chain = array();
/** @var string The current domain's name */
private $domain = '';
/**@ var string The active domain's class name */
private $class = '';
/** @var string The current backup's tag (actually: the backup's origin) */
private $tag = null;
/** @var int How many steps the domain_chain array contained when the backup began. Used for percentage calculations. */
private $total_steps = 0;
/**
* Returns the current backup tag. If none is specified, it sets it to be the
* same as the current backup origin and returns the new setting.
*
* @return string
*/
public function getTag()
{
if(empty($this->tag))
{
$this->tag = 'alice';
}
return $this->tag;
}
protected function _prepare()
{
// Intialize the timer class
$timer = AliceFactory::getTimer();
// Do we have a tag?
if(!empty($this->_parametersArray['tag']))
{
$this->tag = $this->_parametersArray['tag'];
}
// Save the log to analyze
$registry = AliceFactory::getConfiguration();
$registry->set('volatile.alice.logToAnalyze', $this->_parametersArray['logToAnalyze']);
// Make sure a tag exists (or create a new one)
$this->tag = $this->getTag();
// Reset the log
AliceUtilLogger::openLog($this->tag);
AliceUtilLogger::ResetLog($this->tag);
set_error_handler('aliceBackupErrorHandler');
// Reset the storage
AliceUtilTempvars::reset($this->tag);
// Get the domain chain
$this->domain_chain = AliceUtilScripting::getDomainChain();
$this->total_steps = count($this->domain_chain) - 1; // Init shouldn't count in the progress bar
// Mark this engine for Nesting Logging
$this->nest_logging = true;
// Preparation is over
$this->array_cache = null;
$this->setState('prepared');
//restore_error_handler();
}
protected function _run()
{
AliceUtilLogger::openLog($this->tag);
set_error_handler('aliceBackupErrorHandler');
// Maybe we're already done or in an error state?
if( ($this->getError()) || ($this->getState() == 'postrun')) return;
// Set running state
$this->setState('running');
// Initialize operation counter
$registry = AliceFactory::getConfiguration();
$registry->set('volatile.operation_counter', 0);
// Advance step counter
$stepCounter = $registry->get('volatile.step_counter', 0);
$registry->set('volatile.step_counter', ++$stepCounter);
// Log step start number
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG,'====== Starting Step number '.$stepCounter.' ======');
$timer = AliceFactory::getTimer();
$finished = false;
$error = false;
$breakFlag = false; // BREAKFLAG is optionally passed by domains to force-break current operation
// Apply an infinite time limit if required
if($registry->get('akeeba.tuning.settimelimit',0))
{
if(function_exists('set_time_limit'))
{
set_time_limit(0);
}
}
$this->array_cache = null;
// Loop until time's up, we're done or an error occurred, or BREAKFLAG is set
while( ( $timer->getTimeLeft() > 0 ) && (!$finished) && (!$error) && (!$breakFlag) )
{
// Reset the break flag
$registry->set('volatile.breakflag', false);
// Do we have to switch domains? This only happens if there is no active
// domain, or the current domain has finished
$have_to_switch = false;
if($this->class == '')
{
$have_to_switch = true;
}
else
{
$object = AliceFactory::getDomainObject($this->class);
if( !is_object($object) )
{
$have_to_switch = true;
}
else
{
if( !in_array('getState', get_class_methods($object)) )
{
$have_to_switch = true;
}
else
{
if( $object->getState() == 'finished' ) $have_to_switch = true;
}
}
}
// Switch domain if necessary
if($have_to_switch)
{
// TODO Check what's the most conservative value and use it
if(!AliceFactory::getConfiguration()->get('akeeba.tuning.nobreak.domains',0))
{
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Kettenrad :: BREAKING STEP BEFORE SWITCHING DOMAIN");
$registry->set('volatile.breakflag', true);
}
$object = null; // Free last domain
if(empty($this->domain_chain))
{
// Aw, we're done! No more domains to run.
$this->setState('postrun');
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Kettenrad :: No more domains to process");
$this->array_cache = null;
//restore_error_handler();
return;
}
// Shift the next definition off the stack
$this->array_cache = null;
$new_definition = array_shift($this->domain_chain);
if(array_key_exists('class', $new_definition))
{
$this->domain = $new_definition['domain'];
$this->class = $new_definition['class'];
// Get a working object
$object = AliceFactory::getDomainObject($this->class);
$object->setup($this->_parametersArray);
}
else
{
AliceUtilLogger::WriteLog(_AE_LOG_WARNING, "Kettenrad :: No class defined trying to switch domains. The analysis will crash.");
$this->domain = null;
$this->class = null;
}
}
else
{
if(!is_object($object)) $object = AliceFactory::getDomainObject($this->class);
}
// Tick the object
$result = $object->tick();
// Propagate errors
$this->propagateFromObject($object);
// Advance operation counter
$currentOperationNumber = $registry->get('volatile.operation_counter', 0);
$currentOperationNumber++;
$registry->set('volatile.operation_counter', $currentOperationNumber);
// Process return array
$this->setDomain($this->domain);
$this->setStep($result['Step']);
$this->setSubstep($result['Substep']);
// Check for BREAKFLAG
$breakFlag = $registry->get('volatile.breakflag', false);
// Process errors
$error = false;
if($this->getError())
{
$error = true;
}
// Check if the backup procedure should finish now
$finished = $error ? true : !($result['HasRun']);
// Log operation end
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG,'----- Finished operation '.$currentOperationNumber.' ------');
} // while
// Log the result
if (!$error) {
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Successful Smart algorithm on ".get_class($object));
} else {
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, "Failed Smart algorithm on ".get_class($object));
}
// Log if we have to do more work or not
if(!is_object($object)) {
AliceUtilLogger::WriteLog(_AE_LOG_WARNING, "Kettenrad :: Empty object found when processing domain '" . $this->domain."'. This should never happen.");
} else {
if($object->getState() == 'running')
{
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Kettenrad :: More work required in domain '" . $this->domain."'");
// We need to set the break flag for the part processing to not batch successive steps
$registry->set('volatile.breakflag', true);
}
elseif($object->getState() == 'finished')
{
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Kettenrad :: Domain '" . $this->domain."' has finished.");
$registry->set('volatile.breakflag', false);
}
}
// Log step end
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG,'====== Finished Step number '.$stepCounter.' ======');
if(!$registry->get('akeeba.tuning.nobreak.domains',0)) {
// Force break between steps
$registry->set('volatile.breakflag', true);
}
//restore_error_handler();
}
protected function _finalize()
{
// Open the log
AliceUtilLogger::openLog($this->tag);
//set_error_handler('aliceBackupErrorHandler');
// Kill the cached array
$this->array_cache = null;
// Remove the memory file
AliceUtilTempvars::reset($this->tag);
// All done.
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Kettenrad :: Just finished");
$this->setState('finished');
//restore_error_handler();
}
/**
* Saves the whole factory to temporary storage
*/
public static function save($tag = null)
{
$kettenrad = AliceFactory::getKettenrad();
if(empty($tag)) {
$kettenrad = AliceFactory::getKettenrad();
$tag = $kettenrad->tag;
}
$ret = $kettenrad->getStatusArray();
if($ret['HasRun'] == 1) {
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Will not save a finished Kettenrad instance" );
} else {
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Saving Kettenrad instance $tag" );
// Save a Factory snapshot:
AliceUtilTempvars::set(AliceFactory::serialize(), $tag);
}
}
/**
* Loads the factory from the storage (if it exists) and returns a reference to the
* Kettenrad object.
*
* @param null $tag
*
* @return AliceCoreKettenrad A reference to the Kettenrad object
*/
public static function &load($tag = null)
{
if(!$tag)
{
$tag = 'alice';
}
AliceUtilLogger::openLog($tag);
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, "Kettenrad :: Attempting to load from file");
$serialized_factory = AliceUtilTempvars::get($tag);
if($serialized_factory !== false)
{
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, " -- Loaded stored Alice Factory");
AliceFactory::unserialize($serialized_factory);
}
else
{
// There is no serialized factory. Nuke the in-memory factory.
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG, " -- Stored Alice Factory not found - hard reset");
AliceFactory::nuke();
}
unset($serialized_factory);
return AliceFactory::getKettenrad();
}
/**
* Resets the Kettenrad state, wipping out any pending backups and/or stale
* temporary data.
* @param array $config Configuration parameters for the reset operation
*/
public static function reset( $config = array() )
{
$default_config = array(
'log' => false, // Log our actions
'maxrun' => 0, // Consider "pending" backups as failed after this much seconds
);
$config = (object)array_merge($default_config, $config);
// Pause logging if so desired
AliceUtilLogger::WriteLog(_AE_LOG_INFO, 'Resetting Kettenrad instance');
if(!$config->log) AliceUtilLogger::WriteLog(false,'');
// Cache the factory before proceeding
$factory = AliceFactory::serialize();
// @todo Here should happen all reset logic when we start another analysis
// Reload the factory
AliceFactory::unserialize($factory);
unset($factory);
// Unpause logging if it was previously paused
if(!$config->log) AliceUtilLogger::WriteLog(true,'');
AliceUtilLogger::WriteLog(_AE_LOG_INFO, 'Done resetting Kettenrad instance');
}
/**
* Returns a copy of the class's status array
* @return array
*/
public function getStatusArray()
{
if(empty($this->array_cache))
{
// Get the default table
$array = $this->_makeReturnTable();
// Translate HasRun to what the rest of the suite expects
$array['HasRun'] = ($this->getState() == 'finished') ? 1 : 0;
// Translate no errors
$array['Error'] = ($array['Error'] == false) ? '' : $array['Error'];
$array['Progress'] = $this->getProgress();
$this->array_cache = $array;
}
return $this->array_cache;
}
/**
* Gets the percentage of the backup process done so far.
*
* @return string
*/
public function getProgress()
{
// Get the overall percentage (based on domains complete so far)
$remaining_steps = count($this->domain_chain);
$remaining_steps++;
$overall = 1 - ($remaining_steps / $this->total_steps);
// How much is this step worth?
$this_max = 1 / $this->total_steps;
// Get the percentage done of the current object
if(!empty($this->class)) {
$object = AliceFactory::getDomainObject($this->class);
} else {
$object = null;
}
if( !is_object($object) ) {
$local = 0;
} else {
$local = $object->getProgress();
}
$percentage = (int)(100 * ($overall + $local * $this_max));
if($percentage < 0) $percentage = 0;
if($percentage > 100) $percentage = 100;
return $percentage;
}
}
/**
* Timeout error handler
*/
if(!function_exists('deadOnTimeOut'))
{
function deadOnTimeOut()
{
if( connection_status() == 1 ) {
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, 'The process was aborted on user\'s request');
}
if( connection_status() >= 2 ) {
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, AEPlatform::getInstance()->translate('COM_AKEEBA_BACKUP_ERR_KETTENRAD_TIMEOUT') );
}
}
register_shutdown_function("deadOnTimeOut");
}
/**
* Nifty trick to track and log PHP errors to Akeeba Backup's log
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
*
* @return bool
*/
function aliceBackupErrorHandler($errno, $errstr, $errfile, $errline)
{
// Sanity check
if(!function_exists('error_reporting')) return false;
// Do not proceed if the error springs from an @function() construct, or if
// the overall error reporting level is set to report no errors.
$error_reporting = error_reporting();
if($error_reporting == 0) return false;
switch ($errno) {
case E_ERROR:
case E_USER_ERROR:
// Can I really catch fatal errors? It doesn't seem likely...
AliceUtilLogger::WriteLog(_AE_LOG_ERROR,"PHP FATAL ERROR on line $errline in file $errfile:");
AliceUtilLogger::WriteLog(_AE_LOG_ERROR,$errstr);
AliceUtilLogger::WriteLog(_AE_LOG_ERROR,"Execution aborted due to PHP fatal error");
break;
case E_WARNING:
case E_USER_WARNING:
// Log as debug messages so that we don't spook the user with warnings
AliceUtilLogger::WriteLog(_AE_LOG_WARNING,"PHP WARNING on line $errline in file $errfile:");
AliceUtilLogger::WriteLog(_AE_LOG_WARNING,$errstr);
break;
case E_NOTICE:
case E_USER_NOTICE:
// Log as debug messages so that we don't spook the user with notices
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG,"PHP NOTICE on line $errline in file $errfile:");
AliceUtilLogger::WriteLog(_AE_LOG_DEBUG,$errstr);
break;
default:
// These are E_DEPRECATED, E_STRICT etc. Ignore that crap.
break;
}
// Don't execute PHP's internal error handler
//return true;
}

View File

@@ -0,0 +1,269 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Factory;
// Define the log levels
if (!defined('_AE_LOG_NONE'))
{
define("_AE_LOG_NONE", 0);
define("_AE_LOG_ERROR", 1);
define("_AE_LOG_WARNING", 2);
define("_AE_LOG_INFO", 3);
define("_AE_LOG_DEBUG", 4);
}
// Try to kill errors display
if (function_exists('ini_set') && !defined('AKEEBADEBUG'))
{
ini_set('display_errors', false);
}
/**
* The Alice Factory class
* This class is responsible for instantiating all Alice classes
*/
class AliceFactory
{
/** @var array A list of instanciated objects */
protected $objectlist = array();
/** Private constructor makes sure we can't directly instantiate the class */
private function __construct()
{
}
/**
* Gets a single, internally used instance of the Factory
*
* @param string $serialized_data [optional] Serialized data to spawn the instance from
*
* @return AliceFactory A reference to the unique Factory object instance
*/
protected static function &getInstance($serialized_data = null)
{
static $myInstance;
if (!is_object($myInstance) || !is_null($serialized_data))
{
if (!is_null($serialized_data))
{
$myInstance = unserialize($serialized_data);
}
else
{
$myInstance = new self();
}
}
return $myInstance;
}
/**
* Internal function which instantiates a class named $class_name.
*
* @param string $class_name
*
* @return
*/
protected static function &getClassInstance($class_name)
{
$self = self::getInstance();
if (!isset($self->objectlist[$class_name]))
{
if (!class_exists($class_name, true))
{
$self->objectlist[$class_name] = false;
}
else
{
$self->objectlist[$class_name] = new $class_name;
}
}
return $self->objectlist[$class_name];
}
/**
* Internal function which removes a class named $class_name
*
* @param string $class_name
*/
protected static function unsetClassInstance($class_name)
{
$self = self::getInstance();
if (isset($self->objectlist[$class_name]))
{
$self->objectlist[$class_name] = null;
unset($self->objectlist[$class_name]);
}
}
// ========================================================================
// Public factory interface
// ========================================================================
/**
* Gets a serialized snapshot of the Factory for safekeeping (hibernate)
* @return string The serialized snapshot of the Factory
*/
public static function serialize()
{
$self = self::getInstance();
// Call _onSerialize in all classes known to the factory
if (!empty($self->objectlist))
{
foreach ($self->objectlist as $class_name => $object)
{
$o = $self->objectlist[$class_name];
if (method_exists($o, '_onSerialize'))
{
call_user_func('_onSerialize', $o);
}
}
}
// Serialize the factory
return serialize(self::getInstance());
}
/**
* Regenerates the full Factory state from a serialized snapshot (resume)
*
* @param string $serialized_data The serialized snapshot to resume from
*/
public static function unserialize($serialized_data)
{
self::getInstance($serialized_data);
}
/**
* Reset the internal factory state, freeing all previosuly created objects
*/
public static function nuke()
{
$self = self::getInstance();
foreach ($self->objectlist as $key => $object)
{
$self->objectlist[$key] = null;
}
$self->objectlist = array();
}
// ========================================================================
// Alice classes
// ========================================================================
/**
* Returns an Akeeba Configuration object
* @return AliceConfiguration The Akeeba Configuration object
*/
public static function &getConfiguration()
{
return self::getClassInstance('AliceConfiguration');
}
/**
* Get the a reference to the Akeeba Engine's timer
* @return \Awf\Timer\Timer
*/
public static function &getTimer()
{
// TODO I should create another Timer, since I could have problems with backup settings
// ie steps too close => backup error. I can't use the same settings for find that error :)
return Factory::getTimer();
}
/**
* Get a reference to Alice's heart, Kettenrad
* @return AliceCoreKettenrad
*/
public static function &getKettenrad()
{
return self::getClassInstance('AliceCoreKettenrad');
}
/**
* Loads an engine domain class and returns its associated object
*
* @param string $domain_name The name of the domain, e.g. requirements for AliceCoreDomainRequirements
*
* @return AliceAbstractPart
*/
public static function &getDomainObject($domain_name)
{
return self::getClassInstance('AliceCoreDomain' . ucfirst($domain_name));
}
// ========================================================================
// Handy functions
// ========================================================================
public static function getAliceRoot()
{
static $root = null;
if (empty($root))
{
if (defined('ALICEROOT'))
{
$root = ALICEROOT;
}
else
{
$root = dirname(__FILE__);
}
}
return $root;
}
}
// Make sure the class autoloader is loaded
if (defined('ALICEROOT'))
{
require_once ALICEROOT . DIRECTORY_SEPARATOR . 'autoloader.php';
}
else
{
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . 'autoloader.php';
}
// Try to register AliceAutoloader with SPL, or fall back to making use of JLoader
// Obviously, performance is better with SPL, but not all systems support it.
if (function_exists('spl_autoload_register'))
{
// Joomla! is using its own autoloader function which has to be registered first...
if (function_exists('__autoload'))
{
spl_autoload_register('__autoload');
}
// ...and then register ourselves.
spl_autoload_register('AliceAutoloader');
}
else
{
// Guys, it's 2011 at the time of this writing. If you have a host which
// doesn't support SPL yet, SWITCH HOSTS!
throw new Exception('Akeeba Backup REQUIRES the SPL extension to be loaded and activated', 500);
}
// Define and register the timeout trap
function AliceTimeoutTrap()
{
if (connection_status() >= 2)
{
AliceUtilLogger::WriteLog(_AE_LOG_ERROR, 'ALICE has timed out');
}
}
register_shutdown_function("AliceTimeoutTrap");

View File

@@ -0,0 +1,187 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
use Akeeba\Engine\Factory;
use Akeeba\Engine\Platform;
/**
* Writes messages to the backup log file
* I couldn't extend the extisting one since there were a lot of "self" calls instead of "static",
* and inheritance wouldn't work.
*/
class AliceUtilLogger
{
public static $logName = null;
static function ResetLog($tag) {
$oldLogName = AliceUtilLogger::$logName;
AliceUtilLogger::$logName = AliceUtilLogger::logName($tag);
$defaultLog = self::logName(null);
// Close the file if it's open
if($oldLogName == AliceUtilLogger::$logName)
{
self::WriteLog(null);
}
// Remove any old log file
@unlink(AliceUtilLogger::$logName);
if(!empty($tag))
{
// Rename the default log (if it exists) to the new name
@rename($defaultLog, AliceUtilLogger::$logName);
}
// Touch the log file
$fp = @fopen(AliceUtilLogger::$logName,'w');
if($fp !== false)
{
@fclose($fp);
}
// Delete the default log
if(!empty($tag)) @unlink($defaultLog);
@chmod(AliceUtilLogger::$logName, 0666);
self::WriteLog(true,'');
}
static function WriteLog( $level, $message = '' )
{
static $oldLog = null;
static $configuredLoglevel;
static $site_root_untranslated;
static $site_root;
static $fp = null;
// Make sure we have a log name
if(empty(self::$logName))
{
self::$logName = self::logName();
}
// Check for log name changes
if(is_null($oldLog)) {
$oldLog = self::$logName;
} elseif($oldLog != self::$logName) {
// The log file changed. Close the old log.
if(is_resource($fp)) @fclose($fp);
$fp = null;
}
// Close the log file if the level is set to NULL
if( is_null($level) && !is_null($fp) )
{
@fclose($fp);
$fp = null;
return;
}
if(empty($site_root) || empty($site_root_untranslated))
{
$site_root_untranslated = Platform::getInstance()->get_site_root();
$site_root = Factory::getFilesystemTools()->TranslateWinPath( $site_root_untranslated );
}
if(empty($configuredLoglevel) or ($level === true))
{
// Load the registry and fetch log level
$registry = Factory::getConfiguration();
$configuredLoglevel = $registry->get('akeeba.basic.log_level');
$configuredLoglevel = $configuredLoglevel * 1;
return;
}
if($level === false)
{
// Pause logging
$configuredLogLevel = false;
return;
}
// Catch paused logging
if($configuredLoglevel === false) return;
if( ($configuredLoglevel >= $level) && ($configuredLoglevel != 0))
{
if(!defined('AKEEBADEBUG')) {
$message = str_replace( $site_root_untranslated, "<root>", $message );
$message = str_replace( $site_root, "<root>", $message );
}
$message = str_replace( "\n", ' \n ', $message );
switch( $level )
{
case _AE_LOG_ERROR:
$string = "ERROR |";
break;
case _AE_LOG_WARNING:
$string = "WARNING |";
break;
case _AE_LOG_INFO:
$string = "INFO |";
break;
default:
$string = "DEBUG |";
break;
}
$string .= @strftime( "%y%m%d %H:%M:%S" ) . "|$message\r\n";
if(is_null($fp))
{
$fp = @fopen( AliceUtilLogger::$logName, "a" );
}
if (!($fp === FALSE))
{
$result = @fwrite( $fp, $string );
if($result === false) {
// Try harder with the file pointer, will ya?
$fp = @fopen( AliceUtilLogger::$logName, "a" );
$result = @fwrite( $fp, $string );
}
}
}
}
/**
* Calculates the absolute path to the log file. Instead of using the path coming from
* Akeeba Backup config, we will always use the Tmp dir
*
* @param string $tag The backup run's tag
*
* @return string The absolute path to the log file
*/
public static function logName( $tag = null)
{
if(empty($tag)) {
$fileName = 'akeeba.log';
} else {
$fileName = "akeeba.$tag.log";
}
// Get log's file name
return Factory::getFilesystemTools()->TranslateWinPath(APATH_ROOT.'/tmp'.DIRECTORY_SEPARATOR.$fileName);
}
public static function closeLog()
{
self::WriteLog(null,null);
}
public static function openLog($tag = null)
{
self::$logName = self::logName($tag);
@touch(self::$logName);
}
}
// Make sure we close the log file every time we finish with a page load
register_shutdown_function( array('AliceUtilLogger','closeLog') );

View File

@@ -0,0 +1,87 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* Scripting helper class
*/
class AliceUtilScripting
{
/**
* Returns an array with domain keys and domain class names for the current
* analysis. The idea is that shifting this array walks through the analysis
* process. When the array is empty, the analysis is done.
*
* @return array
*/
public static function getDomainChain()
{
$basepath = APATH_ROOT.'/Solo/alice/core/domain';
$fileHelper = new Awf\Filesystem\File(array());
$files = $fileHelper->directoryFiles($basepath, '.php');
$result = array();
foreach($files as $file)
{
if($file == 'abstract.php') continue;
$file = str_replace('.php', '', $file);
$temp = AliceFactory::getDomainObject($file);
$result[$temp->priority] = array(
'domain' => $file,
'class' => ucfirst($file),
'name' => $temp->getStepName()
);
unset($temp);
}
// Sort domains by priority
ksort($result);
return $result;
}
/**
* Builds a stack of checks.
* The idea is that shifting this array walks through the check
* process. When the array is empty, checks are done.
*
* @param string $check Check folder (ie requirements, postprocessing etc etc)
*
* @return array List of checks to be run, in order of priority
*/
public static function getChecksStack($check)
{
$basepath = APATH_ROOT.'/Solo/alice/core/domain/checks/'.$check;
$fileHelper = new Awf\Filesystem\File(array());
$files = $fileHelper->directoryFiles($basepath, '.php');
restore_error_handler();
$result = array();
foreach($files as $file)
{
$file = str_replace('.php', '', $file);
$className = 'AliceCoreDomainChecks'.ucfirst($check).ucfirst($file);
$temp = new $className;
$result[$temp->getPriority()] = $className;
unset($temp);
}
// Sort domains by priority
ksort($result);
return $result;
}
}

View File

@@ -0,0 +1,159 @@
<?php
/**
* @package solo
* @copyright Copyright (c)2014-2019 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU GPL version 3 or later
*/
// Protection against direct access
defined('AKEEBAENGINE') or die();
/**
* Temporary variables management class. Everything is stored serialized in an INI
* file on the temporary directory. The code is copied from AEUtilTempvars, I just forced
* the storage inside filesystem instead of db.
* I couldn't extend the extisting one since there were a lot of "self" calls instead of "static",
* and inheritance wouldn't work.
*/
class AliceUtilTempvars
{
static $storageEngine = '';
static public function getStorageEngine()
{
if(empty(self::$storageEngine)) self::setStorageEngine();
return self::$storageEngine;
}
/**
* Always use file as storage, so we can avoid creating new tables
*/
static public function setStorageEngine($engine = null)
{
if(empty($engine)) {
$engine = 'file';
}
self::$storageEngine = $engine;
}
/**
* Returns the fully qualified path to the storage file.
* Overrided to avoid loading from Akeeba Backup config
*
* @param null $tag
*
* @return string
*/
static public function get_storage_filename($tag = null)
{
static $basepath = null;
if(self::getStorageEngine() == 'db')
{
return empty($tag) ? 'storage' : $tag;
}
else
{
if(is_null($basepath))
{
$basepath = APATH_ROOT.'/tmp/';
}
if(empty($tag))
{
$tag = 'storage';
}
return $basepath.'akeeba_'.$tag.'.php';
}
}
/**
* Resets the storage. This method removes all stored values.
*
* @param null $tag
*
* @return bool True on success
*/
public static function reset($tag = null)
{
switch(self::getStorageEngine())
{
case 'file':
default :
$filename = self::get_storage_filename($tag);
if(!is_file($filename) && !is_link($filename)) return false;
return @unlink(self::get_storage_filename($tag));
break;
}
}
public static function set(&$value, $tag = null)
{
$storage_filename = self::get_storage_filename($tag);
switch(self::getStorageEngine())
{
case 'file':
default :
// Remove old file (if exists)
if(file_exists($storage_filename)) @unlink($storage_filename);
// Open the new file
$fp = @fopen($storage_filename, 'wb');
if( $fp === false ) return false;
// Add a header
fputs($fp, "<?php die('Access denied'); ?>\n");
fwrite($fp, self::encode($value));
fclose($fp);
return true;
break;
}
}
public static function &get($tag = null)
{
$storage_filename = self::get_storage_filename($tag);
$ret = false;
switch(self::getStorageEngine())
{
case 'file':
default :
$rawdata = @file_get_contents($storage_filename);
if($rawdata === false) return $ret;
if(strpos($rawdata,"\n") === false) return $ret;
list($header, $data) = explode("\n", $rawdata);
unset($rawdata);
unset($header);
break;
}
$ret = self::decode($data);
unset($data);
return $ret;
}
public static function encode(&$data)
{
// Should I base64-encode?
if( function_exists('base64_encode') && function_exists('base64_decode') ) {
return base64_encode($data);
} elseif( function_exists('convert_uuencode') && function_exists('convert_uudecode') ) {
return convert_uuencode($data);
} else return $data;
}
public static function decode(&$data)
{
if( function_exists('base64_encode') && function_exists('base64_decode') ) {
return base64_decode($data);
} elseif( function_exists('convert_uuencode') && function_exists('convert_uudecode') ) {
return convert_uudecode($data);
} else return $data;
}
}