mirror of
https://github.com/silverstripe/silverstripe-environmentcheck
synced 2024-10-22 17:05:40 +02:00
ENHANCEMENT Added ExternalURLCheck, FileAgeCheck, SMTPConnectCheck
This commit is contained in:
parent
0946addf7e
commit
908a66b4ef
@ -31,6 +31,12 @@ Register checks in your own `_config.php` - see the `_config.php` in this module
|
|||||||
* `HasClassCheck`: Check that the given class exists.
|
* `HasClassCheck`: Check that the given class exists.
|
||||||
This can be used to check that PHP modules or features are installed.
|
This can be used to check that PHP modules or features are installed.
|
||||||
* `FileWriteableCheck`: Check that the given file is writeable.
|
* `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
|
## 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 mode for examples.
|
To add more checks, you should put additional `EnvironmentCheckSuite::register` calls into your `_config.php`. See the `_config.php` file of this mode for examples.
|
||||||
|
110
code/checks/ExternalURLCheck.php
Normal file
110
code/checks/ExternalURLCheck.php
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Checks that one or more URLs are reachable via HTTP.
|
||||||
|
* Note that the HTTP connectivity can just be verified from the server to the remote URL,
|
||||||
|
* it can still fail if the URL in question is requested by the client, e.g. through an iframe.
|
||||||
|
*
|
||||||
|
* Requires curl to present, so ensure to check it before with the following:
|
||||||
|
* <code>EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");</code>
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
106
code/checks/FileAgeCheck.php
Normal file
106
code/checks/FileAgeCheck.php
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* Does NOT check for existence of a file (will silently fail).
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* // Checks that Requirements::combine_files() has regenerated files in the last 24h
|
||||||
|
* EnvironmentCheckSuite::register(
|
||||||
|
* 'check',
|
||||||
|
* 'FileAgeCheck("' . ASSETS_PATH . '/_combined_files/*.js' . '", "-1 day", '>', " . 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
58
code/checks/SMTPConnectCheck.php
Normal file
58
code/checks/SMTPConnectCheck.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Checks if the SMTP connection configured through PHP.ini works as expected.
|
||||||
|
* Only checks socket connection with HELO command, not actually sending the email.
|
||||||
|
*/
|
||||||
|
class SMTPConnectCheck implements EnvironmentCheck {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var String
|
||||||
|
*/
|
||||||
|
protected $host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Int
|
||||||
|
*/
|
||||||
|
protected $port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Int In seconds
|
||||||
|
*/
|
||||||
|
protected $timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param String
|
||||||
|
* @param Int
|
||||||
|
*/
|
||||||
|
function __construct($host = null, $port = null, $timeout = 15) {
|
||||||
|
$this->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, '');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user