diff --git a/README.md b/README.md index 99c9018..b92ca25 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,29 @@ Almost, but not really. Environment checks differ from unit tests in two importa * **They test environment specific settings.** Unit tests are designed to use dummy data and mock interfaces to external system. Environment checks check the real systems and data that the given environment is actually connected to. * **They can't modify data.** Because these checks will run using production databases, they can't go modifying the data in there. This is the biggest reason why we haven't used the same base class as a unit test for writing environment checks - we wanted to make it impossible to accidentally plug a unit test into the environment checker! +## Installation + +Register checks in your own `_config.php` - see the `_config.php` in this module for some defaults. + + :::php + EnvironmentCheckSuite::register('health', 'DatabaseCheck', "Can we connect to the database?"); + EnvironmentCheckSuite::register('check', 'URLCheck("")', "Is the homepage accessible?"); + +## Available checks + + * `DatabaseCheck`: Check that the connection to the database is working, by looking for records in some table. By default, Member will be checked. + * `URLCheck`: Check that a given URL is functioning, by default, the homepage. + * `HasFunctionCheck`: Check that the given function exists. + This can be used to check that PHP modules or features are installed. + * `HasClassCheck`: Check that the given class exists. + This can be used to check that PHP modules or features are installed. + * `FileWriteableCheck`: Check that the given file is writeable. + * `FileAgeCheck`: Checks for the maximum age of one or more files or folders. + Useful for files which should be frequently auto-generated, + like static caches, as well as for backup files and folders. + * `ExternalURLCheck`: Checks that one or more URLs are reachable via HTTP. + * `SMTPConnectCheck`: Checks if the SMTP connection configured through PHP.ini works as expected. + ## Adding more checks To add more checks, you should put additional `EnvironmentCheckSuite::register` calls into your `_config.php`. See the `_config.php` file of this module for examples. diff --git a/_config.php b/_config.php index 4956798..e2dab15 100644 --- a/_config.php +++ b/_config.php @@ -1,25 +1,25 @@ 'DevHealth', - 'dev/check' => 'DevCheck', + 'dev/health' => 'DevHealthController', + 'dev/check' => 'DevCheckController', )); \ No newline at end of file diff --git a/code/DefaultHealthChecks.php b/code/DefaultHealthChecks.php deleted file mode 100644 index 500d6bf..0000000 --- a/code/DefaultHealthChecks.php +++ /dev/null @@ -1,157 +0,0 @@ -checkTable = $checkTable; - } - - function check() { - $count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value(); - - if($count > 0) { - return array(EnvironmentCheck::OK, ""); - } else { - return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records"); - } - } -} - -/** - * Check that a given URL is functioning, by default, the homepage. - * - * Note that Director::test() will be used rather than a CURL check. - */ -class URLCheck implements EnvironmentCheck { - protected $url; - protected $testString; - - /* - * @param $url The URL to check, relative to the site. "" is the homepage. - * @param $testString A piece of text to optionally search for in the homepage HTML. If omitted, no such check is made. - */ - function __construct($url = "", $testString = "") { - $this->url = $url; - $this->testString = $testString; - } - - function check() { - $response = Director::test($this->url); - - if($response->getStatusCode() != 200) { - return array(EnvironmentCheck::ERROR, "Homepage requested and returned HTTP " . $response->getStatusCode() . " response"); - - } else if($this->testString && (strpos($response->getBody(), $this->testString) === false)) { - return array(EnvironmentCheck::WARNING, "Homepage requested ok but '$testString' not found."); - - } else { - return array(EnvironmentCheck::OK, ""); - } - } -} - -/** - * Check that the given function exists. - * This can be used to check that PHP modules or features are installed. - * @param $functionName The name of the function to look for. - */ -class HasFunctionCheck implements EnvironmentCheck { - protected $functionName; - - function __construct($functionName) { - $this->functionName = $functionName; - } - - function check() { - if(function_exists($this->functionName)) return array(EnvironmentCheck::OK, $this->functionName.'() exists'); - else return array(EnvironmentCheck::ERROR, $this->functionName.'() doesn\'t exist'); - } -} - -/** - * Check that the given class exists. - * This can be used to check that PHP modules or features are installed. - * @param $className The name of the class to look for. - */ -class HasClassCheck implements EnvironmentCheck { - protected $className; - - function __construct($className) { - $this->className = $className; - } - - function check() { - if(class_exists($this->className)) return array(EnvironmentCheck::OK, 'Class ' . $this->className.' exists'); - else return array(EnvironmentCheck::ERROR, 'Class ' . $this->className.' doesn\'t exist'); - } -} - -/** - * Check that the given file is writeable. - * This can be used to check that the environment doesn't have permission set-up errors. - * @param $path The full path. If a relative path, it will relative to the BASE_PATH - */ -class FileWriteableCheck implements EnvironmentCheck { - protected $path; - - function __construct($path) { - $this->path = $path; - } - - function check() { - if($this->path[0] == '/') $filename = $this->path; - else $filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path); - - if(file_exists($filename)) $isWriteable = is_writeable($filename); - else $isWriteable = is_writeable(dirname($filename)); - - if(!$isWriteable) { - if(function_exists('posix_getgroups')) { - $userID = posix_geteuid(); - $user = posix_getpwuid($userID); - - $currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename) ); - $currentOwner = posix_getpwuid($currentOwnerID); - - $message = "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe file is currently owned by '$currentOwner[name]'. "; - - if($user['name'] == $currentOwner['name']) { - $message .= "We recommend that you make the file writeable."; - } else { - - $groups = posix_getgroups(); - $groupList = array(); - foreach($groups as $group) { - $groupInfo = posix_getgrgid($group); - if(in_array($currentOwner['name'], $groupInfo['members'])) $groupList[] = $groupInfo['name']; - } - if($groupList) { - $message .= " We recommend that you make the file group-writeable and change the group to one of these groups:\n - ". implode("\n - ", $groupList) - . "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename"; - } else { - $message .= " There is no user-group that contains both the web-server user and the owner of this file. Change the ownership of the file, create a new group, or temporarily make the file writeable by everyone during the install process."; - } - } - - } else { - $message .= "The webserver user needs to be able to write to this file:\n$filename"; - } - - return array(EnvironmentCheck::ERROR, $message); - } - - return array(EnvironmentCheck::OK,''); - } -} \ No newline at end of file diff --git a/code/DevCheck.php b/code/DevCheckController.php similarity index 79% rename from code/DevCheck.php rename to code/DevCheckController.php index 8df6086..6c9884b 100644 --- a/code/DevCheck.php +++ b/code/DevCheckController.php @@ -1,6 +1,6 @@ setErrorCode(404); diff --git a/code/EnvironmentCheck.php b/code/EnvironmentCheck.php index 12d785e..0b3af58 100644 --- a/code/EnvironmentCheck.php +++ b/code/EnvironmentCheck.php @@ -27,149 +27,4 @@ interface EnvironmentCheck { */ function check(); -} - -/** - * Represents a suite of environment checks. - * Also has a register for assigning environment checks to named instances of EnvironmentCheckSuite - * - * Usage: - * EnvironmentCheckSuite::register('health', 'MyHealthCheck'); - * - * $result = EnvironmentCheckSuite::inst('health')->run(); - */ -class EnvironmentCheckSuite { - protected $checks = array(); - - /** - * Run this test suite - * @return The result code of the worst result. - */ - public function run() { - $worstResult = 0; - - $result = new EnvironmentCheckSuiteResult; - foreach($this->checkInstances() as $check) { - list($checkClass, $checkTitle) = $check; - try { - list($status, $message) = $checkClass->check(); - // If the check fails, register that as an error - } catch(Exception $e) { - $status = EnvironmentCheck::ERROR; - $message = $e->getMessage(); - } - $result->addResult($status, $message, $checkTitle); - } - - return $result; - } - - /** - * Get instances of all the environment checks - */ - protected function checkInstances() { - $output = array(); - foreach($this->checks as $check) { - list($checkClass, $checkTitle) = $check; - if(is_string($checkClass)) { - $checkInst = Object::create_from_string($checkClass); - if($checkInst instanceof EnvironmentCheck) { - $output[] = array($checkInst, $checkTitle); - } else { - throw new InvalidArgumentException("Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck"); - } - } else if($checkClass instanceof EnvironmentCheck) { - $output[] = array($checkClass, $checkTitle); - } else { - throw new InvalidArgumentException("Bad EnvironmentCheck: " . var_export($check, true)); - } - } - return $output; - } - - /** - * Add a check to this suite. - * - */ - public function push($check, $title = null) { - if(!$title) { - $title = is_string($check) ? $check : get_class($check); - } - $this->checks[] = array($check, $title); - } - - ///////////////////////////////////////////////////////////////////////////////////////////// - - protected static $instances = array(); - - /** - * Return a named instance of EnvironmentCheckSuite. - */ - static function inst($name) { - if(!isset(self::$instances[$name])) self::$instances[$name] = new EnvironmentCheckSuite(); - return self::$instances[$name]; - } - - /** - * Register a check against the named check suite - */ - static function register($name, $check, $title = null) { - self::inst($name)->push($check, $title); - } -} - -/** - * A single set of results from running an EnvironmentCheckSuite - */ -class EnvironmentCheckSuiteResult extends ViewableData { - protected $details, $worst = 0; - - function __construct() { - parent::__construct(); - $this->details = new DataObjectSet(); - } - - function addResult($status, $message, $checkIdentifier) { - $this->details->push(new ArrayData(array( - 'Check' => $checkIdentifier, - 'Status' => $this->statusText($status), - 'Message' => $message, - ))); - - $this->worst = max($this->worst, $status); - } - - /** - * Returns true if there are no ERRORs, only WARNINGs or OK - */ - function ShouldPass() { - return $this->worst <= EnvironmentCheck::WARNING; - } - - /** - * Returns overall (i.e. worst) status as a string. - */ - function Status() { - return $this->statusText($this->worst); - } - - /** - * Returns detailed status information about each check - */ - function Details() { - return $this->details; - } - - /** - * Return a text version of a status code - */ - protected function statusText($status) { - switch($status) { - case EnvironmentCheck::ERROR: return "ERROR"; - case EnvironmentCheck::WARNING: return "WARNING"; - case EnvironmentCheck::OK: return "OK"; - case 0: return "NO CHECKS"; - default: throw new InvalidArgumentException("Bad environment check status '$status'"); - } - } } \ No newline at end of file diff --git a/code/EnvironmentCheckSuite.php b/code/EnvironmentCheckSuite.php new file mode 100644 index 0000000..6041d3f --- /dev/null +++ b/code/EnvironmentCheckSuite.php @@ -0,0 +1,148 @@ +run(); + */ +class EnvironmentCheckSuite { + protected $checks = array(); + + /** + * Run this test suite + * @return The result code of the worst result. + */ + public function run() { + $worstResult = 0; + + $result = new EnvironmentCheckSuiteResult; + foreach($this->checkInstances() as $check) { + list($checkClass, $checkTitle) = $check; + try { + list($status, $message) = $checkClass->check(); + // If the check fails, register that as an error + } catch(Exception $e) { + $status = EnvironmentCheck::ERROR; + $message = $e->getMessage(); + } + $result->addResult($status, $message, $checkTitle); + } + + return $result; + } + + /** + * Get instances of all the environment checks + */ + protected function checkInstances() { + $output = array(); + foreach($this->checks as $check) { + list($checkClass, $checkTitle) = $check; + if(is_string($checkClass)) { + $checkInst = Object::create_from_string($checkClass); + if($checkInst instanceof EnvironmentCheck) { + $output[] = array($checkInst, $checkTitle); + } else { + throw new InvalidArgumentException("Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck"); + } + } else if($checkClass instanceof EnvironmentCheck) { + $output[] = array($checkClass, $checkTitle); + } else { + throw new InvalidArgumentException("Bad EnvironmentCheck: " . var_export($check, true)); + } + } + return $output; + } + + /** + * Add a check to this suite. + * + */ + public function push($check, $title = null) { + if(!$title) { + $title = is_string($check) ? $check : get_class($check); + } + $this->checks[] = array($check, $title); + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + + protected static $instances = array(); + + /** + * Return a named instance of EnvironmentCheckSuite. + */ + static function inst($name) { + if(!isset(self::$instances[$name])) self::$instances[$name] = new EnvironmentCheckSuite(); + return self::$instances[$name]; + } + + /** + * Register a check against the named check suite. + * + * @param String|Array + */ + static function register($names, $check, $title = null) { + if(!is_array($names)) $names = array($names); + foreach($names as $name) self::inst($name)->push($check, $title); + } +} + +/** + * A single set of results from running an EnvironmentCheckSuite + */ +class EnvironmentCheckSuiteResult extends ViewableData { + protected $details, $worst = 0; + + function __construct() { + parent::__construct(); + $this->details = new DataObjectSet(); + } + + function addResult($status, $message, $checkIdentifier) { + $this->details->push(new ArrayData(array( + 'Check' => $checkIdentifier, + 'Status' => $this->statusText($status), + 'Message' => $message, + ))); + + $this->worst = max($this->worst, $status); + } + + /** + * Returns true if there are no ERRORs, only WARNINGs or OK + */ + function ShouldPass() { + return $this->worst <= EnvironmentCheck::WARNING; + } + + /** + * Returns overall (i.e. worst) status as a string. + */ + function Status() { + return $this->statusText($this->worst); + } + + /** + * Returns detailed status information about each check + */ + function Details() { + return $this->details; + } + + /** + * Return a text version of a status code + */ + protected function statusText($status) { + switch($status) { + case EnvironmentCheck::ERROR: return "ERROR"; + case EnvironmentCheck::WARNING: return "WARNING"; + case EnvironmentCheck::OK: return "OK"; + case 0: return "NO CHECKS"; + default: throw new InvalidArgumentException("Bad environment check status '$status'"); + } + } +} \ No newline at end of file diff --git a/code/checks/DatabaseCheck.php b/code/checks/DatabaseCheck.php new file mode 100644 index 0000000..9696c0f --- /dev/null +++ b/code/checks/DatabaseCheck.php @@ -0,0 +1,29 @@ +checkTable = $checkTable; + } + + function check() { + $count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value(); + + if($count > 0) { + return array(EnvironmentCheck::OK, ""); + } else { + return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records"); + } + } +} \ No newline at end of file diff --git a/code/checks/ExternalURLCheck.php b/code/checks/ExternalURLCheck.php new file mode 100644 index 0000000..a8a09b5 --- /dev/null +++ b/code/checks/ExternalURLCheck.php @@ -0,0 +1,110 @@ +EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?"); + */ +class ExternalURLCheck implements EnvironmentCheck { + + /** + * @var array + */ + protected $urls = array(); + + /** + * @var Int Timeout in seconds. + */ + protected $timeout; + + /** + * @param String Space separated list of absolute URLs + * (can't be an array as we're using Object::create() with strings for the constructor signature) + */ + function __construct($urls, $timeout = 15) { + if($urls) $this->urls = explode(' ', $urls); + $this->timeout = $timeout; + } + + function check() { + $urls = $this->getURLs(); + + $chs = array(); + foreach($urls as $url) { + $ch = curl_init(); + $chs[] = $ch; + curl_setopt_array($ch, $this->getCurlOpts($url)); + } + // Parallel execution for faster performance + $mh = curl_multi_init(); + foreach($chs as $ch) curl_multi_add_handle($mh,$ch); + + $active = null; + // Execute the handles + do { + $mrc = curl_multi_exec($mh, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM); + + while ($active && $mrc == CURLM_OK) { + if (curl_multi_select($mh) != -1) { + do { + $mrc = curl_multi_exec($mh, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM); + } + } + + $hasError = false; + $msgs = array(); + foreach($chs as $ch) { + $url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if(curl_errno($ch) || $code >= 400) { + $hasError = true; + $msgs[] = sprintf( + 'Error retrieving "%s": %s (Code: %s)', + $url, + curl_error($ch), + $code + ); + } else { + $msgs[] = sprintf( + 'Success retrieving "%s" (Code: %s)', + $url, + $code + ); + } + } + + // Close the handles + foreach($chs as $ch) curl_multi_remove_handle($mh, $ch); + curl_multi_close($mh); + + if($hasError) { + return array(EnvironmentCheck::ERROR, implode(', ', $msgs)); + } else { + return array(EnvironmentCheck::OK, implode(', ', $msgs)); + } + } + + /** + * @return Array + */ + protected function getCurlOpts($url) { + return array( + CURLOPT_URL => $url, + CURLOPT_HEADER => 0, + CURLOPT_RETURNTRANSFER => 1, + CURLOPT_FAILONERROR => 1, + CURLOPT_TIMEOUT => $this->timeout, + ); + } + + /** + * @return Array + */ + protected function getURLs() { + return $this->urls; + } +} \ No newline at end of file diff --git a/code/checks/FileAgeCheck.php b/code/checks/FileAgeCheck.php new file mode 100644 index 0000000..b531983 --- /dev/null +++ b/code/checks/FileAgeCheck.php @@ -0,0 +1,106 @@ +', " . FileAgeCheck::CHECK_ALL) . "' + * ); + * + * // Checks that at least one backup folder has been created in the last 24h + * EnvironmentCheckSuite::register( + * 'check', + * 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "' + * ); + */ +class FileAgeCheck implements EnvironmentCheck { + + const CHECK_SINGLE = 1; + + const CHECK_ALL = 2; + + /** + * @var String Absolute path to a file or folder, compatible with glob(). + */ + protected $path; + + /** + * @var String strtotime() compatible relative date specification. + */ + protected $relativeAge; + + /** + * @var String The function to use for checking file age, + * so filemtime(), filectime() or fileatime(). + */ + protected $checkFn; + + /** + * @var Int Constant, check for a single file to match age criteria, or all of them. + */ + protected $checkType; + + /** + * @var String Either '>' or '<'. + */ + protected $compareOperand; + + function __construct($path, $relativeAge, $compareOperand = '>', $checkType = null, $checkFn = 'filemtime') { + $this->path = $path; + $this->relativeAge = $relativeAge; + $this->checkFn = $checkFn; + $this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE; + $this->compareOperand = $compareOperand; + } + + function check() { + $cutoffTime = strtotime($this->relativeAge, SS_Datetime::now()->Format('U')); + $files = $this->getFiles(); + $invalidFiles = array(); + $validFiles = array(); + $checkFn = $this->checkFn; + $allValid = true; + if($files) foreach($files as $file) { + $fileTime = $checkFn($file); + $valid = ($this->compareOperand == '>') ? ($fileTime >= $cutoffTime) : ($fileTime <= $cutoffTime); + if($valid) { + $validFiles[] = $file; + } else { + $invalidFiles[] = $file; + if($this->checkType == self::CHECK_ALL) { + return array( + EnvironmentCheck::ERROR, + sprintf( + 'File "%s" doesn\'t match age check (compare %s: %s, actual: %s)', + $file, $this->compareOperand, date('c', $cutoffTime), date('c', $fileTime) + ) + ); + } + } + } + + // If at least one file was valid, count as passed + if($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) { + return array(EnvironmentCheck::OK, ''); + } else { + return array( + EnvironmentCheck::ERROR, + sprintf('No files matched criteria (%s %s)', $this->compareOperand, date('c', $cutoffTime)) + ); + } + + } + + /** + * @return Array Of absolute file paths + */ + protected function getFiles() { + return glob($this->path); + } + +} \ No newline at end of file diff --git a/code/checks/FileWriteableCheck.php b/code/checks/FileWriteableCheck.php new file mode 100644 index 0000000..3d3ae98 --- /dev/null +++ b/code/checks/FileWriteableCheck.php @@ -0,0 +1,58 @@ +path = $path; + } + + function check() { + if($this->path[0] == '/') $filename = $this->path; + else $filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path); + + if(file_exists($filename)) $isWriteable = is_writeable($filename); + else $isWriteable = is_writeable(dirname($filename)); + + if(!$isWriteable) { + if(function_exists('posix_getgroups')) { + $userID = posix_geteuid(); + $user = posix_getpwuid($userID); + + $currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename) ); + $currentOwner = posix_getpwuid($currentOwnerID); + + $message = "User '$user[name]' needs to be able to write to this file:\n$filename\n\nThe file is currently owned by '$currentOwner[name]'. "; + + if($user['name'] == $currentOwner['name']) { + $message .= "We recommend that you make the file writeable."; + } else { + + $groups = posix_getgroups(); + $groupList = array(); + foreach($groups as $group) { + $groupInfo = posix_getgrgid($group); + if(in_array($currentOwner['name'], $groupInfo['members'])) $groupList[] = $groupInfo['name']; + } + if($groupList) { + $message .= " We recommend that you make the file group-writeable and change the group to one of these groups:\n - ". implode("\n - ", $groupList) + . "\n\nFor example:\nchmod g+w $filename\nchgrp " . $groupList[0] . " $filename"; + } else { + $message .= " There is no user-group that contains both the web-server user and the owner of this file. Change the ownership of the file, create a new group, or temporarily make the file writeable by everyone during the install process."; + } + } + + } else { + $message .= "The webserver user needs to be able to write to this file:\n$filename"; + } + + return array(EnvironmentCheck::ERROR, $message); + } + + return array(EnvironmentCheck::OK,''); + } +} \ No newline at end of file diff --git a/code/checks/HasClassCheck.php b/code/checks/HasClassCheck.php new file mode 100644 index 0000000..db372fa --- /dev/null +++ b/code/checks/HasClassCheck.php @@ -0,0 +1,18 @@ +className = $className; + } + + function check() { + if(class_exists($this->className)) return array(EnvironmentCheck::OK, 'Class ' . $this->className.' exists'); + else return array(EnvironmentCheck::ERROR, 'Class ' . $this->className.' doesn\'t exist'); + } +} \ No newline at end of file diff --git a/code/checks/HasFunctionCheck.php b/code/checks/HasFunctionCheck.php new file mode 100644 index 0000000..2f3d78b --- /dev/null +++ b/code/checks/HasFunctionCheck.php @@ -0,0 +1,18 @@ +functionName = $functionName; + } + + function check() { + if(function_exists($this->functionName)) return array(EnvironmentCheck::OK, $this->functionName.'() exists'); + else return array(EnvironmentCheck::ERROR, $this->functionName.'() doesn\'t exist'); + } +} \ No newline at end of file diff --git a/code/checks/SMTPConnectCheck.php b/code/checks/SMTPConnectCheck.php new file mode 100644 index 0000000..d3dfb8c --- /dev/null +++ b/code/checks/SMTPConnectCheck.php @@ -0,0 +1,58 @@ +host = ($host) ? $host : ini_get('SMTP'); + if(!$this->host) $this->host = 'localhost'; + + $this->port = ($port) ? $port : ini_get('smtp_port'); + if(!$this->port) $this->port = 25; + + $this->timeout = $timeout; + } + + function check() { + $f = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout); + if(!$f) { + return array( + EnvironmentCheck::ERROR, + sprintf("Couldn't connect to SMTP on %s:%s (Error: %s %s)", $this->host, $this->port, $errno, $errstr) + ); + } + + fwrite($f, "HELO its_me\r\n"); + $response = fread($f, 26); + if(substr($response, 0, 3) != '220') { + return array( + EnvironmentCheck::ERROR, + sprintf("Invalid mail server response: %s", $response) + ); + } + + return array(EnvironmentCheck::OK, ''); + + } +} \ No newline at end of file diff --git a/code/checks/URLCheck.php b/code/checks/URLCheck.php new file mode 100644 index 0000000..6db586b --- /dev/null +++ b/code/checks/URLCheck.php @@ -0,0 +1,42 @@ +url = $url; + $this->testString = $testString; + } + + function check() { + $response = Director::test($this->url); + + if($response->getStatusCode() != 200) { + return array( + EnvironmentCheck::ERROR, + sprintf('Error retrieving "%s" (Code: %d)', $this->url, $response->getStatusCode()) + ); + + } else if($this->testString && (strpos($response->getBody(), $this->testString) === false)) { + return array( + EnvironmentCheck::WARNING, + sprintf('Success retrieving "%s", but string "%s" not found', $this->url, $testString) + ); + + } else { + return array( + EnvironmentCheck::OK, + sprintf('Success retrieving "%s"', $this->url) + ); + } + } +} \ No newline at end of file