. * * * Thank you notice: * Many thanks to Jean-Sebastien Gervais of LazyBackup.net for proving that * backup triggered by visitor activity is possible, essentially inspiring the * functionality of this plugin. */ // Protect from unauthorized access defined('_JEXEC') or die('Restricted Access'); class plgSystemAklazy extends JPlugin { /** @var string A nonce (token) to validate requests */ private $nonce = null; private $locked = 0; private $tstamp = 0; /** @var bool Did the last backup crash? */ private $isCrashed = false; private $debugInfo = ''; public function __construct(& $subject, $config = array()) { // Use the parent constructor to create the plugin object parent::__construct($subject, $config); // Check if we have to disable ourself $akreset = JRequest::getCmd('akreset',''); $defaultpw = $this->params->get('resetpw',''); if( ($akreset == $defaultpw) && !empty($defaultpw) ) { // Disable the plugin $db = JFactory::getDBO(); if( version_compare( JVERSION, '1.6.0', 'ge' ) ) { $sql = 'UPDATE `#__extensions` SET `enabled` = 0 WHERE `type` = \'plugin\' AND `element` = \'aklazy\''; } else { $sql = 'UPDATE #__plugins SET `published` = 0 WHERE `element` = \'aklazy\''; } $db->setQuery($sql); $db->query(); // Load the configuration $profile = (int)$this->params->get('profile',1); if($profile <= 0) $profile = 1; $session =& JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); AEPlatform::load_configuration($profile); // Remove the log files $logfile = AEUtilLogger::logName(null); @unlink($logfile); AEUtilLogger::ResetLog('lazy'); // Clear lock $this->unsetLock(); $this->unsetNonce(); // Reset pending backups AECoreKettenrad::reset(); // Redirect $app = JFactory::getApplication(); $app->redirect('index.php'); return; } // Hijack the application to do the backup steps if aklazy and nonce // params are defined in the URL query $aklazy = JRequest::getCmd('aklazy',null); $nonce = JRequest::getCmd('nonce',null); // Load the settings $profile = (int)$this->params->get('profile',1); if($profile <= 0) $profile = 1; AEPlatform::load_configuration($profile); $config = AEFactory::getConfiguration(); $this->locked = $config->get('lazy.lock.status', 0); $this->tstamp = $config->get('lazy.lock.stamp', 0); $this->nonce = $config->get('lazy.nonce', null); // When aklazy is 'check', it returns a backup URL, or dies if there's // no need to start/step a backup. if( ($aklazy == 'check') ) { // Do a backup necessity check and return a URL or nothing at all $state = $this->getBackupState(); if($state != 'none') { $url = JURI::base().'index.php?aklazy='.$state.'&nonce='.$this->nonce; } else { $url = ''; } @ob_end_clean(); // Just in case... echo('###'.$url.'###'); die(); } if( (in_array($aklazy, array('start','step','ajaxstart','ajaxstep'))) && !empty($nonce) ) { // Make sure we're not locked if($this->isLocked()) return; // Get the saved nonce and compare it to the one in the URL $this->getNonce(); if(empty($this->nonce)) return; if($this->nonce != $nonce) return; // Lock the backup process if($this->isLocked()) return; $this->setLock(); // Update the nonce $this->setNonce(); // Try to convince PHP to not abort the request when the user is disconnected if(function_exists('ignore_user_abort')) { ignore_user_abort(true); } // Define the basic constants for the Akeeba Engine if(!defined('AKEEBA_BACKUP_ORIGIN')) { define('AKEEBA_BACKUP_ORIGIN','lazy'); // Set the backup origin } if(!defined('AKEEBAENGINE')) { define('AKEEBAENGINE', 1); // Required for accessing Akeeba Engine's factory class define('AKEEBAPLATFORM', 'joomla15'); // So that platform-specific stuff can get done! } // Load the Akeeba Engine factory require_once JPATH_ADMINISTRATOR.DS.'components'.DS.'com_akeeba'.DS.'akeeba'.DS.'factory.php'; // Load the language files $jlang =& JFactory::getLanguage(); $jlang->load('com_akeeba', JPATH_SITE, 'en-GB', true); $jlang->load('com_akeeba', JPATH_SITE, $jlang->getDefault(), true); $jlang->load('com_akeeba', JPATH_SITE, null, true); $jlang->load('com_akeeba', JPATH_ADMINISTRATOR, 'en-GB', true); $jlang->load('com_akeeba', JPATH_ADMINISTRATOR, $jlang->getDefault(), true); $jlang->load('com_akeeba', JPATH_ADMINISTRATOR, null, true); // Set the profile and load the configuration $profile = (int)$this->params->get('profile',1); if($profile <= 0) $profile = 1; $session =& JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); AEPlatform::load_configuration($profile); $isDone = false; register_shutdown_function('AkeebaBackupLazyShutdown'); if(in_array($aklazy,array('start','ajaxstart'))) { // Start a new backup AECoreKettenrad::reset(); $kettenrad =& AECoreKettenrad::load(AKEEBA_BACKUP_ORIGIN); $user =& JFactory::getUser(); $userTZ = $user->getParam('timezone',0); $dateNow = new JDate(); $dateNow->setOffset($userTZ); if( version_compare( JVERSION, '1.6.0', 'ge' ) ) { $description = JText::_('BACKUP_DEFAULT_DESCRIPTION').' '.$dateNow->format(JText::_('DATE_FORMAT_LC2'), true); } else { $description = JText::_('BACKUP_DEFAULT_DESCRIPTION').' '.$dateNow->toFormat(JText::_('DATE_FORMAT_LC2')); } $options = array( 'description' => $description, 'comment' => '' ); $kettenrad->setup($options); $array = $kettenrad->tick(); } else { // Run a backup step $kettenrad =& AECoreKettenrad::load(AKEEBA_BACKUP_ORIGIN); $array = $kettenrad->tick(); } AECoreKettenrad::save(AKEEBA_BACKUP_ORIGIN); // Parse the return array if($array['Error'] != '') { // An error occured. Reset the engine and unset the nonce. $this->unsetNonce(); AECoreKettenrad::reset(); $isDone = true; } elseif($array['HasRun'] == false) { // All done. Clean up and unset the nonce. $this->unsetNonce(); AEFactory::nuke(); AEUtilTempvars::reset(); $isDone = true; } // Unlock the process $this->unsetLock(); // Do we need to forward to the new step? if(in_array($aklazy, array('start','step'))) { // IFRAME handling if(!$isDone) { $url = JURI::base().'index.php?aklazy=step&nonce='.$this->nonce; die("
"); } } else { if(!$isDone) { die('###'.$this->nonce.'###'); } } // Stop processing die(); } } /** * Checks if it's necessary to add background backup code to the page */ function onAfterRender() { $caching = $this->getCachingState(); $debug = ''; $html = ''; if($caching) { // If caching is enabled, use Javascript code $html = $this->getJavascript(); } else { // If caching is disabled, create a hidden backup iFrame if we need // to start or continue a backup job $action = $this->getBackupState(); if(JDEBUG) { $debug = ''.$this->debugInfo.''; } if($action != 'none') { $url = JURI::base().'index.php?aklazy='.$action.'&nonce='.$this->nonce; $html = ''; } } if(empty($html) && empty($debug)) return; // Add the extra HTML to the page $buffer = JResponse::getBody(); $pos = strpos($buffer, "