1<? 2/** 3 * Cronojob 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Luigi Micco <l.micco@tiscali.it> 7 */ 8 9/*************************************************************************** 10This program is free software; you can redistribute it and/or 11modify it under the terms of the GNU General Public License 12as published by the Free Software Foundation; either version 2 13of the License, or (at your option) any later version. 14 15This program is distributed in the hope that it will be useful, 16but WITHOUT ANY WARRANTY; without even the implied warranty of 17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18GNU General Public License for more details. 19 20You should have received a copy of the GNU General Public License 21along with this program; if not, write to the Free Software 22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 23**************************************************************************** 24 25This script can be called using an HTML img tag, for example: 26 27<img src="pseudocron.php" width="1" height="1" alt="" /> 28 29The advantage of using this script is that pseudocron is called in a separate 30request and thus does not slow down output of the main page as it would if called 31from there. 32 33***************************************************************************/ 34define("PC_MINUTE", 1); 35define("PC_HOUR", 2); 36define("PC_DOM", 3); 37define("PC_MONTH", 4); 38define("PC_DOW", 5); 39define("PC_CMD", 7); 40define("PC_COMMENT", 8); 41define("PC_CRONLINE", 20); 42 43// set some info about Dokuwiki 44define('DOKU_INC', realpath(dirname(__FILE__).'/../../../').'/'); 45define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); 46require_once(DOKU_INC.'inc/utf8.php'); 47require_once(DOKU_INC.'inc/pageutils.php'); 48 49$cronojob = new cronojob(); 50$cronojob->dojobs(); 51$cronojob->sendGif(); 52 53/***************************************************************************/ 54 55class cronojob { 56 57 // The string that contains the job descriptions. 58 // One job for line 59 60 // #scheduled jobs 61 // #comments start with # 62 // #mi h d m dow job comment'; 63 64 // For a description of the format, see http://www.unixgeeks.org/security/newbie/unix/cron-1.html 65 // and http://www.bitfolge.de/pseudocron 66 var $cronTab; 67 68 // The directory where the script can store information on completed jobs and its log file. 69 // include trailing slash 70 var $writeDir; 71 72 // Control logging, true=use log file, false=don't use log file 73 var $useLog; 74 75 // Where to send cron results. 76 var $sendLogToEmail; 77 78 // Maximum number of jobs run during one call of pseudocron. 79 // Set to a low value if your jobs take longer than a few seconds and if you scheduled them 80 // very close to each other. Set to 0 to run any number of jobs. 81 var $maxJobs = 1; 82 83 // Turn on / off debugging output 84 // DO NOT use this on live servers! 85 var $debug = false; 86 87 /****************************************/ 88 /* don't change anything here */ 89 /****************************************/ 90 91 var $resultsSummary; 92 var $pluginname; 93 var $dokuwikititle; 94 var $ID; 95 var $conf; 96 97 function cronojob($debug = false) { 98 global $ID; 99 global $conf; 100 101 $ID = cleanID($_REQUEST['id']); 102 $this->debug = $debug; 103 $this->writeDir = DOKU_INC."data/tmp/"; 104 $this->pluginname = "cronojob"; 105 106 // legge la configurazione 107 $path = DOKU_PLUGIN.$this->pluginname.'/conf/'; 108 $conf = array(); 109 if (@file_exists($path.'default.php')) { 110 include($path.'default.php'); 111 } 112 $conf_plug = $conf; 113 114 $path = DOKU_INC.'conf/'; 115 $conf = array(); 116 if (@file_exists($path.'dokuwiki.php')) include($path.'dokuwiki.php'); 117 if (@file_exists($path.'local.php')) include($path.'local.php'); 118 119 $this->dokuwikititle = $conf['title']; 120 foreach ($conf_plug as $key => $value) { 121 if (isset($conf['plugin'][$this->pluginname][$key])) $conf_plug[$key] = $conf['plugin'][$this->pluginname][$key]; 122 } 123 // legge la configurazione 124 125 $this->cronTab = $conf_plug['cronotab']; 126 $this->sendLogToEmail = $conf_plug['email']; 127 if ($conf_plug['maxjobs'] > 0) $this->maxjobs = $conf_plug['maxjobs']; 128 $this->useLog = $conf_plug['uselog']; 129 130 } 131 132 function dojobs() { 133 if ($this->debug) echo "<pre>"; 134 $jobs = $this->parseCronFile($this->cronTab); 135 $jobsRun = 0; 136 for ($i=0;$i<count($jobs);$i++) { 137 if ($this->maxJobs==0 || $jobsRun<$this->maxJobs) { 138 if ($this->runJob($jobs[$i])) $jobsRun++; 139 } 140 } 141 if ($this->debug) echo "</pre>"; 142 143 } 144 145 function runJob($job) { 146 global $conf; 147 global $ID; 148 global $cronojob; 149 150 // creo una funzione di servizio per gli script 151 function logMessage($msg) { 152 global $cronojob; 153 $cronojob->logMessage($msg); 154 } 155 156 $this->resultsSummary = ""; 157 158 $lastActual = $job["lastActual"]; 159 $lastScheduled = $job["lastScheduled"]; 160 161 if ($lastScheduled<time()) { 162 $this->logMessage("Running ".$job[PC_CRONLINE]); 163 $this->logMessage(" Last run: ".date("r",$lastActual).", Last scheduled: ".date("r",$lastScheduled)); 164 $e = @error_reporting(0); 165 if ($this->debug) { 166 include(DOKU_PLUGIN.$this->pluginname."/jobs/".$job[PC_CMD]); // display errors only when debugging 167 } else { 168 @include(DOKU_PLUGIN.$this->pluginname."/jobs/".$job[PC_CMD]); // any error messages are supressed 169 } 170 @error_reporting($e); 171 $this->markLastRun($job[PC_CMD], $lastScheduled); 172 $this->logMessage(" Completed ".$job[PC_CRONLINE]); 173 if ($this->sendLogToEmail!="") { 174 @mail($this->sendLogToEmail, "[".$this->dokuwikititle."][".$this->pluginname."] ".$job[PC_COMMENT], $this->resultsSummary); 175 } 176 return true; 177 } else { 178 if ($this->debug) { 179 $this->logMessage("Skipping ".$job[PC_CRONLINE]); 180 $this->logMessage(" Last run: ".date("r",$lastActual).", Last scheduled: ".date("r",$lastScheduled)); 181 $this->logMessage(" Completed ".$job[PC_CRONLINE]); 182 } 183 return false; 184 } 185 186 } 187 188 function logMessage($msg) { 189 if ($msg[strlen($msg)-1]!="\n") { 190 $msg.="\n"; 191 } 192 if ($this->debug) echo $msg." ".$this->useLog; 193 $this->resultsSummary.= $msg; 194 if ($this->useLog) { 195 $logfile = $this->writeDir."pseudo-cron.log"; 196 $file = fopen($logfile,"a"); 197 fputs($file,date("r",time())." ".$msg); 198 fclose($file); 199 } 200 } 201 202 function lTrimZeros($number) { 203 while ($number[0]=='0') { 204 $number = substr($number,1); 205 } 206 return $number; 207 } 208 209 function multisort(&$array, $sortby, $order='asc') { 210 foreach($array as $val) { 211 $sortarray[] = $val[$sortby]; 212 } 213 $c = $array; 214 $const = $order == 'asc' ? SORT_ASC : SORT_DESC; 215 $s = array_multisort($sortarray, $const, $c, $const); 216 $array = $c; 217 return $s; 218 } 219 220 function parseElement($element, &$targetArray, $numberOfElements) { 221 $subelements = explode(",",$element); 222 for ($i=0;$i<$numberOfElements;$i++) { 223 $targetArray[$i] = $subelements[0]=="*"; 224 } 225 226 for ($i=0;$i<count($subelements);$i++) { 227 if (preg_match("~^(\\*|([0-9]{1,2})(-([0-9]{1,2}))?)(/([0-9]{1,2}))?$~",$subelements[$i],$matches)) { 228 if ($matches[1]=="*") { 229 $matches[2] = 0; // from 230 $matches[4] = $numberOfElements; //to 231 } elseif ($matches[4]=="") { 232 $matches[4] = $matches[2]; 233 } 234 if ($matches[5][0]!="/") { 235 $matches[6] = 1; // step 236 } 237 for ($j=$this->lTrimZeros($matches[2]);$j<=$this->lTrimZeros($matches[4]);$j+=$this->lTrimZeros($matches[6])) { 238 $targetArray[$j] = TRUE; 239 } 240 } 241 } 242 } 243 244 function incDate(&$dateArr, $amount, $unit) { 245 246 if ($this->debug) echo sprintf("Increasing from %02d.%02d. %02d:%02d by %d %6s ",$dateArr[mday],$dateArr[mon],$dateArr[hours],$dateArr[minutes],$amount,$unit); 247 if ($unit=="mday") { 248 $dateArr["hours"] = 0; 249 $dateArr["minutes"] = 0; 250 $dateArr["seconds"] = 0; 251 $dateArr["mday"] += $amount; 252 $dateArr["wday"] += $amount % 7; 253 if ($dateArr["wday"]>6) { 254 $dateArr["wday"]-=7; 255 } 256 257 $months28 = Array(2); 258 $months30 = Array(4,6,9,11); 259 $months31 = Array(1,3,5,7,8,10,12); 260 261 if ( 262 (in_array($dateArr["mon"], $months28) && $dateArr["mday"]==28) || 263 (in_array($dateArr["mon"], $months30) && $dateArr["mday"]==30) || 264 (in_array($dateArr["mon"], $months31) && $dateArr["mday"]==31) 265 ) { 266 $dateArr["mon"]++; 267 $dateArr["mday"] = 1; 268 } 269 270 } elseif ($unit=="hour") { 271 if ($dateArr["hours"]==23) { 272 $this->incDate($dateArr, 1, "mday"); 273 } else { 274 $dateArr["minutes"] = 0; 275 $dateArr["seconds"] = 0; 276 $dateArr["hours"]++; 277 } 278 } elseif ($unit=="minute") { 279 if ($dateArr["minutes"]==59) { 280 $this->incDate($dateArr, 1, "hour"); 281 } else { 282 $dateArr["seconds"] = 0; 283 $dateArr["minutes"]++; 284 } 285 } 286 if ($this->debug) echo sprintf("to %02d.%02d. %02d:%02d\n",$dateArr[mday],$dateArr[mon],$dateArr[hours],$dateArr[minutes]); 287 } 288 289 function getLastScheduledRunTime($job) { 290 291 $extjob = Array(); 292 $this->parseElement($job[PC_MINUTE], $extjob[PC_MINUTE], 60); 293 $this->parseElement($job[PC_HOUR], $extjob[PC_HOUR], 24); 294 $this->parseElement($job[PC_DOM], $extjob[PC_DOM], 31); 295 $this->parseElement($job[PC_MONTH], $extjob[PC_MONTH], 12); 296 $this->parseElement($job[PC_DOW], $extjob[PC_DOW], 7); 297 298 $dateArr = getdate($this->getLastActualRunTime($job[PC_CMD])); 299 $minutesAhead = 0; 300 while ( 301 $minutesAhead<525600 AND 302 (!$extjob[PC_MINUTE][$dateArr["minutes"]] OR 303 !$extjob[PC_HOUR][$dateArr["hours"]] OR 304 (!$extjob[PC_DOM][$dateArr["mday"]] OR !$extjob[PC_DOW][$dateArr["wday"]]) OR 305 !$extjob[PC_MONTH][$dateArr["mon"]]) 306 ) { 307 if (!$extjob[PC_DOM][$dateArr["mday"]] OR !$extjob[PC_DOW][$dateArr["wday"]]) { 308 $this->incDate($dateArr,1,"mday"); 309 $minutesAhead+=1440; 310 continue; 311 } 312 if (!$extjob[PC_HOUR][$dateArr["hours"]]) { 313 $this->incDate($dateArr,1,"hour"); 314 $minutesAhead+=60; 315 continue; 316 } 317 if (!$extjob[PC_MINUTE][$dateArr["minutes"]]) { 318 $this->incDate($dateArr,1,"minute"); 319 $minutesAhead++; 320 continue; 321 } 322 } 323 324 //if ($this->debug) print_r($dateArr); 325 326 return mktime($dateArr["hours"],$dateArr["minutes"],0,$dateArr["mon"],$dateArr["mday"],$dateArr["year"]); 327 } 328 329 function getJobFileName($jobname) { 330 $jobfile = $this->writeDir.urlencode($jobname).".job"; 331 return $jobfile; 332 } 333 334 function getLastActualRunTime($jobname) { 335 $jobfile = $this->getJobFileName($jobname); 336 if (file_exists($jobfile)) { 337 return filemtime($jobfile); 338 } 339 return 0; 340 } 341 342 function markLastRun($jobname, $lastRun) { 343 $jobfile = $this->getJobFileName($jobname); 344 touch($jobfile); 345 } 346 347 function parseCronFile($cronTabFile) { 348 $file = explode("\n", $cronTabFile); 349// $file = file($cronTabFile); 350// $file = $cronTabFile; 351 $job = Array(); 352 $jobs = Array(); 353 for ($i=0;$i<count($file);$i++) { 354 if ($file[$i][0]!='#') { 355 // old regex, without dow abbreviations: 356 // if (preg_match("~^([-0-9,/*]+)\\s+([-0-9,/*]+)\\s+([-0-9,/*]+)\\s+([-0-9,/*]+)\\s+([-0-7,/*]+|Sun|Mon|Tue|Wen|Thu|Fri|Sat)\\s+([^#]*)(#.*)?$~i",$file[$i],$job)) { 357 if (preg_match("~^([-0-9,/*]+)\\s+([-0-9,/*]+)\\s+([-0-9,/*]+)\\s+([-0-9,/*]+)\\s+([-0-7,/*]+|(-|/|Sun|Mon|Tue|Wed|Thu|Fri|Sat)+)\\s+([^#]*)\\s*(#.*)?$~i",$file[$i],$job)) { 358 $jobNumber = count($jobs); 359 $jobs[$jobNumber] = $job; 360 if ($jobs[$jobNumber][PC_DOW][0]!='*' AND !is_numeric($jobs[$jobNumber][PC_DOW])) { 361 $jobs[$jobNumber][PC_DOW] = str_replace( 362 Array("Sun","Mon","Tue","Wed","Thu","Fri","Sat"), 363 Array(0,1,2,3,4,5,6), 364 $jobs[$jobNumber][PC_DOW]); 365 } 366 $jobs[$jobNumber][PC_CMD] = trim($job[PC_CMD]); 367 $jobs[$jobNumber][PC_COMMENT] = trim(substr($job[PC_COMMENT],1)); 368 $jobs[$jobNumber][PC_CRONLINE] = $file[$i]; 369 } 370 $jobfile = $this->getJobFileName($jobs[$jobNumber][PC_CMD]); 371 372 $jobs[$jobNumber]["lastActual"] = $this->getLastActualRunTime($jobs[$jobNumber][PC_CMD]); 373 $jobs[$jobNumber]["lastScheduled"] = $this->getLastScheduledRunTime($jobs[$jobNumber]); 374 } 375 } 376 377 $this->multisort($jobs, "lastScheduled"); 378 379 if ($this->debug) var_dump($jobs); 380 return $jobs; 381 } 382 383 function sendGif() { 384 if($this->debug) return; 385 $img = base64_decode("R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=="); 386 387/* 388 $img = base64_decode("iVBORw0KGgoAAAANSUhEUgAAAFAAAAAPCAIAAAD8q9/YAAAA5ElEQVRIieVXuw7DIAw8qnwrnrt0 3894AM6sDD7a+lAQylg4kp5VOIm63TINucYxVhrMRMWAMx8dRkngYiWNTQ/n+bog9u3oEPxuD8B3K4u 39042xM1/DS4Ti+g3LOEylMfpoWAOWQJzIzSo0UVwc3Nd10EB0mAzKfzjnWTAMfnA8up0mllIxSU8YD 391mUbTPdVzGLKf8m6TTBj42UUqcZd12L2gocMtthweZ1W2MTYTQifKkgSHK+RhVr9euegqZWmgpMF3 392z61Mw0AYKGOtZeZJ3mEimu5Zmq7h9RuWt9EAyuXxVzCz/S29AGJYqkfnR9EBAAAAAElFTkSuQmCC"); 393*/ 394 395 Header("Content-Type: image/gif"); 396 Header('Content-Length: '.strlen($img)); 397 header('Connection: Close'); 398 echo $img; 399 } 400 401} 402 403?> 404 405