zZzzZ.
home2
/
zrzvbdry
/
wiredsave.com
/
wp-content
/
plugins
/
backup
/
src
/
JetBackup
/
Cron
New Folder
Editing: Cron.php
Save
Cancel
<?php namespace JetBackup\Cron; if (!defined( '__JETBACKUP__')) die('Direct access is not allowed'); use JetBackup\BackupJob\BackupJob; use JetBackup\Cache\CacheHandler; use JetBackup\Cron\Task\Backup; use JetBackup\Cron\Task\DownloadBackupLog; use JetBackup\Cron\Task\RetentionCleanup; use JetBackup\Cron\Task\Download; use JetBackup\Cron\Task\Export; use JetBackup\Cron\Task\Extract; use JetBackup\Cron\Task\Reindex; use JetBackup\Cron\Task\PreRestore; use JetBackup\Cron\Task\System; use JetBackup\Exception\CronException; use JetBackup\Exception\DBException; use JetBackup\Exception\IOException; use JetBackup\Exception\JBException; use JetBackup\Exception\LogException; use JetBackup\Exception\QueueException; use JetBackup\Exception\ReindexException; use JetBackup\Factory; use JetBackup\IO\Lock; use JetBackup\JetBackup; use JetBackup\Log\FileLogger; use JetBackup\Log\LogController; use JetBackup\Log\Logger; use JetBackup\Log\StdLogger; use JetBackup\Queue\Queue; use JetBackup\Queue\QueueItem; use JetBackup\Wordpress\Helper; use SleekDB\Exceptions\InvalidArgumentException; use WP_REST_Response; class Cron { const LOCK_FILE = 'cron.lock'; const LAST_FILE = 'cron.last'; private const CRON_LOG_FILE = 'cron.log'; private LogController $_logController; private string $_data_dir; /** @var QueueItem|null Current queue item being processed (for fatal error handling) */ private static ?QueueItem $_currentQueueItem = null; /** * @throws CronException * @throws LogException */ private function __construct() { if(!$this->canRun()) throw new CronException('Cron system disabled, you can only execute via wp-cli'); $this->_data_dir = Factory::getLocations()->getDataDir(); $this->_setLastRun(); if (!Lock::LockFile($this->_data_dir . JetBackup::SEP . self::LOCK_FILE)) throw new CronException('Cron is already running', 501); $logFile = Factory::getLocations()->getLogsDir() . JetBackup::SEP . self::CRON_LOG_FILE; $level = Logger::LOG_LEVEL_ERROR | Logger::LOG_LEVEL_WARNING | Logger::LOG_LEVEL_NOTICE | Logger::LOG_LEVEL_MESSAGE; if(Factory::getSettingsLogging()->isDebugEnabled()) $level |= Logger::LOG_LEVEL_DEBUG; $this->_logController = new LogController(); $this->_logController->addLogger(new FileLogger($logFile, $level)); if(Cron::inDebug() || Helper::isWPCli()) $this->_logController->addLogger(new StdLogger($level)); } /** * @throws \SleekDB\Exceptions\IOException * @throws IOException * @throws InvalidArgumentException * @throws QueueException|DBException|JBException */ public static function main() { // Register shutdown handler to catch fatal errors (like max_execution_time) register_shutdown_function([self::class, 'handleFatalError']); CacheHandler::pre(); $cron = new Cron(); $cron->execute(); CacheHandler::post(); } /** * Shutdown handler to catch fatal errors that cannot be caught with try/catch. * This ensures queue items are not left in a corrupted state when PHP dies. */ public static function handleFatalError(): void { $error = error_get_last(); // Only handle fatal errors if ($error === null || !in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE])) { return; } $message = sprintf( "[FATAL ERROR] %s in %s on line %d", $error['message'], $error['file'], $error['line'] ); try { $logFile = Factory::getLocations()->getLogsDir() . JetBackup::SEP . self::CRON_LOG_FILE; FileLogger::emergency($logFile, $message); // If we have a current queue item, log that it will be retried if (self::$_currentQueueItem !== null) { $itemId = self::$_currentQueueItem->getId(); if ($itemId) { FileLogger::emergency($logFile, "Queue item {$itemId} will be retried on next cron run"); } } } catch (\Throwable $e) { // Logging failed, ignore } } /** * @return void * @throws IOException * @throws InvalidArgumentException * @throws QueueException * @throws \SleekDB\Exceptions\IOException|DBException|JBException */ public function execute() { try { $this->_executeNextQueue(); } catch(\TypeError|\Error $e) { $message = sprintf("Cron exited due to an fatal error. Error: %s in %s on line %s", $e->getMessage(), $e->getFile(), $e->getLine()); $this->_logController->logError($message); $this->_logController->logError($e->getTraceAsString()); die($message . PHP_EOL . $e->getTraceAsString()); } // Add all scheduled backup jobs to queue BackupJob::addToQueueScheduled(); // Add system tasks to queue System::addToQueue(); } /** * @return void * @throws InvalidArgumentException * @throws DBException * @throws \SleekDB\Exceptions\IOException|JBException */ private function _executeNextQueue():void { if(!($item = Queue::next())) return; // Track current item for fatal error handling self::$_currentQueueItem = $item; $this->getLogController()->logMessage("Got next queue item (ID: {$item->getId()}, Type: {$item->getType()})"); $task = null; try { switch ($item->getType()) { case Queue::QUEUE_TYPE_BACKUP: $task = new Backup(); break; case Queue::QUEUE_TYPE_DOWNLOAD: $task = new Download(); break; case Queue::QUEUE_TYPE_DOWNLOAD_BACKUP_LOG: $task = new DownloadBackupLog(); break; case Queue::QUEUE_TYPE_EXTRACT: $task = new Extract(); break; case Queue::QUEUE_TYPE_REINDEX: $task = new Reindex(); break; case Queue::QUEUE_TYPE_RETENTION_CLEANUP: $task = new RetentionCleanup(); break; case Queue::QUEUE_TYPE_SYSTEM: $task = new System(); break; case Queue::QUEUE_TYPE_EXPORT: $task = new Export(); break; case Queue::QUEUE_TYPE_RESTORE: $task = new PreRestore(); break; default: throw new CronException('Could not find queue type'); } $task->setQueueItem($item); $task->setCronLogController($this->getLogController()); if(Helper::isCLI()) $task->setExecutionTimeLimit(0); $task->setExecutionTimeDie(true); $task->execute(); // Clear current item on successful completion self::$_currentQueueItem = null; } catch (\Exception $e) { $message = "Cron exited due to an uncaught " . get_class($e) . ". Error: " . $e->getMessage(); $this->_logController->logError($message); // Also log to task's log controller (visible in GUI job log) if ($task !== null) { try { $task->getLogController()->logError($message); } catch (\Throwable $logError) { // Ignore logging failures } } $item->updateStatus(Queue::STATUS_NEVER_FINISHED); $progress = $item->getProgress(); $progress->setMessage($message); $backup_job = null; if ($item->getType() == Queue::QUEUE_TYPE_BACKUP) { // Prevent infinite loop with a failed backup destination // It will fail before getting to the backup job, so the job meta will never update $instance = $item->getItemData(); $backup_job = new BackupJob($instance->getJobId()); $backup_job->setLastRun(time()); $backup_job->calculateNextRun(); } // Save operation is return void so have to try-catch them try { // Save queue item $item->save(); } catch (\Exception $saveException) { $this->_logController->logError("Failed to save Queue item: " . $saveException->getMessage()); } if ($backup_job !== null) { try { // Save the backup job $backup_job->save(); } catch (\Exception $saveException) { $this->_logController->logError("Failed to save Backup Job: " . $saveException->getMessage()); } } // Clear current item after exception handling self::$_currentQueueItem = null; } } public function getLogController(): LogController { return $this->_logController; } private function _setLastRun() { if (!Helper::isCLI()) return; touch($this->_data_dir . JetBackup::SEP . self::LAST_FILE); } private function canRun(): bool { $_cron_disabled = !Factory::getSettingsAutomation()->isCronsEnabled(); if ($_cron_disabled && !Helper::isCLI()) return false; // cannot run // Disable the script timeout for CLI mode if (Helper::isCLI()) set_time_limit(0); return true; } public static function inDebug(): bool { return self::_argExists('debug'); } public function __destruct() { Lock::UnlockFile($this->_data_dir . JetBackup::SEP . self::LOCK_FILE); } private static function _argExists($arg): bool { global $argv; return isset($argv) && in_array('--'.$arg, $argv); } }