Execute cronjobs as a System user
authorJoshua Rüsweg <josh@bastelstu.be>
Wed, 21 Jun 2017 20:10:04 +0000 (22:10 +0200)
committerJoshua Rüsweg <josh@bastelstu.be>
Wed, 21 Jun 2017 20:10:04 +0000 (22:10 +0200)
wcfsetup/install/files/lib/data/cronjob/CronjobAction.class.php
wcfsetup/install/files/lib/system/cli/command/CronjobCLICommand.class.php

index beb4276969548ffac459588cc2c04c541c4bd451..2fe27817f5da5f34d25433303a60905a20a7dfc2 100644 (file)
@@ -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;
index 5b78d316e474ee78b3102720ac6d6d4a92b2f1a4..035485b407322a00e50c8a84d00df57175e5b186 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 namespace wcf\system\cli\command;
+use wcf\data\user\User;
 use wcf\system\cronjob\CronjobScheduler;
+use wcf\system\WCF;
 use Zend\Console\Exception\RuntimeException as ArgvException;
 use Zend\Console\Getopt as ArgvParser;
 
@@ -40,7 +42,18 @@ class CronjobCLICommand implements IArgumentedCLICommand {
                        throw new ArgvException('', $this->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);
+               }
        }
        
        /**