Beispiel #1
0
	/**
	 * Sets or updates the statistics record of the current backup attempt
	 * @param array $data
	 */
	public function setStatistics($data)
	{
		$ret = AEPlatform::set_or_update_statistics($this->statistics_id, $data, $this);
		if($ret !== false) {
			if(!is_null($ret)) {
				$this->statistics_id = $ret;
			}
			$this->cached_data = array_merge($this->cached_data, $data);
			$result = true;
		} elseif($ret === false) {
			$result = false;
		}
		return $result;
	}
Beispiel #2
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 #3
0
	/**
	 * Save an edited backup record
	 */
	public function save()
	{
		// CSRF prevention
		if(!JRequest::getVar(JUtility::getToken(), false, 'POST')) {
			JError::raiseError('403', JText::_(version_compare(JVERSION, '1.6.0', 'ge') ? 'JLIB_APPLICATION_ERROR_ACCESS_FORBIDDEN' : 'Request Forbidden'));
		}
		
		$id = JRequest::getInt('id');
		$description = JRequest::getString('description');
		$comment = JRequest::getVar('comment',null,'default','string',4);

		$statistic = AEPlatform::get_statistics(JRequest::getInt('id'));
		$statistic['description']	= $description;
		$statistic['comment']		= $comment;
		AEPlatform::set_or_update_statistics(JRequest::getInt('id'),$statistic,$self);

		if( !$this->getError() ) {
			$message = JText::_('STATS_LOG_SAVEDOK');
			$type = 'message';
		} else {
			$message = JText::_('STATS_LOG_SAVEERROR');
			$type = 'error';
		}
		$session = JFactory::getSession();
		$task = $session->get('buadmin.task', 'default', 'akeeba');
		$this->setRedirect(JURI::base().'index.php?option=com_akeeba&view=buadmin&task='.$task, $message, $type);
	}
Beispiel #4
0
	public function apply_srp_quotas($parent) {
		$parent->relayStep('Applying quotas');
		$parent->relaySubstep('');
		
		// If no quota settings are enabled, quit
		$registry =& AEFactory::getConfiguration();
		$srpQuotas = $registry->get('akeeba.quota.srp_size_quota');
		
		if($srpQuotas <= 0)
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "No restore point quotas were defined; old restore point files will be kept intact" );
			return true; // No quota limits were requested
		}
		
		// Get valid-looking backup ID's
		$validIDs =& AEPlatform::get_valid_backup_records(true, array('restorepoint'));
		
		$statistics =& AEFactory::getStatistics();
		$latestBackupId = $statistics->getId();
		
		// Create a list of valid files
		$allFiles = array();
		if(count($validIDs))
		{
			foreach($validIDs as $id)
			{
				$stat = AEPlatform::get_statistics($id);
				// Multipart processing
				$filenames = AEUtilStatistics::get_all_filenames($stat, true);
				if(!is_null($filenames))
				{
					// Only process existing files
					$filesize = 0;
					foreach($filenames as $filename)
					{
						$filesize += @filesize($filename);
					}
					$allFiles[] = array('id' => $id, 'filenames' => $filenames, 'size' => $filesize);
				}
			}
		}
		unset($validIDs);
		
		// If there are no files, exit early
		if(count($allFiles) == 0)
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "There were no old restore points to apply quotas on" );
			return true;
		}
		
		// Init arrays
		$killids = array();
		$ret = array();
		$leftover = array();
		
		// Do we need to apply size quotas?
		AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Processing restore point size quotas" );
		// OK, let's start counting bytes!
		$runningSize = 0;
		while(count($allFiles) > 0)
		{
			// Each time, remove the last element of the backup array and calculate
			// running size. If it's over the limit, add the archive to the return array.
			$def = array_pop($allFiles);
			$runningSize += $def['size'];
			if($runningSize >= $srpQuotas)
			{
				if($latestBackupId == $def['id'])
				{
					$runningSize -= $def['size'];
				}
				else
				{
					$ret[] = $def['filenames'];
					$killids[] = $def['filenames'];
				}
			}
		}
		
		// Convert the $ret 2-dimensional array to single dimensional
		$quotaFiles = array();
		foreach($ret as $temp)
		{
			foreach($temp as $filename)
			{
				$quotaFiles[] = $filename;
			}
		}
		
		// Update the statistics record with the removed remote files
		if(!empty($killids)) foreach($killids as $id) {
			$data = array('filesexist' => '0');
			AEPlatform::set_or_update_statistics($id, $data, $parent);
		}
		
		// Apply quotas
		if(count($quotaFiles) > 0)
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Applying quotas" );
			jimport('joomla.filesystem.file');
			foreach($quotaFiles as $file)
			{
				if(!@AEPlatform::unlink($file))
				{
					$parent->setWarning("Failed to remove old system restore point file ".$file );
				}
			}
		}
		
		return true;
	}
Beispiel #5
0
	public function upload()
	{
		// Get the parameters
		$id = $this->getAndCheckId();
		$part = JRequest::getInt('part', 0);
		$frag = JRequest::getInt('frag', 0);

		// Check the backup stat ID
		if($id === false) {
			$url = 'index.php?option=com_akeeba&view=upload&tmpl=component&task=cancelled&id='.$id;
			$this->setRedirect($url, JText::_('AKEEBA_TRANSFER_ERR_INVALIDID'), 'error');
			return;
		}
		
		// Calculate the filenames
		$stat = AEPlatform::get_statistics($id);
		$local_filename = $stat['absolute_path'];
		$basename = basename($local_filename);
		$extension = strtolower(str_replace(".", "", strrchr($basename, ".")));
		
		if($part > 0) {
			$new_extension = substr($extension,0,1) . sprintf('%02u', $part); 
		} else {
			$new_extension = $extension;
		}
		
		$filename = $basename.'.'.$new_extension;
		$local_filename = substr($local_filename, 0, -strlen($extension)).$new_extension;
		
		// Load the post-processing engine
		AEPlatform::load_configuration($stat['profile_id']);
		$config = AEFactory::getConfiguration();
		
		$session = JFactory::getSession();
		$engine = null;
		if(!empty($savedEngine) && ($frag != -1)) {
			// If it's not the first fragment, try to revive the saved engine
			$savedEngine = $session->get('postproc_engine', null, 'akeeba');
			$engine = unserialize($savedEngine);
		}
		if(empty($engine)) {
			$engine_name = $config->get('akeeba.advanced.proc_engine');
			$engine = AEFactory::getPostprocEngine($engine_name);
		}
		
		// Start uploading
		$result = $engine->processPart($local_filename);
		switch($result) {
			case true:
				$part++;
				break;
			
			case 1:
				$frag++;
				$savedEngine = serialize($engine);
				$session->set('postproc_engine', null, 'akeeba');
				break;
			
			case false;
				$part = -1;
				return;
				break;
		}
		
		if(version_compare(JVERSION, '1.6.0', 'ge')) {
			$view = & $this->getView( 'upload', 'html', '', array('base_path' => $this->basePath));
		} else {
			$view = & $this->getView( 'upload', 'html', '', array( 'base_path'=>$this->_basePath));
		}

		if($part >= 0) {
			if($part < $stat['multipart']) {
				$view->setLayout('uploading');
				$view->assign('parts',$stat['multipart']);
				$view->assign('part', $part);
				$view->assign('frag', $frag);
				$view->assign('id', $id);
			} else {
				// Update stats with remote filename
				$remote_filename = $config->get('akeeba.advanced.proc_engine','').'://';
				$remote_filename .= $engine->remote_path;
				$data = array(
					'remote_filename'	=> $remote_filename
				);
				AEPlatform::set_or_update_statistics($id, $data, $engine);
				
				$view->setLayout('done');
			}
		} else {
			$view->setLayout('error');
		}
		$view->display();
	}
Beispiel #6
0
	/**
	 * Applies the size and count quotas
	 * @return bool
	 */
	private function get_remote_quotas()
	{
		// Get all records with a remote filename
		$allRecords = AEPlatform::get_valid_remote_records();
		
		// Bail out if no records found
		if(empty($allRecords)) return array();

		// Try to find the files to be deleted due to quota settings
		$statistics =& AEFactory::getStatistics();
		$latestBackupId = $statistics->getId();
		
		// Filter out the current record
		$temp = array();
		foreach($allRecords as $item)
		{
			if($item['id'] == $latestBackupId) continue;
			$item['files'] = $this->get_remote_files($item['remote_filename'], $item['multipart']);
			$temp[] = $item;
		}
		$allRecords = $temp;
		
		// Bail out if only the current backup was included in the list
		if(count($allRecords) == 0) return array();
		
		// Get quota values
		$registry =& AEFactory::getConfiguration();
		$countQuota = $registry->get('akeeba.quota.count_quota');
		$sizeQuota = $registry->get('akeeba.quota.size_quota');
		$useCountQuotas = $registry->get('akeeba.quota.enable_count_quota');
		$useSizeQuotas = $registry->get('akeeba.quota.enable_size_quota');
		$useDayQuotas = $registry->get('akeeba.quota.maxage.enable');
		$daysQuota = $registry->get('akeeba.quota.maxage.maxdays');
		$preserveDay = $registry->get('akeeba.quota.maxage.keepday');

		$leftover = array();
		$ret = array();
		$killids = array();
		
		if($useDayQuotas) {
			$killDatetime = new DateTime();
			$killDatetime->sub(new DateInterval('P'.$daysQuota.'D'));
			$killTS = $killDatetime->format('U');
			
			foreach($allRecords as $def) {
				$backupstart = new DateTime($def['backupstart']);
				$backupTS = $backupstart->format('U');
				$backupDay = $backupstart->format('d');

				// Is this on a preserve day?
				if($preserveDay > 0) {
					if($preserveDay == $backupDay) {
						$leftover[] = $def;
						continue;
					}
				}
				// Otherwise, check the timestamp
				if($backupTS < $killTS) {
					$ret[] = $def['files'];
					$killids[] = $def['id'];
				} else {
					$leftover[] = $def;
				}

			}
		}
		
		// Do we need to apply count quotas?
		if($useCountQuotas && ($countQuota >= 1) && !$useDayQuotas )
		{
			$countQuota--;
			// Are there more files than the quota limit?
			if( !(count($allRecords) > $countQuota) )
			{
				// No, effectively skip the quota checking
				$leftover = $allRecords;
			}
			else
			{
				AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Processing remote count quotas" );
				// Yes, apply the quota setting.
				$totalRecords = count($allRecords);
				for($count = 0; $count <= $totalRecords; $count++)
				{
					$def = array_pop($allRecords);
					if(count($leftover) >= $countQuota)
					{
						$ret[] = $def['files'];
						$killids[] = $def['id'];
					}
					else
					{
						$leftover[] = $def;
					}
				}
				unset($allRecords);
			}
		}
		else
		{
			// No count quotas are applied
			$leftover = $allRecords;
		}

		// Do we need to apply size quotas?
		if( $useSizeQuotas && ($sizeQuota > 0) && (count($leftover) > 0) && !$useDayQuotas )
		{			
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Processing remote size quotas" );
			// OK, let's start counting bytes!
			$runningSize = 0;
			while(count($leftover) > 0)
			{
				// Each time, remove the last element of the backup array and calculate
				// running size. If it's over the limit, add the archive to the $ret array.
				$def = array_pop($leftover);
				$runningSize += $def['total_size'];
				if($runningSize >= $sizeQuota)
				{
					$ret[] = $def['files'];
					$killids[] = $def['id'];
				}
			}
		}

		// Convert the $ret 2-dimensional array to single dimensional
		$quotaFiles = array();
		foreach($ret as $temp)
		{
			if(!is_array($temp) || empty($temp)) continue;
			foreach($temp as $filename)
			{
				$quotaFiles[] = $filename;
			}
		}
		
		// Update the statistics record with the removed remote files
		if(!empty($killids)) foreach($killids as $id) {
			if(empty($id)) continue;
			$data = array('remote_filename' => '');
			AEPlatform::set_or_update_statistics($id, $data, $this);
		}
		
		return $quotaFiles;
	}