/** * 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; }
/** * 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,''); }
/** * 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); }
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; }
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(); }
/** * 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; }