/** * Creates a randomly-named temporary file, registers it with the temporary * files management and returns its absolute path * * @return string The temporary file name */ public function createRegisterTempFile() { // Create a randomly named file in the temp directory $registry = Factory::getConfiguration(); $tempFile = tempnam($registry->get('akeeba.basic.output_directory'), 'ak'); // Register it and return its absolute path $tempName = basename($tempFile); return Factory::getTempFiles()->registerTempFile($tempName); }
private function _apiStartBackup($config) { // Get the passed configuration values $defConfig = array('profile' => 1, 'description' => '', 'comment' => '', 'backupid' => null); $config = array_merge($defConfig, $config); $profile = $config['profile']; $description = $config['description']; $comment = $config['comment']; $backupid = $config['backupid']; // Nuke the factory Factory::nuke(); // Set the profile $profile = (int) $profile; if (!is_numeric($profile)) { $profile = 1; } if (strtoupper($backupid) == '[DEFAULT]') { $db = F0FPlatform::getInstance()->getDbo(); $query = $db->getQuery(true)->select('MAX(' . $db->qn('id') . ')')->from($db->qn('#__ak_stats')); try { $maxId = $db->setQuery($query)->loadResult(); } catch (Exception $e) { $maxId = 0; } $backupid = 'id' . ($maxId + 1); } elseif (empty($backupid)) { $backupid = null; } $session = JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); Platform::getInstance()->load_configuration($profile); // Check if there are critical issues preventing the backup if (!Factory::getConfigurationChecks()->getShortStatus()) { $configChecks = Factory::getConfigurationChecks()->getDetailedStatus(); foreach ($configChecks as $checkItem) { if ($checkItem['severity'] != 'critical') { continue; } $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'Failed configuration check Q' . $checkItem['code'] . ': ' . $checkItem['description'] . '. Please refer to https://www.akeebabackup.com/warnings/q' . $checkItem['code'] . '.html for more information and troubleshooting instructions.'; } } // Use the default description if none specified if (empty($description)) { JLoader::import('joomla.utilities.date'); $dateNow = new JDate(); /* $user = JFactory::getUser(); $userTZ = $user->getParam('timezone',0); $dateNow->setOffset($userTZ); */ $description = JText::_('BACKUP_DEFAULT_DESCRIPTION') . ' ' . $dateNow->format(JText::_('DATE_FORMAT_LC2'), true); } // Start the backup Factory::resetState(array('maxrun' => 0)); Factory::getTempFiles()->deleteTempFiles(); $tempVarsTag = AKEEBA_BACKUP_ORIGIN; $tempVarsTag .= empty($backupid) ? '' : '.' . $backupid; Factory::getFactoryStorage()->reset($tempVarsTag); Factory::loadState(AKEEBA_BACKUP_ORIGIN, $backupid); $kettenrad = Factory::getKettenrad(); $kettenrad->setBackupId($backupid); $options = array('description' => $description, 'comment' => $comment, 'tag' => AKEEBA_BACKUP_ORIGIN); $kettenrad->setup($options); // Setting up the engine $array = $kettenrad->tick(); // Initializes the init domain try { Factory::saveState(AKEEBA_BACKUP_ORIGIN, $backupid); } catch (\RuntimeException $e) { $array['Error'] = $e->getMessage(); } $array = $kettenrad->getStatusArray(); if ($array['Error'] != '') { // A backup error had occurred. Why are we here?! $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'A backup error had occurred: ' . $array['Error']; } else { $statistics = Factory::getStatistics(); $array['BackupID'] = $statistics->getId(); $array['HasRun'] = 1; // Force the backup to go on. return $array; } }
/** * Removes temporary files * * @return bool True on success */ protected function remove_temp_files() { $this->setStep('Removing temporary files'); $this->setSubstep(''); Factory::getLog()->log(LogLevel::DEBUG, "Removing temporary files"); Factory::getTempFiles()->deleteTempFiles(); return true; }
/** * Create a Central Directory temporary file * * @return void * * @throws ErrorException */ private function createCentralDirectoryTempFile() { $configuration = Factory::getConfiguration(); $this->centralDirectoryFilename = tempnam($configuration->get('akeeba.basic.output_directory'), 'akzcd'); $this->centralDirectoryFilename = basename($this->centralDirectoryFilename); $pos = strrpos($this->centralDirectoryFilename, '/'); if ($pos !== false) { $this->centralDirectoryFilename = substr($this->centralDirectoryFilename, $pos + 1); } $pos = strrpos($this->centralDirectoryFilename, '\\'); if ($pos !== false) { $this->centralDirectoryFilename = substr($this->centralDirectoryFilename, $pos + 1); } $this->centralDirectoryFilename = Factory::getTempFiles()->registerTempFile($this->centralDirectoryFilename); Factory::getLog()->log(LogLevel::DEBUG, __CLASS__ . " :: CntDir Tempfile = " . $this->centralDirectoryFilename); // Create temporary file if (!@touch($this->centralDirectoryFilename)) { throw new ErrorException("Could not open temporary file for ZIP archiver. Please check your temporary directory's permissions!"); } if (function_exists('chmod')) { chmod($this->centralDirectoryFilename, 0666); } }
/** * Resets the engine state, wiping out any pending backups and/or stale * temporary data. * * @param array $config Configuration parameters for the reset operation */ public static function resetState($config = array()) { $default_config = array('global' => true, 'log' => false, 'maxrun' => 180); $config = (object) array_merge($default_config, $config); // Pause logging if so desired if (!$config->log) { Factory::getLog()->pause(); } $originTag = null; if (!$config->global) { // If we're not resetting globally, get a list of running backups per tag $originTag = Platform::getInstance()->get_backup_origin(); } // Cache the factory before proceeding $factory = self::serialize(); $runningList = Platform::getInstance()->get_running_backups($originTag); // Origins we have to clean $origins = array(Platform::getInstance()->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($originTag)) { // Check the timestamp of the log file to decide if it's stuck, // but only if a tag is not set $tstamp = Factory::getLog()->getLastTimestamp($running['origin']); if (!is_null($tstamp)) { // 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 maxrun seconds old are not considered stale (default: 3 minutes) if ($difference < $config->maxrun) { continue; } } } $filenames = Factory::getStatistics()->get_all_filenames($running, false); $totalSize = 0; // Process if there are files to delete... if (!is_null($filenames)) { // Delete the failed backup's archive, if exists foreach ($filenames as $failedArchive) { if (file_exists($failedArchive)) { $totalSize += (int) @filesize($failedArchive); Platform::getInstance()->unlink($failedArchive); } } } // Mark the backup failed if (!$running['total_size']) { $running['total_size'] = $totalSize; } $running['status'] = 'fail'; $running['multipart'] = 0; $dummy = null; Platform::getInstance()->set_or_update_statistics($running['id'], $running, $dummy); $backupId = isset($running['backupid']) ? '.' . $running['backupid'] : ''; $origins[] = $running['origin'] . $backupId; } } if (!empty($origins)) { $origins = array_unique($origins); foreach ($origins as $originTag) { self::loadState($originTag); // Remove temporary files Factory::getTempFiles()->deleteTempFiles(); // Delete any stale temporary data self::getFactoryStorage()->reset($originTag); } } // Reload the factory self::unserialize($factory); unset($factory); // Unpause logging if it was previously paused if (!$config->log) { Factory::getLog()->unpause(); } }
public function browse() { // Check permissions $this->_checkPermissions(); // Set the profile $this->_setProfile(); // Get the backup ID $backupId = $this->input->get('backupid', null, 'raw', 2); if (strtoupper($backupId) == '[DEFAULT]') { $db = JFactory::getDbo(); $query = $db->getQuery(true)->select('MAX(' . $db->qn('id') . ')')->from($db->qn('#__ak_stats')); try { $maxId = $db->setQuery($query)->loadResult(); } catch (Exception $e) { $maxId = 0; } $backupId = 'id' . ($maxId + 1); } elseif (empty($backupId)) { $backupId = null; } // Start the backup JLoader::import('joomla.utilities.date'); Factory::resetState(array('maxrun' => 0)); Factory::getTempFiles()->deleteTempFiles(); $tempVarsTag = AKEEBA_BACKUP_ORIGIN; $tempVarsTag .= empty($backupId) ? '' : '.' . $backupId; Factory::getFactoryStorage()->reset($tempVarsTag); Factory::loadState(AKEEBA_BACKUP_ORIGIN, $backupId); $kettenrad = Factory::getKettenrad(); $kettenrad->setBackupId($backupId); $dateNow = new JDate(); $description = JText::_('BACKUP_DEFAULT_DESCRIPTION') . ' ' . $dateNow->format(JText::_('DATE_FORMAT_LC2'), true); $options = array('description' => $description, 'comment' => ''); $kettenrad->setup($options); $kettenrad->tick(); $kettenrad->tick(); $array = $kettenrad->getStatusArray(); try { Factory::saveState(AKEEBA_BACKUP_ORIGIN, $backupId); } catch (\RuntimeException $e) { $array['Error'] = $e->getMessage(); } if ($array['Error'] != '') { // An error occured die('500 ERROR -- ' . $array['Error']); } else { $noredirect = $this->input->get('noredirect', 0, 'int'); if ($noredirect != 0) { @ob_end_clean(); header('Content-type: text/plain'); header('Connection: close'); echo "301 More work required"; flush(); JFactory::getApplication()->close(); } else { $curUri = JUri::getInstance(); $ssl = $curUri->isSSL() ? 1 : 0; $tempURL = JRoute::_('index.php?option=com_akeeba', false, $ssl); $uri = new JUri($tempURL); $uri->setVar('view', 'backup'); $uri->setVar('task', 'step'); $uri->setVar('key', $this->input->get('key', '', 'none', 2)); $uri->setVar('profile', $this->input->get('profile', 1, 'int')); if (!empty($backupId)) { $uri->setVar('backupid', $backupId); } // Maybe we have a multilingual site? $lg = F0FPlatform::getInstance()->getLanguage(); $languageTag = $lg->getTag(); $uri->setVar('lang', $languageTag); $redirectionUrl = $uri->toString(); $this->_customRedirect($redirectionUrl); } } }
private function _apiStartBackup($config) { // Get the passed configuration values $defConfig = array('profile' => 1, 'description' => '', 'comment' => '', 'backupid' => null); $config = array_merge($defConfig, $config); foreach ($config as $key => $value) { if (!array_key_exists($key, $defConfig)) { unset($config[$key]); } } extract($config); // Nuke the factory Factory::nuke(); // Set the profile $profile = (int) $profile; if (!is_numeric($profile)) { $profile = 1; } if (strtoupper($backupid) == '[DEFAULT]') { $db = JFactory::getDbo(); $query = $db->getQuery(true)->select('MAX(' . $db->qn('id') . ')')->from($db->qn('#__ak_stats')); try { $maxId = $db->setQuery($query)->loadResult(); } catch (Exception $e) { $maxId = 0; } $backupid = 'id' . ($maxId + 1); } elseif (empty($backupid)) { $backupid = null; } $session = JFactory::getSession(); $session->set('profile', $profile, 'akeeba'); Platform::getInstance()->load_configuration($profile); // Use the default description if none specified if (empty($description)) { JLoader::import('joomla.utilities.date'); $dateNow = new JDate(); /* $user = JFactory::getUser(); $userTZ = $user->getParam('timezone',0); $dateNow->setOffset($userTZ); */ $description = JText::_('BACKUP_DEFAULT_DESCRIPTION') . ' ' . $dateNow->format(JText::_('DATE_FORMAT_LC2'), true); } // Start the backup Factory::resetState(array('maxrun' => 0)); Factory::getTempFiles()->deleteTempFiles(); $tempVarsTag = AKEEBA_BACKUP_ORIGIN; $tempVarsTag .= empty(${$backupid}) ? '' : '.' . ${$backupid}; Factory::getFactoryStorage()->reset($tempVarsTag); Factory::loadState(AKEEBA_BACKUP_ORIGIN, $backupid); $kettenrad = Factory::getKettenrad(); $kettenrad->setBackupId($backupid); $options = array('description' => $description, 'comment' => $comment, 'tag' => AKEEBA_BACKUP_ORIGIN); $kettenrad->setup($options); // Setting up the engine $array = $kettenrad->tick(); // Initializes the init domain Factory::saveState(AKEEBA_BACKUP_ORIGIN, $backupid); $array = $kettenrad->getStatusArray(); if ($array['Error'] != '') { // A backup error had occurred. Why are we here?! $this->status = self::STATUS_ERROR; $this->encapsulation = self::ENCAPSULATION_RAW; return 'A backup error had occurred: ' . $array['Error']; } else { $statistics = Factory::getStatistics(); $array['BackupID'] = $statistics->getId(); $array['HasRun'] = 1; // Force the backup to go on. return $array; } }
/** * Creates a new dump part */ protected function getNextDumpPart() { // On database dump only mode we mustn't create part files! if (Factory::getEngineParamsProvider()->getScriptingParameter('db.saveasname', 'normal') == 'output') { return false; } // If the archiver is still processing, quit $finished = true; $configuration = Factory::getConfiguration(); $archiver = Factory::getArchiverEngine(); if ($configuration->get('volatile.engine.archiver.processingfile', false)) { return false; } // We have to add the dump file to the archive $this->closeFile(); Factory::getLog()->log(LogLevel::DEBUG, "Adding the SQL dump part to the archive"); $archiver->addFileRenamed($this->tempFile, $this->saveAsName); if ($this->getError()) { return false; } $finished = !$configuration->get('volatile.engine.archiver.processingfile', false); if (!$finished) { return false; } // Return if the file didn't finish getting added to the archive // Remove the old file Factory::getLog()->log(LogLevel::DEBUG, "Removing dump part's temporary file"); Factory::getTempFiles()->unregisterAndDeleteTempFile($this->tempFile, true); // Create the new dump part $this->partNumber++; $this->getBackupFilePaths($this->partNumber); $null = null; $this->writeline($null); return true; }
/** * Creates the ZIP file out of its pieces. * Official ZIP file format: http://www.pkware.com/appnote.txt * * @return void */ public function finalize() { // 1. Get size of central directory clearstatcache(); $cdOffset = @filesize($this->_dataFileName); $this->_totalDataSize += $cdOffset; $cdSize = @filesize($this->_ctrlDirFileName); // 2. Append Central Directory to data file and remove the CD temp file afterwards if (!is_null($this->fp)) { $this->_fclose($this->fp); } if (!is_null($this->cdfp)) { $this->_fclose($this->cdfp); } $this->fp = $this->_fopen($this->_dataFileName, "ab"); $this->cdfp = $this->_fopen($this->_ctrlDirFileName, "rb"); if ($this->fp === false) { $this->setError('Could not open ZIP data file ' . $this->_dataFileName . ' for reading'); return; } if ($this->cdfp === false) { // Already glued, return $this->_fclose($this->fp); $this->fp = null; $this->cdfp = null; return; } if (!$this->_useSplitZIP) { while (!feof($this->cdfp)) { $chunk = fread($this->cdfp, _AKEEBA_DIRECTORY_READ_CHUNK); $this->_fwrite($this->fp, $chunk); if ($this->getError()) { return; } } unset($chunk); $this->_fclose($this->cdfp); } else { // Calculate size of Central Directory + EOCD records $comment_length = function_exists('mb_strlen') ? mb_strlen($this->_comment, '8bit') : strlen($this->_comment); $total_cd_eocd_size = $cdSize + 22 + $comment_length; // Free space on the part clearstatcache(); $current_part_size = @filesize($this->_dataFileName); $free_space = $this->_fragmentSize - ($current_part_size === false ? 0 : $current_part_size); if ($free_space < $total_cd_eocd_size && $total_cd_eocd_size > 65536) { // Not enough space on archive for CD + EOCD, will go on separate part // Create new final part if (!$this->_createNewPart(true)) { // Die if we couldn't create the new part $this->setError('Could not create new ZIP part file ' . basename($this->_dataFileName)); return; } // Close the old data file $this->_fclose($this->fp); // Open data file for output $this->fp = @$this->_fopen($this->_dataFileName, "ab"); if ($this->fp === false) { $this->fp = null; $this->setError("Could not open archive file {$this->_dataFileName} for append!"); return; } // Write the CD record while (!feof($this->cdfp)) { $chunk = fread($this->cdfp, _AKEEBA_DIRECTORY_READ_CHUNK); $this->_fwrite($this->fp, $chunk); if ($this->getError()) { return; } } unset($chunk); $this->_fclose($this->cdfp); $this->cdfp = null; } else { // Glue the CD + EOCD on the same part if they fit, or anyway if they are less than 64Kb. // NOTE: WE *MUST NOT* CREATE FRAGMENTS SMALLER THAN 64Kb!!!! while (!feof($this->cdfp)) { $chunk = fread($this->cdfp, _AKEEBA_DIRECTORY_READ_CHUNK); $this->_fwrite($this->fp, $chunk); if ($this->getError()) { return; } } unset($chunk); $this->_fclose($this->cdfp); $this->cdfp = null; } } Factory::getTempFiles()->unregisterAndDeleteTempFile($this->_ctrlDirFileName); // 3. Write the rest of headers to the end of the ZIP file $this->_fclose($this->fp); $this->fp = null; clearstatcache(); $this->fp = $this->_fopen($this->_dataFileName, "ab"); if ($this->fp === false) { $this->setError('Could not open ' . $this->_dataFileName . ' for append'); return; } $this->_fwrite($this->fp, $this->_ctrlDirEnd); if ($this->getError()) { return; } if ($this->_useSplitZIP) { // Split ZIP files, enter relevant disk number information $this->_fwrite($this->fp, pack('v', $this->_totalFragments - 1)); /* Number of this disk. */ $this->_fwrite($this->fp, pack('v', $this->_totalFragments - 1)); /* Disk with central directory start. */ } else { // Non-split ZIP files, the disk numbers MUST be 0 $this->_fwrite($this->fp, pack('V', 0)); } $this->_fwrite($this->fp, pack('v', $this->_totalFileEntries)); /* Total # of entries "on this disk". */ $this->_fwrite($this->fp, pack('v', $this->_totalFileEntries)); /* Total # of entries overall. */ $this->_fwrite($this->fp, pack('V', $cdSize)); /* Size of central directory. */ $this->_fwrite($this->fp, pack('V', $cdOffset)); /* Offset to start of central dir. */ $sizeOfComment = $comment_length = function_exists('mb_strlen') ? mb_strlen($this->_comment, '8bit') : strlen($this->_comment); // 2.0.b2 -- Write a ZIP file comment $this->_fwrite($this->fp, pack('v', $sizeOfComment)); /* ZIP file comment length. */ $this->_fwrite($this->fp, $this->_comment); $this->_fclose($this->fp); // If Split ZIP and there is no .zip file, rename the last fragment to .ZIP if ($this->_useSplitZIP) { $extension = substr($this->_dataFileName, -3); if ($extension != '.zip') { Factory::getLog()->log(LogLevel::DEBUG, 'Renaming last ZIP part to .ZIP extension'); $newName = $this->_dataFileNameBase . '.zip'; if (!@rename($this->_dataFileName, $newName)) { $this->setError('Could not rename last ZIP part to .ZIP extension.'); return; } $this->_dataFileName = $newName; } } // If Split ZIP and only one fragment, change the signature if ($this->_useSplitZIP && $this->_totalFragments == 1) { $this->fp = $this->_fopen($this->_dataFileName, 'r+b'); $this->_fwrite($this->fp, "PK00"); } if (function_exists('chmod')) { @chmod($this->_dataFileName, 0755); } }