#! /usr/bin/php > lifeLog.txt & The program is fetching an XHTML page and looking for a specific field. The content of the field is a UNIX-Epoch timestamp in integer or floating point form. This (program) takes client time as a floating point, with a precision of microseconds, so server time in microseconds would be used. The page must be valid XHTML (XML), or it won't parse properly. The original program fetches the server timestamp from the "serverTimeUE" field of the page: http://kwynn.com/t/0/11/time/time.php The program is expecting the field to have other characteristic than that ID--see the code. Both client and server need accurate clocks. The original setting is to consider a 20 second delay a "fail." **** Operation **** This (program) goes through a loop (originally set at 40 minutes). It reads the target web page and compares client and server time. If the page is unreachable or the time + read time difference is too long, this is a "fail." Upon fail, it goes into a second loop. If there are several failures over the course of several minutes, several emails / texts are sent over a period of time, then the program exits. (Once the web site has been declared dead, no reason to keep sending messages.) */ // The first few lines are the "main." Everything else is functions. // Functions are generally defined a few lines below their first call. check_for_web_execution(); // defined at bottom $settings = simplexml_load_file('life.xml'); if ($settings == false) { showStatus(2, "xml file fail. exiting"); exit(1); } $periodInMin = 40; $periodInSec = $periodInMin * 60; showStatus(0, "BEGIN EXECUTION"); do { probe_loop(); sleep($periodInSec); } while(1); /* *********** BEGIN FUNCTION SECTION *************/ // output example: 2011_0424_0547_48 - OK - BEGIN EXECUTION function showStatus($warningLevel = 0, $msg = "") { $wls = ""; switch($warningLevel) { case 0: $wls = "OK"; break; case 1: $wls = "WARNING"; break; case 2: $wls = "ERROR"; break; } // getFTS = formatted timestamp echo getFTS() . " - " . $wls . " - " . $msg . "\n"; } function getFTS() { $now = new DateTime(); return $now->format('Y_md_Hi_s'); // see output example above } function probe_loop() { global $settings; // if you're in test mode, you want the failure email / text to come quickly. Otherwise, // wait a few minutes to confirm failure // $slarr = sleep array if ($settings->test_mode == '1') $slarr = array(1, 1, 1); else $slarr = array(2 * 60, 3 * 60, 5 * 60); // if the multiple tests fail, continue on to mailing. Otherwise return (and wait for the next test cycle) for ($i=0; $i < count($slarr); $i++) { if (probe_analyze_diff() == false) sleep($slarr[$i]); else return; } // send 3 texts / emails. The second one comes 65 seconds after the first (so hopefully it will have a // different minute stamp), then wait 25 minutes $mailArr = array(65, 60 * 25); if (probe_analyze_diff() == false) { showStatus(2, "MAILING"); myMail(); for ($i=0; $i < count($mailArr); $i++) { sleep($mailArr[$i]); myMail(); } exit(0); } } // if the difference between client and server time is a number, round to 6 digits beyond the decimal and display // if the difference is too large, return false (failure) function probe_analyze_diff() { $diff = client_server_diff(); if ($diff !== false) $diff = round($diff, 6); if ($diff === false || $diff > 20 || $diff < -20) { if ($diff === false) showStatus(1,"diff is false"); else showStatus(1,"diff = " . $diff); return false; } showStatus(0,"diff = $diff"); // show status OK return true; } function client_server_diff() { global $settings; $diff = 600; // I'm not sure if there's a condition where this default would matter. It's supposed to // be a large number that would mean failure try { $doc = new SimpleXMLElement($settings->url, 0, true); // fetch the server time page if ($doc == false) return false; $serverTime = getServerTime($doc); $myTime = microtime(true); $diff = (float) $myTime - (float) $serverTime; } catch(exception $e) { return false; } // this catches 404 errors, etc. return $diff; } // a recursive function to pick the server time out of the XHTML document function getServerTime($node) { if ($node->getName() == 'td') foreach ($node->attributes() as $key => $value) if ($key == 'id' && $value=='serverTimeUE') return trim($node); // if no trim, is_numeric will fail foreach ($node->children() as $child) { $ret = getServerTime($child); if ($ret !== 0) { if (!is_numeric($ret)) return 0; if ($ret < 1303517034) return 0; // another check. This is a time that has already passed. return $ret; } } return 0; } // see the XML file and the PEAR Mail documentation for details // XML file example at http://kwynn.com/t/0/11/life/life.xml // note that you can send text messages through email, as described in the XML file comments function myMail() { include_once('Mail.php'); global $settings; $mailSet = $settings->email_upon_death; if ($mailSet->smtp->auth == '1') $mailSet->smtp->auth = true; else $mailSet->smtp->auth = false; foreach ($mailSet->headers->children() as $key => $value) $headers[ucwords($key)] = $value; foreach ($mailSet->smtp ->children() as $key => $value) $smtp [$key ] = $value; $mail =& Mail::factory('smtp',$smtp); if ($mail instanceof PEAR_Error) showStatus(2,$mail->getMessage()); $return = $mail->send($headers['To'], $headers, $mailSet->body); if ($return !== true) showStatus(2, $return->getMessage()); } // not sure this is the best way to check, but it appears to work // I added SERVER_NAME because it is in the CGI 1.1 specification (RFC 3875), as // mentioned at http://us3.php.net/manual/en/reserved.variables.server.php function check_for_web_execution() { if ($_SERVER) if ( array_key_exists('SERVER_ADDR', $_SERVER) || array_key_exists('SERVER_NAME', $_SERVER) ) { showStatus(2, "executing from a web server. Exiting."); exit(2); } } ?>