acron.php
Das Problem:
Eine dynamisch generierte Webseite (oder auch eine komplexe 'Site') erfordert mitunter regelmäßig wiederkehrende Aufgaben und Vorgänge. Viele dieser Vorgänge bedürfen keiner User-/admin Interaktion. Auf einem UNIX Sytem kann man solche Aufgaben elegant mit einem Eintrag in die crontab erledigen. Der cron Deamon checkt dann jede Minute, welche Aufgaben zu erledigen sind und führt diese aus. Die Angaben im crontab sind denkbar flexibel und lassen sich wunderbar gfenau einstellen.
Einmal pro Woche die Festplatte auf eine bestimmte Art von Dateien überprüfen? Am 03.03. jedes Jahres an den Hochzeitstag errinnern? Nachts um halb zwei eine bestimmte Webseite auf Änderungen überprüfen, aber das nur an Wochentagen?
Mit cron und ein paar shell-scripten (Perl-, Python- oder was auch immer) alles kein Problem.Aber was machen, wenn man seine Seiten auf einem Account hat, der zwar PHP kann, aber keinen shell-Zugang oder gar crontab? (das ist für Viele bestimmt auch eine Frage der Finanzen. PHP-fähiger Webspace ist schon recht günstig zu haben. ShellAccess nicht)
Ein Lösungsansatz:
OK, was haben wir?
- PHP Support. Also können wir alles mögliche sinnvolle ofder un-sinnvolle machen. Webseiten holen. Mail schicken. Dateien löschen. Listings erstellen.
- Ein paar Seiten mit Inhalten, die häufig aufgerufen werden. (das liegt dann auch der Hase begraben s. später)
- Ein wenig Hirnschmalz. (hoffentlich)
Und was wollen wir?
- In einer Textdatei sollen die zu erledigenden Jobs zusammen mit dem Zeitintervall der Ausführung eingetragen werden.
- Ich gehe hier bewußt ersteinmal von dem vollen Funktionsumfang von 'cron' etwas weg um die Sache zu vereinfachen. 'cron' kann Befehle auch zu genau festgelegten Uhrzeiten etc. ausführen.
- ein zentrales Script ließt möglichst regelmäßig diese Datei, überprüft, ob die jeweiligen Jobs in dem angegebenen Intervall schon ausgeführt wurden, und startet die Scripte wenn nicht.
- Um das zu können, muß sich das zentrale Script natürlich auch merken, wann es zuletzt die fraglichen Jobs ausgeführt hat.
Die zentrale Idee zur Lösung
Ein Cron-Daemon funktioniert ungefähr so:
Das Programm liest die crontab, in der die Jobs stehen, vergleicht die Einstellungen pro Job mit der aktuellen Uhr- Tages und Jahres-zeit und führt diejenigen Jobs aus, auf die die aktuelle Zeit passt.
Dann 'schäft' das Programm ca. 1 Minute, erwacht und wiederholt den ersten Vorgang.
Wichtig hieran ist: der Cron-Daemon muß immer im Hintergrund laufen.genau das geht hier aber nicht.
Ein PHP-Script auf einem normalen Webhost-Server wird aufgerufen, arbeitet seine Anweisungen ab, und beendet sich dann. Die meisten Hoster erlauben keine 'Longrunning Processes' also Programme, die im Hintergrund weitlaufen.
... und doch!
wenn wir eine PHP-basierte Seite hätten, könnten wir doch jenes Script in diese Seite integrieren, nicht?
Und genau da liegt der Haken. Nur wenn wir sicher sein können, daß unser cron-script häufiger als einmal pro Minute aufgerufen wird, funktioniert das mit den minütlichen Jobs.'work in progress'
soll heißen: das wäre also das grundlegende Prinzip. Ich habe sowas teilweise realisiert und für meine Zwecke funktioniert es auch ganz ok. Aber wirklich umgesetzt habe ich es (noch) nicht.
<?
//
// dadaCron.php is the dummed down version of fakeCron.php,
// (fakeCron.php does not yet exist)
// (c) 2001 Martin Spernau, martin @trauwind.de
// php-script to mimic the functionality of a unix cron-deamon
//
// script will be included into a page that is called fairly regularly
// -> more tha once a minute would be optimal
// crons.txt will have one line per job
// with
// diff-time space job
// like
// 10 getXML.php
//
// functions
function dojob ($url) {
// $url needs to be fully specified http:// type url
global $log;
$fjob = @fopen($url,"r");
if (! $fjob) { fwrite ($log, "\tfailed $url\n"); }
else { fwrite ($log, "\tsuccess $url\n"); }
}
function checkjob ($s) {
global $missed;
list ($minutes, $job) = split (" ", $s);
if ($minutes < ($missed / 60)) { dojob($job); }
}
// some config vars
$crontab = "crons.txt";
$lastrun_file = "cron.run"; // dummy-file -> timestamp signals lastrun
$cronlog = date("Y-m-d").".log"; // like 2001-05-14.log, one file per day
if (! file_exists($lastrun_file)) { // lets make sure it exists
$temp = fopen($lastrun_file, "w") or die ("unable to create lastrun file ($lastrun_file)\n");
fclose($temp);
}
// get lastrun
$lastrun = filemtime ($lastrun_file);
// set lastrun
touch ($lastrun_file);
$now = time();
$missed = ($now - $lastrun); // time since last run
if ($missed > 60) { // we only run once every minute!
$nowArr = getdate ($now);
$lastArr = getdate ($lastrun);
// open our LOG
$log = fopen ($cronlog, "a") or die ("coudn't open/create $cronlog\n");
fwrite ($log, "cron at ".gmdate( "d/M/Y:H:i:s", $now)."\n");
// read the crontab-file
$cronjobs = file ($crontab);
// do the cron-jobs in $crontab
while (list ($linenum, $line) = each ($cronjobs) ) {
$line = chop($line);
if ($line[0] == "") {next;} // this a comment
else { checkjob($line); }
}
// done
fclose ($log);
} // end if $missed > 60
?>
alles Bild, Text und Tonmaterial ist © Martin Spernau, Verwendung und Reproduktion erfordert die Zustimmung des Authors