Beispiel #1
0
	public function display()
	{
		$task = JRequest::getCmd('task','default');

		switch($task)
		{
			case 'showcomment':
				JToolBarHelper::title(JText::_('AKEEBA').': <small>'.JText::_('BUADMIN').'</small>','akeeba');
				JToolBarHelper::back('AKEEBA_CONTROLPANEL', 'index.php?option='.JRequest::getCmd('option'));
				JToolBarHelper::save();
				JToolBarHelper::cancel();
				$document =& JFactory::getDocument();
				$document->addStyleSheet(JURI::base().'../media/com_akeeba/theme/akeebaui.css?'.AKEEBAMEDIATAG);

				$id = JRequest::getInt('id',0);
				$record = AEPlatform::get_statistics($id);
				$this->assign('record', $record);
				$this->assign('record_id', $id);

				JRequest::setVar('tpl','comment');
				break;

			default:
				$registry =& AEFactory::getConfiguration();

				if($task == 'default') {
					JToolBarHelper::title(JText::_('AKEEBA').': <small>'.JText::_('BUADMIN').'</small>','akeeba');
				} else {
					JToolBarHelper::title(JText::_('AKEEBA').': <small>'.JText::_('BUADMINSRP').'</small>','akeeba');
				}

				JToolBarHelper::back('AKEEBA_CONTROLPANEL', 'index.php?option='.JRequest::getCmd('option'));
				JToolBarHelper::spacer();
				JToolBarHelper::deleteList();
				JToolBarHelper::custom( 'deletefiles', 'delete.png', 'delete_f2.png', JText::_('STATS_LABEL_DELETEFILES'), true );

				// Add custom submenus
				JSubMenuHelper::addEntry(
					JText::_('BUADMIN_LABEL_BACKUPS'),
					JURI::base().'index.php?option=com_akeeba&view='.JRequest::getCmd('view').'&task=default',
					($task == 'default')
				);
				JSubMenuHelper::addEntry(
					JText::_('BUADMIN_LABEL_SRP'),
					JURI::base().'index.php?option=com_akeeba&view='.JRequest::getCmd('view').'&task=restorepoint',
					($task == 'restorepoint')
				);
				
				if(AKEEBA_PRO && ($task == 'default'))
				{
					$bar = & JToolBar::getInstance('toolbar');
					$bar->appendButton( 'Link', 'restore', JText::_('DISCOVER'), 'index.php?option=com_akeeba&view=discover' );
					JToolBarHelper::publish('restore', JText::_('STATS_LABEL_RESTORE'));
				}

				if(($task == 'default')) {
					JToolBarHelper::editList('showcomment', JText::_('STATS_LOG_EDITCOMMENT'));
					
					$pModel = JModel::getInstance('Profiles','AkeebaModel');
					$enginesPerPprofile = $pModel->getPostProcessingEnginePerProfile();
					$this->assign('enginesPerProfile', $enginesPerPprofile);
				}
				JToolBarHelper::spacer();

				// "Show warning first" download button. Joomlantastic!
				$confirmationText = AkeebaHelperEscape::escapeJS( JText::_('STATS_LOG_DOWNLOAD_CONFIRM'), "'\n" );
				$baseURI = JURI::base();
				$js = <<<ENDSCRIPT
function confirmDownloadButton()
{
	var answer = confirm('$confirmationText');
	if(answer) submitbutton('download');
}

function confirmDownload(id, part)
{
	var answer = confirm('$confirmationText');
	var newURL = '$baseURI';
	if(answer) {
		newURL += 'index.php?option=com_akeeba&view=buadmin&task=download&id='+id;
		if( part != '' ) newURL += '&part=' + part
		window.location = newURL;
	}
}

ENDSCRIPT;

				$document =& JFactory::getDocument();
				$document->addScriptDeclaration($js);				
				$document->addStyleSheet(JURI::base().'../media/com_akeeba/theme/akeebaui.css?'.AKEEBAMEDIATAG);
				
				$hash = 'akeebabuadmin';
		
				// ...ordering
				$app = JFactory::getApplication();
				$this->lists->set('order',			$app->getUserStateFromRequest($hash.'filter_order',
					'filter_order', 'backupstart'));
				$this->lists->set('order_Dir',		$app->getUserStateFromRequest($hash.'filter_order_Dir',
					'filter_order_Dir', 'DESC'));
				
				// ...filter state
				$this->lists->set('fltDescription',	$app->getUserStateFromRequest($hash.'filter_description',
					'description', null));
				$this->lists->set('fltFrom',		$app->getUserStateFromRequest($hash.'filter_from',
					'from', null));
				$this->lists->set('fltTo',			$app->getUserStateFromRequest($hash.'filter_to',
					'to', null));
				$this->lists->set('fltOrigin',		$app->getUserStateFromRequest($hash.'filter_origin',
					'origin', null));
				$this->lists->set('fltProfile',		$app->getUserStateFromRequest($hash.'filter_profile',
					'profile', null));
				
				$filters = $this->_getFilters();
				$ordering = $this->_getOrdering();

				require_once JPATH_COMPONENT_ADMINISTRATOR.DS.'models'.DS.'statistics.php';
				$model = new AkeebaModelStatistics();
				$list =& $model->getStatisticsListWithMeta(false, $filters, $ordering);

				// Assign data to the view
				$this->assignRef( 'lists',		$this->lists); // Filter lists
				$this->assignRef( 'list',		$list); // Data
				$this->assignRef( 'pagination',	$model->getPagination($filters)); // Pagination object
				break;
		}

		// Add live help
		AkeebaHelperIncludes::addHelp();

		parent::display(JRequest::getVar('tpl'));
	}
Beispiel #2
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 #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
	/**
	 * Was the last backup a failed one? Used to apply magic settings as a means of
	 * troubleshooting.
	 *
	 * @return bool
	 */
	public function isLastBackupFailed()
	{
		// Get the last backup record ID
		$list = AEPlatform::get_statistics_list(0,1);
		if(empty($list)) return false;
		$id = $list[0];

		$statmodel->setId($id);
		$record = AEPlatform::get_statistics($id);

		return ($record['status'] == 'fail');
	}
Beispiel #5
0
	/**
	 * Validates the data passed to the request.
	 * @return mixed True if all is OK, an error string if something is wrong
	 */
	function validateRequest()
	{
		// Does the ID exist?
		$id = $this->getId();
		if(empty($id))
		{
			return JText::_('RESTORE_ERROR_INVALID_RECORD');
		}

		// Is this a valid backup entry?
		$data = AEPlatform::get_statistics($id);
		if(empty($data))
		{
			return JText::_('RESTORE_ERROR_INVALID_RECORD');
		}

		// Is this a complete backup?
		if($data['status'] != 'complete')
		{
			return JText::_('RESTORE_ERROR_INVALID_RECORD');
		}
		
		// Is it a restoration point backup?
		if($data['tag'] != 'restorepoint') {
			return JText::_('RESTORE_ERROR_NOT_AN_SRP');
		}
		
		$rawDataParts = explode("\n", $data['comment']);
		$this->info = json_decode($rawDataParts[1]);
		$this->info->srpdate = $data['backupstart'];

		// Load the profile ID (so that we can find out the output directory)
		$profile_id = $data['profile_id'];
		AEPlatform::load_configuration($profile_id);

		$path = $data['absolute_path'];
		$exists = @file_exists($path);
		if(!$exists)
		{
			// Let's try figuring out an alternative path
			$config =& AEFactory::getConfiguration();
			$path = $config->get('akeeba.basic.output_directory', '').DS.$data['archivename'];
			$exists = @file_exists($path);
		}

		if(!$exists)
		{
			return JText::_('RESTORE_ERROR_ARCHIVE_MISSING');
		}

		$filename = basename($path);
		$lastdot = strrpos($filename, '.');
		$extension = strtoupper( substr($filename, $lastdot+1) );
		if( !in_array($extension, array('JPA','ZIP')) )
		{
			return JText::_('RESTORE_ERROR_INVALID_TYPE');
		}

		$this->data =& $data;
		$this->path = $path;
		$this->extension = $extension;

		return true;
	}
Beispiel #6
0
	/**
	 * Gets the stats record ID from the request and checks that it does exist
	 * 
	 * @return bool|int False if an invalid ID is found, the numeric ID if it's valid
	 */
	private function getAndCheckId()
	{
		$id = JRequest::getInt('id',0);
		
		if($id <= 0) return false;

		$statObject = AEPlatform::get_statistics($id);
		if(empty($statObject) || !is_array($statObject)) return false;

		return $id;
	}
Beispiel #7
0
	/**
	 * Applies the size and count quotas
	 * @return bool
	 */
	private function apply_quotas()
	{
		$this->setStep('Applying quotas');
		$this->setSubstep('');

		// If no quota settings are enabled, quit
		$registry =& AEFactory::getConfiguration();
		$useDayQuotas = $registry->get('akeeba.quota.maxage.enable');
		$useCountQuotas = $registry->get('akeeba.quota.enable_count_quota');
		$useSizeQuotas = $registry->get('akeeba.quota.enable_size_quota');
		if(! ($useDayQuotas || $useCountQuotas || $useSizeQuotas) )
		{
			$this->apply_obsolete_quotas();

			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "No quotas were defined; old backup files will be kept intact" );
			return true; // No quota limits were requested
		}

		// Try to find the files to be deleted due to quota settings
		$statistics =& AEFactory::getStatistics();
		$latestBackupId = $statistics->getId();

		// Get quota values
		$countQuota = $registry->get('akeeba.quota.count_quota');
		$sizeQuota = $registry->get('akeeba.quota.size_quota');
		$daysQuota = $registry->get('akeeba.quota.maxage.maxdays');
		$preserveDay = $registry->get('akeeba.quota.maxage.keepday');

		// Get valid-looking backup ID's
		$validIDs =& AEPlatform::get_valid_backup_records(true, array('NOT','restorepoint'));

		// Create a list of valid files
		$allFiles = array();
		if(count($validIDs))
		{
			foreach($validIDs as $id)
			{
				$stat = AEPlatform::get_statistics($id);
				try {
					$backupstart = new DateTime($stat['backupstart']);
					$backupTS = $backupstart->format('U');
					$backupDay = $backupstart->format('d');
				} catch (Exception $e) {
					$backupTS = 0;
					$backupDay = 0;
				}
				// 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, 'backupstart' => $backupTS, 'day' => $backupDay);
				}
			}
		}
		unset($validIDs);

		// If there are no files, exit early
		if(count($allFiles) == 0)
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "There were no old backup files to apply quotas on" );
			return true;
		}

		// Init arrays
		$killids = array();
		$ret = array();
		$leftover = array();
		
		// Do we need to apply maximum backup age quotas?
		if($useDayQuotas) {
			$killDatetime = new DateTime();
			$killDatetime->sub(new DateInterval('P'.$daysQuota.'D'));
			$killTS = $killDatetime->format('U');
			foreach($allFiles as $file) {
				// Is this on a preserve day?
				if($preserveDay > 0) {
					if($preserveDay == $file['day']) {
						$leftover[] = $file;
						continue;
					}
				}
				// Otherwise, check the timestamp
				if($file['backupstart'] < $killTS) {
					$ret[] = $file['filenames'];
					$killids[] = $file['id'];
				} else {
					$leftover[] = $file;
				}
			}
		}

		// Do we need to apply count quotas?
		if($useCountQuotas && is_numeric($countQuota) && !($countQuota <= 0) && !$useDayQuotas )
		{
			// Are there more files than the quota limit?
			if( !(count($allFiles) > $countQuota) )
			{
				// No, effectively skip the quota checking
				$leftover =& $allFiles;
			}
			else
			{
				AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Processing count quotas" );
				// Yes, aply the quota setting. Add to $ret all entries minus the last
				// $countQuota ones.
				$totalRecords = count($allFiles);
				$checkLimit = $totalRecords - $countQuota;
				// Only process if at least one file (current backup!) is to be left
				for($count = 0; $count < $totalRecords; $count++)
				{
					$def = array_pop($allFiles);
					if(count($ret) < $checkLimit)
					{
						if($latestBackupId != $def['id']) {
							$ret[] = $def['filenames'];
							$killids[] = $def['id'];
						}
					}
					else
					{
						$leftover[] = $def;
					}
				}
				unset($allFiles);
			}
		}
		else
		{
			// No count quotas are applied
			$leftover =& $allFiles;
		}

		// Do we need to apply size quotas?
		if( $useSizeQuotas && is_numeric($sizeQuota) && !($sizeQuota <= 0) && (count($leftover) > 0) && !$useDayQuotas )
		{
			AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Processing 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 return array.
				$def = array_pop($leftover);
				$runningSize += $def['size'];
				if($runningSize >= $sizeQuota)
				{
					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, $this);
		}

		// 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))
				{
					$this->setWarning("Failed to remove old backup file ".$file );
				}
			}
		}

		$this->apply_obsolete_quotas();

		return true;
	}
Beispiel #8
0
	private function _apiDownloadDirect($config)
	{
		$defConfig = array(
			'backup_id'			=> 0,
			'part_id'			=> 1
		);
		$config = array_merge($defConfig, $config);
		extract($config);

		$backup_stats = AEPlatform::get_statistics($backup_id);
		if(empty($backup_stats))
		{
			// Backup record doesn't exist
			$this->status = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup record identifier');
			flush();
			JFactory::getApplication()->close();
		}
		$files = AEUtilStatistics::get_all_filenames($backup_stats);

		if( (count($files) < $part_id) || ($part_id <= 0) )
		{
			// Invalid part
			$this->status = self::STATUS_NOT_FOUND;
			$this->encapsulation = self::ENCAPSULATION_RAW;
			@ob_end_clean();
			header('HTTP/1.1 500 Invalid backup part');
			flush();
			JFactory::getApplication()->close();
		}

		$filename = $files[$part_id-1];
		@clearstatcache();
		
		// For a certain unmentionable browser -- Thank you, Nooku, for the tip
		if(function_exists('ini_get') && function_exists('ini_set')) {
			if(ini_get('zlib.output_compression')) {
				ini_set('zlib.output_compression', 'Off');
			}
		}
		
		// Remove php's time limit -- Thank you, Nooku, for the tip
		if(function_exists('ini_get') && function_exists('set_time_limit')) {
			if(!ini_get('safe_mode') ) {
			    @set_time_limit(0);
	        }
		}
		
		$basename = @basename($filename);
		$filesize = @filesize($filename);
		$extension = strtolower(str_replace(".", "", strrchr($filename, ".")));

		while (@ob_end_clean());
		@clearstatcache();
		// Send MIME headers
		header('MIME-Version: 1.0');
		header('Content-Disposition: attachment; filename='.$basename);
		header('Content-Transfer-Encoding: binary');
		header('Accept-Ranges: bytes');
		
		switch($extension)
		{
			case 'zip':
				// ZIP MIME type
				header('Content-Type: application/zip');
				break;

			default:
				// Generic binary data MIME type
				header('Content-Type: application/octet-stream');
				break;
		}
		// Notify of filesize, if this info is available
		if($filesize > 0) header('Content-Length: '.@filesize($filename));
		// Disable caching
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Expires: 0");
		header('Pragma: no-cache');
		flush();
		if($filesize > 0)
		{
			// If the filesize is reported, use 1M chunks for echoing the data to the browser
			$blocksize = 1048756; //1M chunks
			$handle    = @fopen($filename, "r");
			// Now we need to loop through the file and echo out chunks of file data
			if($handle !== false) while(!@feof($handle)){
			    echo @fread($handle, $blocksize);
			    @ob_flush();
				flush();
			}
			if($handle !== false) @fclose($handle);
		} else {
			// If the filesize is not reported, hope that readfile works
			@readfile($filename);
		}
		flush();
		JFactory::getApplication()->close();
	}