Beispiel #1
0
	/**
	 * 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(
			'global'	=> true,	// Reset all origins when true
			'log'		=> false,	// Log our actions
		);

		$config = (object)array_merge($default_config, $config);

		// Pause logging if so desired
		if(!$config->log) AEUtilLogger::WriteLog(false,'');

		$tag = null;
		if(!$config->global)
		{
			// If we're not resetting globally, get a list of running backups per tag
			$tag = AEPlatform::get_backup_origin();
		}

		// Cache the factory before proceeding
		$factory = AEFactory::serialize();

		$runningList = AEPlatform::get_running_backups($tag);
		// Origins we have to clean
		$origins = array(
			AEPlatform::get_backup_origin()
		);

		// 1. Detect failed backups
		if(is_array($runningList) && !empty($runningList))
		{
			// The current timestamp
			$now = time();

			// Mark running backups as failed
			foreach($runningList as $running)
			{
				if(empty($tag))
				{
					// Check the timestamp of the log file to decide if it's stuck,
					// but only if a tag is not set
					$tstamp = @filemtime( AEUtilLogger::logName($running['origin']) );
					if($tstamp !== false)
					{
						// We can only check the timestamp if it's returned. If not, we assume the backup is stale
						$difference = abs($now - $tstamp);
						// Backups less than 3 minutes old are not considered stale
						if($difference < 180) continue;
					}
				}

				$filenames = AEUtilStatistics::get_all_filenames($running);
				// Process if there are files to delete...
				if(!is_null($filenames))
				{
					// Delete the failed backup's archive, if exists
					foreach($filenames as $failedArchive)
					{
						AEPlatform::unlink($failedArchive);
					}
				}

				// Mark the backup failed
				$running['status'] = 'fail';
				$running['multipart'] = 0;
				$dummy = null;
				AEPlatform::set_or_update_statistics( $running['id'], $running, $dummy );

				$origins[] = $running['origin'];
			}
		}

		if(!empty($origins))
		{
			$origins = array_unique($origins);
			foreach($origins as $tag)
			{
				AECoreKettenrad::load($tag);
				// Remove temporary files
				AEUtilTempfiles::deleteTempFiles();
				// Delete any stale temporary data
				AEUtilTempvars::reset($tag);
			}
		}

		// Reload the factory
		AEFactory::unserialize($factory);
		unset($factory);

		// Unpause logging if it was previously paused
		if(!$config->log) AEUtilLogger::WriteLog(true,'');
	}
Beispiel #2
0
	/**
	 * Implements the _run() abstract method
	 */
	protected function _run()
	{
		if( $this->getState() == 'postrun' )
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__." :: Already finished");
			$this->setStep('');
			$this->setSubstep('');
			return;
		} else {
			$this->setState('running');
		}

		// Load the version defines
		AEPlatform::load_version_defines();

		$registry =& AEFactory::getConfiguration();

		// Write log file's header
		AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
		AEUtilLogger::WriteLog(_AE_LOG_INFO, "Akeeba Backup ".AKEEBA_VERSION.' ('.AKEEBA_DATE.')');
		AEUtilLogger::WriteLog(_AE_LOG_INFO, "Got backup?");
		AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
		// PHP configuration variables are tried to be logged only for debug and info log levels
		if ($registry->get('akeeba.basic.log_level') >= _AE_LOG_INFO ) {
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "--- System Information ---" );
			if( function_exists('phpversion'))
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "PHP Version        :" . phpversion() );
			if(function_exists('php_uname'))
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "OS Version         :" . php_uname('s') );
			$db =& AEFactory::getDatabase();
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "DB Version         :" . $db->getVersion() );
			if (isset($_SERVER['SERVER_SOFTWARE'])) {
				$server = $_SERVER['SERVER_SOFTWARE'];
			} else if (($sf = getenv('SERVER_SOFTWARE'))) {
				$server = $sf;
			} else {
				$server = 'n/a';
			}
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Web Server         :" . $server );
			if(function_exists('php_sapi_name'))
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "PHP Interface      :" . php_sapi_name() );
			AEPlatform::getPlatformVersion( $platform, $version );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "$platform version    :" . $version );
			if(isset($_SERVER['HTTP_USER_AGENT']))
				AEUtilLogger::WriteLog(_AE_LOG_INFO, "User agent         :" . phpversion() <= "4.2.1" ? getenv( "HTTP_USER_AGENT" ) : $_SERVER['HTTP_USER_AGENT'] );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Safe mode          :" . ini_get("safe_mode") );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Display errors     :" . ini_get("display_errors") );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Error reporting    :" . self::error2string() );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Error display      :" . self::errordisplay() );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Disabled functions :" . ini_get("disable_functions") );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "open_basedir restr.:" . ini_get('open_basedir') );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Max. exec. time    :" . ini_get("max_execution_time") );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Memory limit       :" . ini_get("memory_limit") );
			if(function_exists("memory_get_usage"))
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Current mem. usage :" . memory_get_usage() );
			if(function_exists("gzcompress")) {
				AEUtilLogger::WriteLog(_AE_LOG_INFO, "GZIP Compression   : available (good)" );
			} else {
				AEUtilLogger::WriteLog(_AE_LOG_INFO, "GZIP Compression   : n/a (no compression)" );
			}
			AEPlatform::log_platform_special_directories();
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Output directory   :" . $registry->get('akeeba.basic.output_directory') );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Temporary directory:" . $registry->get('akeeba.basic.temporary_directory') );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
		}

		// Quirks reporting
		$quirks = AEUtilQuirks::get_quirks(true);
		if( !empty($quirks) )
		{
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "Akeeba Backup has detected the following potential problems:" );
			foreach($quirks as $q)
			{
				AEUtilLogger::WriteLog(_AE_LOG_INFO, '- '.$q['code'].' '.$q['description'].' ('.$q['severity'].')' );
			}
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "You probably do not have to worry about them, but you should be aware of them." );
			AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------");
		}

		// Report profile ID
		$profile_id = AEPlatform::get_active_profile();
		AEUtilLogger::WriteLog(_AE_LOG_INFO, "Loaded profile #$profile_id");

		// Get archive name
		AEUtilFilesystem::get_archive_name($relativeArchiveName, $absoluteArchiveName);

		// ==== Stats initialisation ===
		$origin = AEPlatform::get_backup_origin(); // Get backup origin
		$profile_id = AEPlatform::get_active_profile(); // Get active profile

		$registry =& AEFactory::getConfiguration();
		$backupType = $registry->get('akeeba.basic.backup_type');
		AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Backup type is now set to '" . $backupType . "'");

		// Substitute "variables" in the archive name
		$description = AEUtilFilesystem::replace_archive_name_variables($this->description);
		$comment = AEUtilFilesystem::replace_archive_name_variables($this->comment);

		if($registry->get('volatile.writer.store_on_server', true) )
		{
			// Archive files are stored on our server
			$stat_relativeArchiveName = $relativeArchiveName;
			$stat_absoluteArchiveName = $absoluteArchiveName;
		}
		else
		{
			// Archive files are not stored on our server (FTP backup, cloud backup, sent by email, etc)
			$stat_relativeArchiveName = '';
			$stat_absoluteArchiveName = '';
		}

		$kettenrad =& AEFactory::getKettenrad();
		$temp = array(
			'description'	=> $description,
			'comment'		=> $comment,
			'backupstart'	=> AEPlatform::get_timestamp_mysql(),
			'status'		=> 'run',
			'origin'		=> $origin,
			'type'			=> $backupType,
			'profile_id'	=> $profile_id,
			'archivename'	=> $stat_relativeArchiveName,
			'absolute_path'	=> $stat_absoluteArchiveName,
			'multipart'		=> 0,
			'filesexist'	=> 1,
			'tag'			=> $kettenrad->getTag()
		);
		// Save the entry
		$statistics =& AEFactory::getStatistics();
		$statistics->setStatistics($temp);
		if($statistics->getError())
		{
			$this->setError($statistics->getError());
			return;
		}

		$statistics->release_multipart_lock();

		// Initialize the archive.
		if (AEUtilScripting::getScriptingParameter('core.createarchive',true))
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Expanded archive file name: " . $absoluteArchiveName);

			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Initializing archiver engine");
			$archiver =& AEFactory::getArchiverEngine();
			$archiver->initialize($absoluteArchiveName);
			$archiver->setComment($comment); // Add the comment to the archive itself.
			$archiver->propagateToObject($this);
			if($this->getError())
			{
				return;
			}
		}

		$this->setState('postrun');
	}
Beispiel #3
0
	public function runBackup()
	{
		$ret_array = array();
		
		$ajaxTask = $this->getState('ajax');

		switch($ajaxTask)
		{
			case 'start':
				// Description is passed through a strict filter which removes HTML
				$description = $this->getState('description');
				// The comment is passed through the Safe HTML filter (note: use 2 to force no filtering)
				$comment = $this->getState('comment');
				$jpskey = $this->getState('jpskey');

				$tag = $this->getState('tag');

				// Try resetting the engine
				AECoreKettenrad::reset();

				// Remove any stale memory files left over from the previous step

				if(empty($tag)) $tag = AEPlatform::get_backup_origin();
				AEUtilTempvars::reset($tag);
				
				$kettenrad =& AECoreKettenrad::load($tag);

				// Take care of System Restore Point setup
				if($tag == 'restorepoint') {
					// Fetch the extension's version information
					require_once JPATH_COMPONENT_ADMINISTRATOR.DS.'liveupdate'.DS.'classes'.DS.'xmlslurp.php';
					$slurp = new LiveUpdateXMLSlurp();
					$exttype = $this->getState('type');
					switch($exttype) {
						case 'component':
							$extname = 'com_';
							break;
						case 'module':
							$extname = 'mod_';
							break;
						case 'plugin':
							$extname = 'plg_';
							break;
						case 'template':
							$extname = 'tpl_';
							break;
					}
					$extname .= $this->getState('name');
					$info = $slurp->getInfo($extname, '');
					
					// Get the configOverrides for this extension
					AEPlatform::$configOverrides = $this->getConfigOverridesForSRP($extname, $info);
					
					// Create an SRP descriptor
					$srpdescriptor = array(
						'type'			=> $this->getState('type'),
						'name'			=> $this->getState('name'),
						'group'			=> $this->getState('group'),
						'version'		=> $info['version'],
						'date'			=> $info['date']
					);

					// Set the description and comment
					$description = "System Restore Point - ".JText::_($exttype).": $extname";
					$comment = "---BEGIN SRP---\n".json_encode($srpdescriptor)."\n---END SRP---";
					$jpskey = '';
					
					// Set a custom finalization action queue
					AEPlatform::$configOverrides['volatile.core.finalization.action_handlers'] = array(
						new AEFinalizationSrpquotas()						
					);
					AEPlatform::$configOverrides['volatile.core.finalization.action_queue'] = array(
						'remove_temp_files',
						'update_statistics',
						'update_filesizes',
						'apply_srp_quotas'
					);
				}
				
				$options = array(
					'description'	=> $description,
					'comment'		=> $comment,
					'jpskey'		=> $jpskey
				);
				$kettenrad->setup($options);
				$kettenrad->tick();
				if( ($kettenrad->getState() != 'running') && ($tag == 'restorepoint') ) {
					$kettenrad->tick();
				}
				$ret_array  = $kettenrad->getStatusArray();
				$kettenrad->resetWarnings(); // So as not to have duplicate warnings reports
				AECoreKettenrad::save($tag);
				break;

			case 'step':
				$tag = $this->getState('tag');
				$kettenrad =& AECoreKettenrad::load($tag);
				$kettenrad->tick();
				$ret_array  = $kettenrad->getStatusArray();
				$kettenrad->resetWarnings(); // So as not to have duplicate warnings reports
				AECoreKettenrad::save($tag);

				if($ret_array['HasRun'] == 1)
				{
					// Clean up
					AEFactory::nuke();
					AEUtilTempvars::reset($tag);
				}
				break;

			default:
				break;
		}
		
		return $ret_array;
	}
Beispiel #4
0
	/**
	 * Sends an email to the administrators
	 * @return bool
	 */
	private function mail_administrators()
	{
		$this->setStep('Processing emails to administrators');
		$this->setSubstep('');
		// Skip email for back-end backups
		if(AEPlatform::get_backup_origin() == 'backend' ) return true;

		$must_email = AEPlatform::get_platform_configuration_option('frontend_email_on_finish', 0) != 0;
		if(!$must_email) return true;

		AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Preparing to send e-mail to administrators");

		$email = AEPlatform::get_platform_configuration_option('frontend_email_address', '');
		$email = trim($email);
		if( !empty($email) )
		{
			$emails = array($email);
		}
		else
		{
			$emails = AEPlatform::get_administrator_emails();
		}

		if(!empty($emails))
		{
			// Fetch user's preferences
			$subject = trim(AEPlatform::get_platform_configuration_option('frontend_email_subject',''));
			$body = trim(AEPlatform::get_platform_configuration_option('frontend_email_body',''));

			// Get the statistics
			$statistics =& AEFactory::getStatistics();
			$stat = $statistics->getRecord();
			$parts = AEUtilStatistics::get_all_filenames($stat, false);

			$profile_number = AEPlatform::get_active_profile();
			$profile_name = AEPlatform::get_profile_name($profile_number);
			$parts = AEUtilStatistics::get_all_filenames($stat, false);
			$stat = (object)$stat;
			$num_parts = $stat->multipart;
			if($num_parts == 0) $num_parts = 1; // Non-split archives have a part count of 0
			$parts_list = '';
			if(!empty($parts)) foreach($parts as $file) {
				$parts_list .= "\t".basename($file)."\n";
			}

			// Do we need a default subject?
			if(empty($subject)) {
				// Get the default subject
				$subject = AEPlatform::translate('EMAIL_SUBJECT_OK');
			} else {
				// Post-process the subject
				$subject = AEUtilFilesystem::replace_archive_name_variables($subject);
			}

			// Do we need a default body?
			if(empty($body)) {
				$body = AEPlatform::translate('EMAIL_BODY_OK');
				$info_source = AEPlatform::translate('EMAIL_BODY_INFO');
				$body .= "\n\n" . sprintf($info_source, $profile_number, $num_parts) . "\n\n";
				$body .= $parts_list;
			} else {
				// Post-process the body
				$body = AEUtilFilesystem::replace_archive_name_variables($body);
				$body = str_replace('[PROFILENUMBER]', $profile_number, $body);
				$body = str_replace('[PROFILENAME]', $profile_name, $body);
				$body = str_replace('[PARTCOUNT]', $num_parts, $body);
				$body = str_replace('[FILELIST]', $parts_list, $body);
			}
			// Sometimes $body contains literal \n instead of newlines
			$body = str_replace('\\n',"\n", $body);

			foreach($emails as $email)
			{
				AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Sending email to $email");
				AEPlatform::send_email($email, $subject, $body);
			}
		}

		return true;
	}