Пример #1
0
 /**
  * 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);
 }
Пример #2
0
 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;
     }
 }
Пример #3
0
 /**
  * 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;
 }
Пример #4
0
 /**
  * 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);
     }
 }
Пример #5
0
 /**
  * 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();
     }
 }
Пример #6
0
 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);
         }
     }
 }
Пример #7
0
 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;
     }
 }
Пример #8
0
 /**
  * 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;
 }
Пример #9
0
 /**
  * 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);
     }
 }