/** * Implements the _run() abstract method */ function _run() { if ($this->getState() == 'postrun') { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__ . " :: Already finished"); $this->setStep(''); $this->setSubstep(''); } else { $this->setState('running'); } // Try to step the archiver $archive = AEFactory::getArchiverEngine(); $ret = $archive->transformJPA($this->xformIndex, $this->offset); // Error propagation $this->propagateFromObject($archive); if ($ret !== false && $archive->getError() == '') { $this->offset = $ret['offset']; $this->xformIndex = $ret['index']; $this->setStep($ret['filename']); } // Check for completion if ($ret['done']) { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__ . ":: archive is initialized"); $this->setState('finished'); } // Calculate percentage $this->runningSize += $ret['chunkProcessed']; if ($ret['filesize'] > 0) { $this->progress = $this->runningSize / $ret['filesize']; } }
/** * Implements the _run() abstract method */ protected function _run() { if ($this->getState() == 'postrun') { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__ . " :: Already finished"); $this->setStep(''); $this->setSubstep(''); return; } else { $this->setState('running'); } // Load the version defines AEPlatform::getInstance()->load_version_defines(); $registry = AEFactory::getConfiguration(); // Write log file's header AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------"); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Akeeba Backup " . AKEEBA_VERSION . ' (' . AKEEBA_DATE . ')'); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Got backup?"); AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------"); // PHP configuration variables are tried to be logged only for debug and info log levels if ($registry->get('akeeba.basic.log_level') >= _AE_LOG_INFO) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "--- System Information ---"); AEUtilLogger::WriteLog(_AE_LOG_INFO, "PHP Version :" . PHP_VERSION); AEUtilLogger::WriteLog(_AE_LOG_INFO, "PHP OS :" . PHP_OS); AEUtilLogger::WriteLog(_AE_LOG_INFO, "PHP SAPI :" . PHP_SAPI); if (function_exists('php_uname')) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "OS Version :" . php_uname('s')); } $db = AEFactory::getDatabase(); AEUtilLogger::WriteLog(_AE_LOG_INFO, "DB Version :" . $db->getVersion()); if (isset($_SERVER['SERVER_SOFTWARE'])) { $server = $_SERVER['SERVER_SOFTWARE']; } else { if ($sf = getenv('SERVER_SOFTWARE')) { $server = $sf; } else { $server = 'n/a'; } } AEUtilLogger::WriteLog(_AE_LOG_INFO, "Web Server :" . $server); $platform = 'Unknown platform'; $version = '(unknown version)'; $platformData = AEPlatform::getInstance()->getPlatformVersion(); AEUtilLogger::WriteLog(_AE_LOG_INFO, $platformData['name'] . " version :" . $platformData['version']); if (isset($_SERVER['HTTP_USER_AGENT'])) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "User agent :" . phpversion() <= "4.2.1" ? getenv("HTTP_USER_AGENT") : $_SERVER['HTTP_USER_AGENT']); } AEUtilLogger::WriteLog(_AE_LOG_INFO, "Safe mode :" . ini_get("safe_mode")); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Display errors :" . ini_get("display_errors")); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Error reporting :" . self::error2string()); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Error display :" . self::errordisplay()); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Disabled functions :" . ini_get("disable_functions")); AEUtilLogger::WriteLog(_AE_LOG_INFO, "open_basedir restr.:" . ini_get('open_basedir')); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Max. exec. time :" . ini_get("max_execution_time")); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Memory limit :" . ini_get("memory_limit")); if (function_exists("memory_get_usage")) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Current mem. usage :" . memory_get_usage()); } if (function_exists("gzcompress")) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "GZIP Compression : available (good)"); } else { AEUtilLogger::WriteLog(_AE_LOG_INFO, "GZIP Compression : n/a (no compression)"); } AEPlatform::getInstance()->log_platform_special_directories(); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Output directory :" . $registry->get('akeeba.basic.output_directory')); AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------"); } // Quirks reporting $quirks = AEUtilQuirks::get_quirks(true); if (!empty($quirks)) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Akeeba Backup has detected the following potential problems:"); foreach ($quirks as $q) { AEUtilLogger::WriteLog(_AE_LOG_INFO, '- ' . $q['code'] . ' ' . $q['description'] . ' (' . $q['severity'] . ')'); } AEUtilLogger::WriteLog(_AE_LOG_INFO, "You probably do not have to worry about them, but you should be aware of them."); AEUtilLogger::WriteLog(_AE_LOG_INFO, "--------------------------------------------------------------------------------"); } if (!version_compare(PHP_VERSION, '5.3.0', 'ge')) { AEUtilLogger::WriteLog(_AE_LOG_WARNING, "You are using an outdated version of PHP. Akeeba Engine may not work properly. Please upgrade to PHP 5.3 or later."); } // Report profile ID $profile_id = AEPlatform::getInstance()->get_active_profile(); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Loaded profile #{$profile_id}"); // Get archive name AEUtilFilesystem::get_archive_name($relativeArchiveName, $absoluteArchiveName); // ==== Stats initialisation === $origin = AEPlatform::getInstance()->get_backup_origin(); // Get backup origin $profile_id = AEPlatform::getInstance()->get_active_profile(); // Get active profile $registry = AEFactory::getConfiguration(); $backupType = $registry->get('akeeba.basic.backup_type'); AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Backup type is now set to '" . $backupType . "'"); // Substitute "variables" in the archive name $description = AEUtilFilesystem::replace_archive_name_variables($this->description); $comment = AEUtilFilesystem::replace_archive_name_variables($this->comment); if ($registry->get('volatile.writer.store_on_server', true)) { // Archive files are stored on our server $stat_relativeArchiveName = $relativeArchiveName; $stat_absoluteArchiveName = $absoluteArchiveName; } else { // Archive files are not stored on our server (FTP backup, cloud backup, sent by email, etc) $stat_relativeArchiveName = ''; $stat_absoluteArchiveName = ''; } $kettenrad = AEFactory::getKettenrad(); $temp = array('description' => $description, 'comment' => $comment, 'backupstart' => AEPlatform::getInstance()->get_timestamp_database(), 'status' => 'run', 'origin' => $origin, 'type' => $backupType, 'profile_id' => $profile_id, 'archivename' => $stat_relativeArchiveName, 'absolute_path' => $stat_absoluteArchiveName, 'multipart' => 0, 'filesexist' => 1, 'tag' => $kettenrad->getTag()); // Save the entry $statistics = AEFactory::getStatistics(); $statistics->setStatistics($temp); if ($statistics->getError()) { $this->setError($statistics->getError()); return; } $statistics->release_multipart_lock(); // Initialize the archive. if (AEUtilScripting::getScriptingParameter('core.createarchive', true)) { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Expanded archive file name: " . $absoluteArchiveName); AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Initializing archiver engine"); $archiver = AEFactory::getArchiverEngine(); $archiver->initialize($absoluteArchiveName); $archiver->setComment($comment); // Add the comment to the archive itself. $archiver->propagateToObject($this); if ($this->getError()) { return; } } $this->setState('postrun'); }
/** * Implements the _finalize() abstract method * */ protected function _finalize() { $this->setState('finished'); // If we are in db backup mode, don't create a databases.ini $configuration = AEFactory::getConfiguration(); if (!AEUtilScripting::getScriptingParameter('db.databasesini', 1)) { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__ . " :: Skipping databases.ini"); } else { // Create the databases.ini contents if ($this->installerSettings->databasesini) { $this->createDatabasesINI(); AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__ . " :: Creating databases.ini"); // Create a new string $databasesINI = $this->databases_ini; // BEGIN FIX 1.2 Stable -- databases.ini isn't written on disk AEUtilLogger::WriteLog(_AE_LOG_DEBUG, __CLASS__ . " :: Writing databases.ini contents"); $archiver = AEFactory::getArchiverEngine(); $virtualLocation = AEUtilScripting::getScriptingParameter('db.saveasname', 'normal') == 'short' ? '' : $this->installerSettings->sqlroot; $archiver->addVirtualFile('databases.ini', $virtualLocation, $databasesINI); // Error propagation $this->propagateFromObject($archiver); if ($this->getError()) { return false; } } } // On alldb mode, we have to finalize the archive as well if (AEUtilScripting::getScriptingParameter('db.finalizearchive', 0)) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Finalizing database dump archive"); $archiver = AEFactory::getArchiverEngine(); $archiver->finalize(); // Error propagation $this->propagateFromObject($archiver); if ($this->getError()) { return false; } } // In CLI mode we'll also close the database connection if (defined('AKEEBACLI')) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Closing the database connection to the main database"); $db = AEFactory::unsetDatabase(); } return true; }
/** * Try to pack some files in the $file_list, restraining ourselves not to reach the max * number of files or max fragment size while doing so. If this process is over and we are * left without any more files, reset $done_scanning to false in order to instruct the class * to scan for more files. * * @return bool True if there were files packed, false otherwise (empty filelist) */ private function pack_files() { // Get a reference to the archiver and the timer classes $archiver = AEFactory::getArchiverEngine(); $timer = AEFactory::getTimer(); $configuration = AEFactory::getConfiguration(); // If post-processing after part creation is enabled, make sure we do post-process each part before moving on if ($configuration->get('engine.postproc.common.after_part', 0)) { if (!empty($archiver->finishedPart)) { $filename = array_shift($archiver->finishedPart); AEUtilLogger::WriteLog(_AE_LOG_INFO, 'Preparing to post process ' . basename($filename)); $post_proc = AEFactory::getPostprocEngine(); $result = $post_proc->processPart($filename); $this->propagateFromObject($post_proc); if ($result === false) { $this->setWarning('Failed to process file ' . basename($filename)); } else { AEUtilLogger::WriteLog(_AE_LOG_INFO, 'Successfully processed file ' . basename($filename)); } // Should we delete the file afterwards? if ($configuration->get('engine.postproc.common.delete_after', false) && $post_proc->allow_deletes && $result !== false) { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, 'Deleting already processed file ' . basename($filename)); AEPlatform::getInstance()->unlink($filename); } if ($post_proc->break_after && $result !== false) { $configuration->set('volatile.breakflag', true); return true; } // This is required to let the backup continue even after a post-proc failure $this->resetErrors(); $this->setState('running'); } } // If the archiver has work to do, make sure it finished up before continuing if ($configuration->get('volatile.engine.archiver.processingfile', false)) { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Continuing file packing from previous step"); $result = $archiver->addFile('', '', ''); $this->propagateFromObject($archiver); if ($this->getError()) { return false; } // If that was the last step, mark a file done if (!$configuration->get('volatile.engine.archiver.processingfile', false)) { $this->progressMarkFileDone(); } } // Did it finish, or does it have more work to do? if ($configuration->get('volatile.engine.archiver.processingfile', false)) { // More work to do. Let's just tell our parent that we finished up successfully. return true; } // Normal file backup loop; we keep on processing the file list, packing files as we go. if (count($this->file_list) == 0) { // No files left to pack -- This should never happen! We catch this condition at the end of this method! $this->done_scanning = false; $this->progressMarkFolderDone(); return false; } else { AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Packing files"); $packedSize = 0; $numberOfFiles = 0; list($usec, $sec) = explode(" ", microtime()); $opStartTime = (double) $usec + (double) $sec; while (count($this->file_list) > 0) { $file = @array_shift($this->file_list); $size = 0; if (file_exists($file)) { $size = @filesize($file); } // Anticipatory file size algorithm if ($numberOfFiles > 0 && $size > AELargeFileThreshold) { if (!AEFactory::getConfiguration()->get('akeeba.tuning.nobreak.beforelargefile', 0)) { // If the file is bigger than the big file threshold, break the step // to avoid potential timeouts $this->setBreakFlag(); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Breaking step _before_ large file: " . $file . " - size: " . $size); // Push the file back to the list. array_unshift($this->file_list, $file); // Mark that we are not done packing files $this->done_scanning = true; return true; } } // Proactive potential timeout detection // Rough estimation of packing speed in bytes per second list($usec, $sec) = explode(" ", microtime()); $opEndTime = (double) $usec + (double) $sec; if ($opEndTime - $opStartTime == 0) { $_packSpeed = 0; } else { $_packSpeed = $packedSize / ($opEndTime - $opStartTime); } // Estimate required time to pack next file. If it's the first file of this operation, // do not impose any limitations. $_reqTime = $_packSpeed - 0.01 <= 0 ? 0 : $size / $_packSpeed; // Do we have enough time? if ($timer->getTimeLeft() < $_reqTime) { if (!AEFactory::getConfiguration()->get('akeeba.tuning.nobreak.proactive', 0)) { array_unshift($this->file_list, $file); AEUtilLogger::WriteLog(_AE_LOG_INFO, "Proactive step break - file: " . $file . " - size: " . $size . " - req. time " . sprintf('%2.2f', $_reqTime)); $this->setBreakFlag(); $this->done_scanning = true; return true; } } $packedSize += $size; $numberOfFiles++; $ret = $archiver->addFile($file, $this->remove_path_prefix, $this->path_prefix); // If no more processing steps are required, mark a done file if (!$configuration->get('volatile.engine.archiver.processingfile', false)) { $this->progressMarkFileDone(); } // Error propagation $this->propagateFromObject($archiver); if ($this->getError()) { return false; } // If this was the first file of the fragment and it exceeded the fragment's capacity, // break the step. Continuing with more operations after packing such a big file is // increasing the risk to hit a timeout. if ($packedSize > AELargeFileThreshold && $numberOfFiles == 1) { if (!AEFactory::getConfiguration()->get('akeeba.tuning.nobreak.afterlargefile', 0)) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Breaking step *after* large file: " . $file . " - size: " . $size); $this->setBreakFlag(); return true; } } // If we have to continue processing the file, break the file packing loop forcibly if ($configuration->get('volatile.engine.archiver.processingfile', false)) { return true; } } $this->done_scanning = count($this->file_list) > 0; if (!$this->done_scanning) { $this->progressMarkFolderDone(); } return true; } }
/** * Creates a new dump part */ protected function getNextDumpPart() { // On database dump only mode we mustn't create part files! if (AEUtilScripting::getScriptingParameter('db.saveasname', 'normal') == 'output') { return false; } // If the archiver is still processing, quit $finished = true; $configuration = AEFactory::getConfiguration(); $archiver = AEFactory::getArchiverEngine(); if ($configuration->get('volatile.engine.archiver.processingfile', false)) { return false; } // We have to add the dump file to the archive $this->closeFile(); AEUtilLogger::WriteLog(_AE_LOG_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 AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Removing dump part's temporary file"); AEUtilTempfiles::unregisterAndDeleteTempFile($this->tempFile, true); // Create the new dump part $this->partNumber++; $this->getBackupFilePaths($this->partNumber); $null = null; $this->writeline($null); return true; }
/** * Steps the files scanning of the current directory * * @return boolean True on success, false on fatal error */ private function scanFiles() { $engine = AEFactory::getScanEngine(); list($root, $translated_root, $dir) = $this->getCleanDirectoryComponents(); // Get a filters instance $filters = AEFactory::getFilters(); if (is_null($this->getFiles_position)) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Scanning files of " . $this->current_directory); $this->processed_files_counter = 0; } else { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Resuming scanning files of " . $this->current_directory); } // Get file listing $fileList = $engine->getFiles($this->current_directory, $this->getFiles_position); // Error propagation $this->propagateFromObject($engine); // If the list contains "too many" items, please break this step! if (AEFactory::getConfiguration()->get('volatile.breakflag', false)) { // Log the step break decision, for debugging reasons AEUtilLogger::WriteLog(_AE_LOG_INFO, "Large directory " . $this->current_directory . " while scanning for files; I will resume scanning in next step."); // Return immediately, marking that we are not done yet! return true; } // Error control if ($this->getError()) { return false; } // Do I have an unreadable directory? if ($fileList === false) { $this->setWarning('Unreadable directory ' . $this->current_directory); $this->done_file_scanning = true; } else { if (is_array($fileList) && !empty($fileList)) { // Add required trailing slash to $dir if (!empty($dir)) { $dir .= '/'; } // Scan all directory entries foreach ($fileList as $fileName) { $check = $dir . basename($fileName); if (_AKEEBA_IS_WINDOWS) { $check = AEUtilFilesystem::TranslateWinPath($check); } // Do I need this? $dir contains a path relative to the root anyway... $check = ltrim(str_replace($translated_root, '', $check), '/'); $byFilter = ''; $skipThisFile = $filters->isFilteredExtended($check, $root, 'file', 'all', $byFilter); if ($skipThisFile) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Skipping file {$fileName} (filter: {$byFilter})"); } else { $this->file_list[] = $fileName; $this->processed_files_counter++; $this->progressAddFile(); } } } } // If the scanner engine nullified the next position we are done // scanning for files if (is_null($this->getFiles_position)) { $this->done_file_scanning = true; } // If the directory was genuinely empty we will have to add an empty // directory entry in the archive, otherwise this directory will never // be restored. if ($this->done_file_scanning && $this->processed_files_counter == 0) { AEUtilLogger::WriteLog(_AE_LOG_INFO, "Empty directory " . $this->current_directory); $archiver = AEFactory::getArchiverEngine(); if ($this->current_directory != $this->remove_path_prefix) { $archiver->addFile($this->current_directory, $this->remove_path_prefix, $this->path_prefix); } // Error propagation $this->propagateFromObject($archiver); // Check for errors if ($this->getError()) { return false; } unset($archiver); } return true; }
/** * Returns the relative and absolute path to the archive, if defined * * @param string $relative The relative path * @param string $absolute The absolute path */ public static function get_archive_name(&$relative, &$absolute) { static $relative_path = null; static $absolute_path = null; if (is_null($relative_path) || is_null($absolute_path)) { $registry = AEFactory::getConfiguration(); // Import volatile scripting keys to the registry AEUtilScripting::importScriptingToRegistry(); // Determine the extension $force_extension = AEUtilScripting::getScriptingParameter('core.forceextension', null); if (is_null($force_extension)) { $archiver = AEFactory::getArchiverEngine(); $extension = $archiver->getExtension(); } else { $extension = $force_extension; } // Get the template name $templateName = $registry->get('akeeba.basic.archive_name'); AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Archive template name: {$templateName}"); // Parse all tags $templateName = self::replace_archive_name_variables($templateName); AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Expanded template name: {$templateName}"); $ds = DIRECTORY_SEPARATOR; $relative_path = $templateName . $extension; $absolute_path = AEUtilFilesystem::TranslateWinPath($registry->get('akeeba.basic.output_directory') . $ds . $relative_path); } $relative = $relative_path; $absolute = $absolute_path; }