From e238e424c32af42111917051efb4fa5fdede0742 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joshua=20R=C3=BCsweg?= Date: Wed, 21 Jun 2017 22:10:04 +0200 Subject: [PATCH] Execute cronjobs as a System user --- .../lib/data/cronjob/CronjobAction.class.php | 155 ++++++++++-------- .../cli/command/CronjobCLICommand.class.php | 15 +- 2 files changed, 97 insertions(+), 73 deletions(-) diff --git a/wcfsetup/install/files/lib/data/cronjob/CronjobAction.class.php b/wcfsetup/install/files/lib/data/cronjob/CronjobAction.class.php index beb4276969..2fe27817f5 100644 --- a/wcfsetup/install/files/lib/data/cronjob/CronjobAction.class.php +++ b/wcfsetup/install/files/lib/data/cronjob/CronjobAction.class.php @@ -113,87 +113,98 @@ class CronjobAction extends AbstractDatabaseObjectAction implements IToggleActio public function execute() { $return = array(); - foreach ($this->objects as $key => $cronjob) { - // mark them as pending - $cronjob->update(array('state' => Cronjob::PENDING)); - } + // switch session owner to 'system' during execution of cronjobs + $actualUser = WCF::getUser(); + WCF::getSession()->changeUser(new User(null, array('userID' => 0, 'username' => 'System')), true); + WCF::getSession()->disableUpdate(); - foreach ($this->objects as $cronjob) { - // it now time for executing - $cronjob->update(array('state' => Cronjob::EXECUTING)); - $className = $cronjob->className; - $executable = new $className(); - - // execute cronjob - $exception = null; - try { - $executable->execute(new Cronjob($cronjob->cronjobID)); + try { + foreach ($this->objects as $key => $cronjob) { + // mark them as pending + $cronjob->update(array('state' => Cronjob::PENDING)); } - catch (\Exception $exception) { } - - CronjobLogEditor::create(array( - 'cronjobID' => $cronjob->cronjobID, - 'execTime' => TIME_NOW, - 'success' => ($exception ? 0 : 1), - 'error' => ($exception ? $exception->getMessage() : '') - )); - - // calculate next exec-time - $nextExec = $cronjob->getNextExec(); - $data = array( - 'lastExec' => TIME_NOW, - 'nextExec' => $nextExec, - 'afterNextExec' => $cronjob->getNextExec(($nextExec + 120)) - ); - // cronjob failed - if ($exception) { - if ($cronjob->failCount < Cronjob::MAX_FAIL_COUNT) { - $data['failCount'] = $cronjob->failCount + 1; - } + foreach ($this->objects as $cronjob) { + // it now time for executing + $cronjob->update(array('state' => Cronjob::EXECUTING)); + $className = $cronjob->className; + $executable = new $className(); - // cronjob failed too often: disable it - if ($cronjob->failCount + 1 == Cronjob::MAX_FAIL_COUNT) { - $data['isDisabled'] = 1; + // execute cronjob + $exception = null; + try { + $executable->execute(new Cronjob($cronjob->cronjobID)); } - } - // if no error: reset fail counter - else { - $data['failCount'] = 0; + catch (\Exception $exception) { } + + CronjobLogEditor::create(array( + 'cronjobID' => $cronjob->cronjobID, + 'execTime' => TIME_NOW, + 'success' => ($exception ? 0 : 1), + 'error' => ($exception ? $exception->getMessage() : '') + )); + + // calculate next exec-time + $nextExec = $cronjob->getNextExec(); + $data = array( + 'lastExec' => TIME_NOW, + 'nextExec' => $nextExec, + 'afterNextExec' => $cronjob->getNextExec(($nextExec + 120)) + ); - // if cronjob has been disabled because of too many - // failed executions, enable it again - if ($cronjob->failCount == Cronjob::MAX_FAIL_COUNT && $cronjob->isDisabled) { - $data['isDisabled'] = 0; + // cronjob failed + if ($exception) { + if ($cronjob->failCount < Cronjob::MAX_FAIL_COUNT) { + $data['failCount'] = $cronjob->failCount + 1; + } + + // cronjob failed too often: disable it + if ($cronjob->failCount + 1 == Cronjob::MAX_FAIL_COUNT) { + $data['isDisabled'] = 1; + } } - } - - $cronjob->update($data); - - // build the return value - if ($exception === null && !$cronjob->isDisabled) { - $dateTime = DateUtil::getDateTimeByTimestamp($nextExec); - $return[$cronjob->cronjobID] = array( - 'time' => $nextExec, - 'formatted' => str_replace( - '%time%', - DateUtil::format($dateTime, DateUtil::TIME_FORMAT), - str_replace( - '%date%', - DateUtil::format($dateTime, DateUtil::DATE_FORMAT), - WCF::getLanguage()->get('wcf.date.dateTimeFormat') + // if no error: reset fail counter + else { + $data['failCount'] = 0; + + // if cronjob has been disabled because of too many + // failed executions, enable it again + if ($cronjob->failCount == Cronjob::MAX_FAIL_COUNT && $cronjob->isDisabled) { + $data['isDisabled'] = 0; + } + } + + $cronjob->update($data); + + // build the return value + if ($exception === null && !$cronjob->isDisabled) { + $dateTime = DateUtil::getDateTimeByTimestamp($nextExec); + $return[$cronjob->cronjobID] = array( + 'time' => $nextExec, + 'formatted' => str_replace( + '%time%', + DateUtil::format($dateTime, DateUtil::TIME_FORMAT), + str_replace( + '%date%', + DateUtil::format($dateTime, DateUtil::DATE_FORMAT), + WCF::getLanguage()->get('wcf.date.dateTimeFormat') + ) ) - ) - ); - } - - // we are finished - $cronjob->update(array('state' => Cronjob::READY)); - - // throw exception again to show error message - if ($exception) { - throw $exception; + ); + } + + // we are finished + $cronjob->update(array('state' => Cronjob::READY)); + + // throw exception again to show error message + if ($exception) { + throw $exception; + } } + } + finally { + // switch session back to the actual user + WCF::getSession()->changeUser($actualUser, true); } return $return; diff --git a/wcfsetup/install/files/lib/system/cli/command/CronjobCLICommand.class.php b/wcfsetup/install/files/lib/system/cli/command/CronjobCLICommand.class.php index 5b78d316e4..035485b407 100644 --- a/wcfsetup/install/files/lib/system/cli/command/CronjobCLICommand.class.php +++ b/wcfsetup/install/files/lib/system/cli/command/CronjobCLICommand.class.php @@ -1,6 +1,8 @@ getUsage()); } - CronjobScheduler::getInstance()->executeCronjobs(); + // switch session owner to 'system' during execution of cronjobs + $actualUser = WCF::getUser(); + WCF::getSession()->changeUser(new User(null, array('userID' => 0, 'username' => 'System')), true); + WCF::getSession()->disableUpdate(); + + try { + CronjobScheduler::getInstance()->executeCronjobs(); + } + finally { + // switch session back to the actual user + WCF::getSession()->changeUser($actualUser, true); + } } /** -- 2.20.1