job = $job; $this->config = $config + [ 'recipients' => null, 'mailer' => null, 'maxRuntime' => null, 'smtpHost' => null, 'smtpPort' => null, 'smtpUsername' => null, 'smtpPassword' => null, 'smtpSender' => null, 'smtpSenderName' => null, 'smtpSecurity' => null, 'runAs' => null, 'environment' => null, 'runOnHost' => null, 'output' => null, 'output_stdout' => null, 'output_stderr' => null, 'dateFormat' => null, 'enabled' => null, 'haltDir' => null, 'debug' => null, ]; $this->config['output_stdout'] = $this->config['output_stdout'] === null ? $this->config['output'] : $this->config['output_stdout']; $this->config['output_stderr'] = $this->config['output_stderr'] === null ? $this->config['output'] : $this->config['output_stderr']; $this->helper = $helper ?: new Helper(); $this->tmpDir = $this->helper->getTempDir(); } public function run() { $lockFile = $this->getLockFile(); try { $this->checkMaxRuntime($lockFile); } catch (Exception $e) { $this->log('ERROR: ' . $e->getMessage(), 'stderr'); $this->mail($e->getMessage()); return; } if (!$this->shouldRun()) { return; } $lockAcquired = false; try { $this->helper->acquireLock($lockFile); $lockAcquired = true; if (isset($this->config['closure'])) { $this->runFunction(); } else { $this->runFile(); } } catch (InfoException $e) { $this->log('INFO: ' . $e->getMessage(), 'stderr'); } catch (Exception $e) { $this->log('ERROR: ' . $e->getMessage(), 'stderr'); $this->mail($e->getMessage()); } if ($lockAcquired) { $this->helper->releaseLock($lockFile); // remove log file if empty $logfile = $this->getLogfile(); if (is_file($logfile) && filesize($logfile) <= 0) { unlink($logfile); } } } /** * @return array */ public function getConfig() { return $this->config; } /** * @param string $lockFile * * @throws Exception */ protected function checkMaxRuntime($lockFile) { $maxRuntime = $this->config['maxRuntime']; if ($maxRuntime === null) { return; } if ($this->helper->getPlatform() === Helper::WINDOWS) { throw new Exception('"maxRuntime" is not supported on Windows'); } $runtime = $this->helper->getLockLifetime($lockFile); if ($runtime < $maxRuntime) { return; } throw new Exception("MaxRuntime of $maxRuntime secs exceeded! Current runtime: $runtime secs"); } /** * @param string $message */ protected function mail($message) { if (empty($this->config['recipients'])) { return; } $this->helper->sendMail( $this->job, $this->config, $message ); } /** * @param string $output * @return string */ protected function getLogfile($output = 'stdout') { $logfile = $this->config['output_'.$output]; if ($logfile === null) { return false; } $logs = dirname($logfile); if (!file_exists($logs)) { mkdir($logs, 0755, true); } return $logfile; } /** * @return string */ protected function getLockFile() { $tmp = $this->tmpDir; $job = $this->helper->escape($this->job); if (!empty($this->config['environment'])) { $env = $this->helper->escape($this->config['environment']); return "$tmp/$env-$job.lck"; } else { return "$tmp/$job.lck"; } } /** * @return bool */ protected function shouldRun() { if (!$this->config['enabled']) { return false; } if (($haltDir = $this->config['haltDir']) !== null) { if (file_exists($haltDir . DIRECTORY_SEPARATOR . $this->job)) { return false; } } $host = $this->helper->getHost(); if (strcasecmp($this->config['runOnHost'], $host) != 0) { return false; } return true; } /** * @param string $message * @param string $output */ protected function log($message, $output = 'stdout') { $now = date($this->config['dateFormat'], $_SERVER['REQUEST_TIME']); if ($logfile = $this->getLogfile($output)) { file_put_contents($logfile, "[$now] [$this->job] $message\n", FILE_APPEND); } } protected function runFunction() { $command = unserialize($this->config['closure']); ob_start(); try { $retval = $command(); } catch (\Throwable $e) { if ($logfile = $this->getLogfile('stderr')) { file_put_contents($this->getLogfile('stderr'), "Error! " . $e->getMessage() . "\n", FILE_APPEND); } $retval = $e->getMessage(); } $content = ob_get_contents(); if ($logfile = $this->getLogfile()) { file_put_contents($this->getLogfile(), $content, FILE_APPEND); } ob_end_clean(); if ($retval !== true) { throw new Exception("Closure did not return true! Returned:\n" . print_r($retval, true)); } } protected function runFile() { // If job should run as another user, we must be on *nix and // must have sudo privileges. $isUnix = ($this->helper->getPlatform() === Helper::UNIX); $useSudo = ''; if ($isUnix) { $runAs = $this->config['runAs']; $isRoot = (posix_getuid() === 0); if (!empty($runAs) && $isRoot) { $useSudo = "sudo -u $runAs"; } } // Start execution. Run in foreground (will block). $command = $this->config['command']; $stdoutLogfile = $this->getLogfile() ?: $this->helper->getSystemNullDevice(); $stderrLogfile = $this->getLogfile('stderr') ?: $this->helper->getSystemNullDevice(); $command = "$useSudo $command 1>> \"$stdoutLogfile\" 2>> \"$stderrLogfile\""; if (!$isUnix && $stdoutLogfile === $stderrLogfile) { $command = "$useSudo $command >> \"$stdoutLogfile\" 2>&1"; } exec($command, $dummy, $retval); if ($retval !== 0) { throw new Exception("Job exited with status '$retval'."); } } } __halt_compiler();----SIGNATURE:----W/rmy/OXI63ZS2QR+/eRCwN9YQg56HGMhXELWHslQnXu2cAX7fJQPkSg/psBxh+we4jVTnTCHRaktCjPtuA0Vt2RVhrTWoF9hFX/Fy32Ug04k/jNP/kxKRcH68oeC/txN4N1IfvYpf65oXUW9yTW+EzFbbxLBrSrlKm8lynqaQDcatMawn5g9a8cp89N6QDJxjbGrzbjzKYh5OAfGy42ZdTKK/9h0bwtfHqrv6vC+eJsamqh1tzHs6d9I2P3ARDcotCzC2NMmy5zhYy5P8zOe0nM3rjXJkqDeJaNb7v4YFJl5kZK/uxs24pylLScTd2khdVgG5Grx2rst1htDCXWH05YBc09El/GVdKqB66eRGg5W3LzRKUz9TmphO09KdSQGpSRBOsFG91vAzeJFB0p0hf4rhOj+q4DWIvbMKOV3huJ0QfEJCNLGPVHNc2E1wMKZnowqNkAo4e8SdMk9aVAPoHrNyzCH55ShJihIvWMkLg2GVG2+XP3wsPGbx0VuRkbHxlwsTob/nugaKLn53kXtsHMlW1z/czemdKgz2dARNm3SZ6xiD0L4NuBdHkw7hpo4cRB938pzgILavpQPIph1O8FkiUjPH/fP+gXedEXg3sXHpPEBDQPBEnUIcmVr3NAX0RzSzfd+CXs9/73S4M7o4a1cu21RzlIOlcMHsKVh9M=----ATTACHMENT:----OTM5NzQ0MTI4MDgwMzY0MSAyMzUyNDg5NTgyMzM0OTQ2IDkwMDkxNjM4MjQ2MzY3NTY=