Converted to PSR-2

This commit is contained in:
helpfulrobot 2015-11-21 19:18:35 +13:00
parent d6a65e1614
commit 5f1f1fcd53
24 changed files with 1429 additions and 1293 deletions

View File

@ -1,37 +1,39 @@
<?php <?php
class DevCheckController extends Controller { class DevCheckController extends Controller
/** {
* @var array /**
*/ * @var array
public static $allowed_actions = array( */
'index' public static $allowed_actions = array(
); 'index'
);
/** /**
* Permission code to check for access to this controller. * Permission code to check for access to this controller.
* *
* @var string * @var string
*/ */
private static $permission = 'ADMIN'; private static $permission = 'ADMIN';
/** /**
* @param SS_HTTPRequest $request * @param SS_HTTPRequest $request
* *
* @return EnvironmentChecker * @return EnvironmentChecker
* *
* @throws SS_HTTPResponse_Exception * @throws SS_HTTPResponse_Exception
*/ */
function index($request) { public function index($request)
$suite = 'check'; {
$suite = 'check';
if ($name = $request->param('Suite')) { if ($name = $request->param('Suite')) {
$suite = $name; $suite = $name;
} }
$checker = new EnvironmentChecker($suite, 'Environment status'); $checker = new EnvironmentChecker($suite, 'Environment status');
$checker->init($this->config()->permission); $checker->init($this->config()->permission);
return $checker; return $checker;
} }
} }

View File

@ -1,25 +1,27 @@
<?php <?php
class DevHealthController extends Controller { class DevHealthController extends Controller
/** {
* @var array /**
*/ * @var array
public static $allowed_actions = array( */
'index' public static $allowed_actions = array(
); 'index'
);
/** /**
* @return EnvironmentChecker * @return EnvironmentChecker
* *
* @throws SS_HTTPResponse_Exception * @throws SS_HTTPResponse_Exception
*/ */
function index() { public function index()
// health check does not require permission to run {
// health check does not require permission to run
$checker = new EnvironmentChecker('health', 'Site health'); $checker = new EnvironmentChecker('health', 'Site health');
$checker->init(''); $checker->init('');
$checker->setErrorCode(404); $checker->setErrorCode(404);
return $checker; return $checker;
} }
} }

View File

@ -14,26 +14,27 @@
* - Are the right PHP modules installed? * - Are the right PHP modules installed?
* - Are the file permissions correct? * - Are the file permissions correct?
*/ */
interface EnvironmentCheck { interface EnvironmentCheck
/** {
* @var int /**
*/ * @var int
const ERROR = 3; */
const ERROR = 3;
/** /**
* @var int * @var int
*/ */
const WARNING = 2; const WARNING = 2;
/** /**
* @var int * @var int
*/ */
const OK = 1; const OK = 1;
/** /**
* @return array Result with 'status' and 'message' keys. * @return array Result with 'status' and 'message' keys.
* *
* Status is EnvironmentCheck::ERROR, EnvironmentCheck::WARNING, or EnvironmentCheck::OK. * Status is EnvironmentCheck::ERROR, EnvironmentCheck::WARNING, or EnvironmentCheck::OK.
*/ */
function check(); public function check();
} }

View File

@ -19,260 +19,284 @@
* *
* $result = EnvironmentCheckSuite::inst('health')->run(); * $result = EnvironmentCheckSuite::inst('health')->run();
*/ */
class EnvironmentCheckSuite extends Object { class EnvironmentCheckSuite extends Object
/** {
* Name of this suite. /**
* * Name of this suite.
* @var string *
*/ * @var string
protected $name; */
protected $name;
/** /**
* @var array * @var array
*/ */
protected $checks = array(); protected $checks = array();
/** /**
* Associative array of named checks registered via the config system. Each check should specify: * Associative array of named checks registered via the config system. Each check should specify:
* - definition (e.g. 'MyHealthCheck("my param")') * - definition (e.g. 'MyHealthCheck("my param")')
* - title (e.g. 'Is my feature working?') * - title (e.g. 'Is my feature working?')
* - state (setting this to 'disabled' will cause suites to skip this check entirely. * - state (setting this to 'disabled' will cause suites to skip this check entirely.
* *
* @var array * @var array
*/ */
private static $registered_checks = array(); private static $registered_checks = array();
/** /**
* Associative array of named suites registered via the config system. Each suite should enumerate * Associative array of named suites registered via the config system. Each suite should enumerate
* named checks that have been configured in 'registered_checks'. * named checks that have been configured in 'registered_checks'.
* *
* @var array * @var array
*/ */
private static $registered_suites = array(); private static $registered_suites = array();
/** /**
* Load checks for this suite from the configuration system. This is an alternative to the * Load checks for this suite from the configuration system. This is an alternative to the
* EnvironmentCheckSuite::register - both can be used, checks will be appended to the suite. * EnvironmentCheckSuite::register - both can be used, checks will be appended to the suite.
* *
* @param string $suiteName The name of this suite. * @param string $suiteName The name of this suite.
*/ */
public function __construct($suiteName) { public function __construct($suiteName)
parent::__construct(); {
parent::__construct();
if (empty($this->config()->registered_suites[$suiteName])) { if (empty($this->config()->registered_suites[$suiteName])) {
// Not registered via config system, but it still may be configured later via self::register. // Not registered via config system, but it still may be configured later via self::register.
return; return;
} }
foreach ($this->config()->registered_suites[$suiteName] as $checkName) { foreach ($this->config()->registered_suites[$suiteName] as $checkName) {
if (empty($this->config()->registered_checks[$checkName])) { if (empty($this->config()->registered_checks[$checkName])) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
"Bad EnvironmentCheck: '$checkName' - the named check has not been registered." "Bad EnvironmentCheck: '$checkName' - the named check has not been registered."
); );
} }
$check = $this->config()->registered_checks[$checkName]; $check = $this->config()->registered_checks[$checkName];
// Existing named checks can be disabled by setting their 'state' to 'disabled'. // Existing named checks can be disabled by setting their 'state' to 'disabled'.
// This is handy for disabling checks mandated by modules. // This is handy for disabling checks mandated by modules.
if (!empty($check['state']) && $check['state']==='disabled') continue; if (!empty($check['state']) && $check['state']==='disabled') {
continue;
}
// Add the check to this suite. // Add the check to this suite.
$this->push($check['definition'], $check['title']); $this->push($check['definition'], $check['title']);
} }
} }
/** /**
* Run this test suite and return the result code of the worst result. * Run this test suite and return the result code of the worst result.
* *
* @return int * @return int
*/ */
public function run() { public function run()
$result = new EnvironmentCheckSuiteResult(); {
$result = new EnvironmentCheckSuiteResult();
foreach($this->checkInstances() as $check) { foreach ($this->checkInstances() as $check) {
list($checkClass, $checkTitle) = $check; list($checkClass, $checkTitle) = $check;
try { try {
list($status, $message) = $checkClass->check(); list($status, $message) = $checkClass->check();
// If the check fails, register that as an error // If the check fails, register that as an error
} catch(Exception $e) { } catch (Exception $e) {
$status = EnvironmentCheck::ERROR; $status = EnvironmentCheck::ERROR;
$message = $e->getMessage(); $message = $e->getMessage();
} }
$result->addResult($status, $message, $checkTitle); $result->addResult($status, $message, $checkTitle);
} }
return $result; return $result;
} }
/** /**
* Get instances of all the environment checks. * Get instances of all the environment checks.
* *
* @return array * @return array
*/ */
protected function checkInstances() { protected function checkInstances()
$output = array(); {
foreach($this->checks as $check) { $output = array();
list($checkClass, $checkTitle) = $check; foreach ($this->checks as $check) {
if(is_string($checkClass)) { list($checkClass, $checkTitle) = $check;
$checkInst = Object::create_from_string($checkClass); if (is_string($checkClass)) {
if($checkInst instanceof EnvironmentCheck) { $checkInst = Object::create_from_string($checkClass);
$output[] = array($checkInst, $checkTitle); if ($checkInst instanceof EnvironmentCheck) {
} else { $output[] = array($checkInst, $checkTitle);
throw new InvalidArgumentException("Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck"); } else {
} throw new InvalidArgumentException("Bad EnvironmentCheck: '$checkClass' - the named class doesn't implement EnvironmentCheck");
} else if($checkClass instanceof EnvironmentCheck) { }
$output[] = array($checkClass, $checkTitle); } elseif ($checkClass instanceof EnvironmentCheck) {
} else { $output[] = array($checkClass, $checkTitle);
throw new InvalidArgumentException("Bad EnvironmentCheck: " . var_export($check, true)); } else {
} throw new InvalidArgumentException("Bad EnvironmentCheck: " . var_export($check, true));
} }
return $output; }
} return $output;
}
/** /**
* Add a check to this suite. * Add a check to this suite.
* *
* @param mixed $check * @param mixed $check
* @param string $title * @param string $title
*/ */
public function push($check, $title = null) { public function push($check, $title = null)
if(!$title) { {
$title = is_string($check) ? $check : get_class($check); if (!$title) {
} $title = is_string($check) ? $check : get_class($check);
$this->checks[] = array($check, $title); }
} $this->checks[] = array($check, $title);
}
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
/** /**
* @var array * @var array
*/ */
protected static $instances = array(); protected static $instances = array();
/** /**
* Return a named instance of EnvironmentCheckSuite. * Return a named instance of EnvironmentCheckSuite.
* *
* @param string $name * @param string $name
* *
* @return EnvironmentCheckSuite * @return EnvironmentCheckSuite
*/ */
static function inst($name) { public static function inst($name)
if(!isset(self::$instances[$name])) self::$instances[$name] = new EnvironmentCheckSuite($name); {
return self::$instances[$name]; if (!isset(self::$instances[$name])) {
} self::$instances[$name] = new EnvironmentCheckSuite($name);
}
return self::$instances[$name];
}
/** /**
* Register a check against the named check suite. * Register a check against the named check suite.
* *
* @param string|array $names * @param string|array $names
* @param EnvironmentCheck $check * @param EnvironmentCheck $check
* @param string|array * @param string|array
*/ */
static function register($names, $check, $title = null) { public static function register($names, $check, $title = null)
if(!is_array($names)) $names = array($names); {
foreach($names as $name) self::inst($name)->push($check, $title); if (!is_array($names)) {
} $names = array($names);
}
foreach ($names as $name) {
self::inst($name)->push($check, $title);
}
}
/** /**
* Unregisters all checks. * Unregisters all checks.
*/ */
static function reset() { public static function reset()
self::$instances = array(); {
} self::$instances = array();
}
} }
/** /**
* A single set of results from running an EnvironmentCheckSuite * A single set of results from running an EnvironmentCheckSuite
*/ */
class EnvironmentCheckSuiteResult extends ViewableData { class EnvironmentCheckSuiteResult extends ViewableData
/** {
* @var ArrayList /**
*/ * @var ArrayList
protected $details; */
protected $details;
/** /**
* @var int * @var int
*/ */
protected $worst = 0; protected $worst = 0;
function __construct() { public function __construct()
parent::__construct(); {
$this->details = new ArrayList(); parent::__construct();
} $this->details = new ArrayList();
}
/** /**
* @param int $status * @param int $status
* @param string $message * @param string $message
* @param string $checkIdentifier * @param string $checkIdentifier
*/ */
function addResult($status, $message, $checkIdentifier) { public function addResult($status, $message, $checkIdentifier)
$this->details->push(new ArrayData(array( {
'Check' => $checkIdentifier, $this->details->push(new ArrayData(array(
'Status' => $this->statusText($status), 'Check' => $checkIdentifier,
'StatusCode' => $status, 'Status' => $this->statusText($status),
'Message' => $message, 'StatusCode' => $status,
))); 'Message' => $message,
)));
$this->worst = max($this->worst, $status); $this->worst = max($this->worst, $status);
} }
/** /**
* Returns true if there are no errors. * Returns true if there are no errors.
* *
* @return bool * @return bool
*/ */
public function ShouldPass() { public function ShouldPass()
return $this->worst <= EnvironmentCheck::WARNING; {
} return $this->worst <= EnvironmentCheck::WARNING;
}
/** /**
* Returns overall (i.e. worst) status as a string. * Returns overall (i.e. worst) status as a string.
* *
* @return string * @return string
*/ */
function Status() { public function Status()
return $this->statusText($this->worst); {
} return $this->statusText($this->worst);
}
/** /**
* Returns detailed status information about each check. * Returns detailed status information about each check.
* *
* @return ArrayList * @return ArrayList
*/ */
function Details() { public function Details()
return $this->details; {
} return $this->details;
}
/** /**
* Convert the final result status and details to JSON. * Convert the final result status and details to JSON.
* *
* @return string * @return string
*/ */
function toJSON() { public function toJSON()
$result = array( {
'Status' => $this->Status(), $result = array(
'ShouldPass' => $this->ShouldPass(), 'Status' => $this->Status(),
'Checks' => array() 'ShouldPass' => $this->ShouldPass(),
); 'Checks' => array()
foreach($this->details as $detail) { );
$result['Checks'][] = $detail->toMap(); foreach ($this->details as $detail) {
} $result['Checks'][] = $detail->toMap();
return json_encode($result); }
} return json_encode($result);
}
/** /**
* Return a text version of a status code. * Return a text version of a status code.
* *
* @return string * @return string
*/ */
protected function statusText($status) { protected function statusText($status)
switch($status) { {
case EnvironmentCheck::ERROR: return "ERROR"; switch ($status) {
case EnvironmentCheck::WARNING: return "WARNING"; case EnvironmentCheck::ERROR: return "ERROR";
case EnvironmentCheck::OK: return "OK"; case EnvironmentCheck::WARNING: return "WARNING";
case 0: return "NO CHECKS"; case EnvironmentCheck::OK: return "OK";
default: throw new InvalidArgumentException("Bad environment check status '$status'"); case 0: return "NO CHECKS";
} default: throw new InvalidArgumentException("Bad environment check status '$status'");
} }
}
} }

View File

@ -3,272 +3,290 @@
/** /**
* Provides an interface for checking the given EnvironmentCheckSuite. * Provides an interface for checking the given EnvironmentCheckSuite.
*/ */
class EnvironmentChecker extends RequestHandler { class EnvironmentChecker extends RequestHandler
/** {
* @var array /**
*/ * @var array
private static $url_handlers = array( */
'' => 'index', private static $url_handlers = array(
); '' => 'index',
);
/** /**
* @var string * @var string
*/ */
protected $checkSuiteName; protected $checkSuiteName;
/** /**
* @var string * @var string
*/ */
protected $title; protected $title;
/** /**
* @var int * @var int
*/ */
protected $errorCode = 500; protected $errorCode = 500;
/** /**
* @var null|string * @var null|string
*/ */
private static $to_email_address = null; private static $to_email_address = null;
/** /**
* @var null|string * @var null|string
*/ */
private static $from_email_address = null; private static $from_email_address = null;
/** /**
* @var bool * @var bool
*/ */
private static $email_results = false; private static $email_results = false;
/** /**
* @var bool Log results via {@link SS_Log} * @var bool Log results via {@link SS_Log}
*/ */
private static $log_results_warning = false; private static $log_results_warning = false;
/** /**
* @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::WARN * @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::WARN
*/ */
private static $log_results_warning_level = 4; private static $log_results_warning_level = 4;
/** /**
* @var bool Log results via {@link SS_Log} * @var bool Log results via {@link SS_Log}
*/ */
private static $log_results_error = false; private static $log_results_error = false;
/** /**
* @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::ALERT * @var int Maps to {@link Zend_Log} levels. Defaults to Zend_Log::ALERT
*/ */
private static $log_results_error_level = 1; private static $log_results_error_level = 1;
/** /**
* @param string $checkSuiteName * @param string $checkSuiteName
* @param string $title * @param string $title
*/ */
function __construct($checkSuiteName, $title) { public function __construct($checkSuiteName, $title)
parent::__construct(); {
parent::__construct();
$this->checkSuiteName = $checkSuiteName; $this->checkSuiteName = $checkSuiteName;
$this->title = $title; $this->title = $title;
} }
/** /**
* @param string $permission * @param string $permission
* *
* @throws SS_HTTPResponse_Exception * @throws SS_HTTPResponse_Exception
*/ */
function init($permission = 'ADMIN') { public function init($permission = 'ADMIN')
// if the environment supports it, provide a basic auth challenge and see if it matches configured credentials {
if(defined('ENVCHECK_BASICAUTH_USERNAME') && defined('ENVCHECK_BASICAUTH_PASSWORD')) { // if the environment supports it, provide a basic auth challenge and see if it matches configured credentials
if(isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { if (defined('ENVCHECK_BASICAUTH_USERNAME') && defined('ENVCHECK_BASICAUTH_PASSWORD')) {
// authenticate the input user/pass with the configured credentials if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) {
if( // authenticate the input user/pass with the configured credentials
!( if (
$_SERVER['PHP_AUTH_USER'] == ENVCHECK_BASICAUTH_USERNAME !(
&& $_SERVER['PHP_AUTH_PW'] == ENVCHECK_BASICAUTH_PASSWORD $_SERVER['PHP_AUTH_USER'] == ENVCHECK_BASICAUTH_USERNAME
) && $_SERVER['PHP_AUTH_PW'] == ENVCHECK_BASICAUTH_PASSWORD
) { )
$response = new SS_HTTPResponse(null, 401); ) {
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\""); $response = new SS_HTTPResponse(null, 401);
// Exception is caught by RequestHandler->handleRequest() and will halt further execution $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
$e = new SS_HTTPResponse_Exception(null, 401); // Exception is caught by RequestHandler->handleRequest() and will halt further execution
$e->setResponse($response); $e = new SS_HTTPResponse_Exception(null, 401);
throw $e; $e->setResponse($response);
} throw $e;
} else { }
$response = new SS_HTTPResponse(null, 401); } else {
$response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\""); $response = new SS_HTTPResponse(null, 401);
// Exception is caught by RequestHandler->handleRequest() and will halt further execution $response->addHeader('WWW-Authenticate', "Basic realm=\"Environment check\"");
$e = new SS_HTTPResponse_Exception(null, 401); // Exception is caught by RequestHandler->handleRequest() and will halt further execution
$e->setResponse($response); $e = new SS_HTTPResponse_Exception(null, 401);
throw $e; $e->setResponse($response);
} throw $e;
} else { }
if(!$this->canAccess(null, $permission)) return $this->httpError(403); } else {
} if (!$this->canAccess(null, $permission)) {
} return $this->httpError(403);
}
}
}
/** /**
* @param null|int|Member $member * @param null|int|Member $member
* @param string $permission * @param string $permission
* *
* @return bool * @return bool
* *
* @throws SS_HTTPResponse_Exception * @throws SS_HTTPResponse_Exception
*/ */
function canAccess($member = null, $permission = "ADMIN") { public function canAccess($member = null, $permission = "ADMIN")
if(!$member) { {
$member = Member::currentUser(); if (!$member) {
} $member = Member::currentUser();
}
if(!$member) { if (!$member) {
$member = BasicAuth::requireLogin('Environment Checker', $permission, false); $member = BasicAuth::requireLogin('Environment Checker', $permission, false);
} }
// We allow access to this controller regardless of live-status or ADMIN permission only // We allow access to this controller regardless of live-status or ADMIN permission only
// if on CLI. Access to this controller is always allowed in "dev-mode", or of the user is ADMIN. // if on CLI. Access to this controller is always allowed in "dev-mode", or of the user is ADMIN.
if( if (
Director::isDev() Director::isDev()
|| Director::is_cli() || Director::is_cli()
|| empty($permission) || empty($permission)
|| Permission::checkMember($member, $permission) || Permission::checkMember($member, $permission)
) { ) {
return true; return true;
} }
// Extended access checks. // Extended access checks.
// "Veto" style, return NULL to abstain vote. // "Veto" style, return NULL to abstain vote.
$canExtended = null; $canExtended = null;
$results = $this->extend('canAccess', $member); $results = $this->extend('canAccess', $member);
if($results && is_array($results)) { if ($results && is_array($results)) {
if(!min($results)) return false; if (!min($results)) {
else return true; return false;
} } else {
return true;
}
}
return false; return false;
} }
/** /**
* @return SS_HTTPResponse * @return SS_HTTPResponse
*/ */
function index() { public function index()
$response = new SS_HTTPResponse; {
$result = EnvironmentCheckSuite::inst($this->checkSuiteName)->run(); $response = new SS_HTTPResponse;
$result = EnvironmentCheckSuite::inst($this->checkSuiteName)->run();
if(!$result->ShouldPass()) { if (!$result->ShouldPass()) {
$response->setStatusCode($this->errorCode); $response->setStatusCode($this->errorCode);
} }
$resultText = $result->customise(array( $resultText = $result->customise(array(
"URL" => Director::absoluteBaseURL(), "URL" => Director::absoluteBaseURL(),
"Title" => $this->title, "Title" => $this->title,
"Name" => $this->checkSuiteName, "Name" => $this->checkSuiteName,
"ErrorCode" => $this->errorCode, "ErrorCode" => $this->errorCode,
))->renderWith("EnvironmentChecker"); ))->renderWith("EnvironmentChecker");
if ($this->config()->email_results && !$result->ShouldPass()) { if ($this->config()->email_results && !$result->ShouldPass()) {
$email = new Email($this->config()->from_email_address, $this->config()->to_email_address, $this->title, $resultText); $email = new Email($this->config()->from_email_address, $this->config()->to_email_address, $this->title, $resultText);
$email->send(); $email->send();
} }
// Optionally log errors and warnings individually // Optionally log errors and warnings individually
foreach($result->Details() as $detail) { foreach ($result->Details() as $detail) {
if($this->config()->log_results_warning && $detail->StatusCode == EnvironmentCheck::WARNING) { if ($this->config()->log_results_warning && $detail->StatusCode == EnvironmentCheck::WARNING) {
$this->log( $this->log(
sprintf('EnvironmentChecker warning at "%s" check. Message: %s', $detail->Check, $detail->Message), sprintf('EnvironmentChecker warning at "%s" check. Message: %s', $detail->Check, $detail->Message),
$this->config()->log_results_warning_level $this->config()->log_results_warning_level
); );
} elseif($this->config()->log_results_error && $detail->StatusCode == EnvironmentCheck::ERROR) { } elseif ($this->config()->log_results_error && $detail->StatusCode == EnvironmentCheck::ERROR) {
$this->log( $this->log(
sprintf('EnvironmentChecker error at "%s" check. Message: %s', $detail->Check, $detail->Message), sprintf('EnvironmentChecker error at "%s" check. Message: %s', $detail->Check, $detail->Message),
$this->config()->log_results_error_level $this->config()->log_results_error_level
); );
} }
} }
// output the result as JSON if requested // output the result as JSON if requested
if( if (
$this->getRequest()->getExtension() == 'json' $this->getRequest()->getExtension() == 'json'
|| strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false || strpos($this->getRequest()->getHeader('Accept'), 'application/json') !== false
) { ) {
$response->setBody($result->toJSON()); $response->setBody($result->toJSON());
$response->addHeader('Content-Type', 'application/json'); $response->addHeader('Content-Type', 'application/json');
return $response; return $response;
} }
$response->setBody($resultText); $response->setBody($resultText);
return $response; return $response;
} }
/** /**
* @param string $message * @param string $message
* @param int $level * @param int $level
*/ */
public function log($message, $level) { public function log($message, $level)
SS_Log::log($message, $level); {
} SS_Log::log($message, $level);
}
/** /**
* Set the HTTP status code that should be returned when there's an error. * Set the HTTP status code that should be returned when there's an error.
* *
* @param int $errorCode * @param int $errorCode
*/ */
function setErrorCode($errorCode) { public function setErrorCode($errorCode)
$this->errorCode = $errorCode; {
} $this->errorCode = $errorCode;
}
/** /**
* @deprecated * @deprecated
* @param string $from * @param string $from
*/ */
public static function set_from_email_address($from) { public static function set_from_email_address($from)
Deprecation::notice('2.0', 'Use config API instead'); {
Config::inst()->update('EnvironmentChecker', 'from_email_address', $from); Deprecation::notice('2.0', 'Use config API instead');
} Config::inst()->update('EnvironmentChecker', 'from_email_address', $from);
}
/** /**
* @deprecated * @deprecated
* @return null|string * @return null|string
*/ */
public static function get_from_email_address() { public static function get_from_email_address()
Deprecation::notice('2.0', 'Use config API instead'); {
return Config::inst()->get('EnvironmentChecker', 'from_email_address'); Deprecation::notice('2.0', 'Use config API instead');
} return Config::inst()->get('EnvironmentChecker', 'from_email_address');
}
/** /**
* @deprecated * @deprecated
* @param string $to * @param string $to
*/ */
public static function set_to_email_address($to) { public static function set_to_email_address($to)
Deprecation::notice('2.0', 'Use config API instead'); {
Config::inst()->update('EnvironmentChecker', 'to_email_address', $to); Deprecation::notice('2.0', 'Use config API instead');
} Config::inst()->update('EnvironmentChecker', 'to_email_address', $to);
}
/** /**
* @deprecated * @deprecated
* @return null|string * @return null|string
*/ */
public static function get_to_email_address() { public static function get_to_email_address()
Deprecation::notice('2.0', 'Use config API instead'); {
return Config::inst()->get('EnvironmentChecker', 'to_email_address'); Deprecation::notice('2.0', 'Use config API instead');
} return Config::inst()->get('EnvironmentChecker', 'to_email_address');
}
/** /**
* @deprecated * @deprecated
* @param bool $results * @param bool $results
*/ */
public static function set_email_results($results) { public static function set_email_results($results)
Deprecation::notice('2.0', 'Use config API instead'); {
Config::inst()->update('EnvironmentChecker', 'email_results', $results); Deprecation::notice('2.0', 'Use config API instead');
} Config::inst()->update('EnvironmentChecker', 'email_results', $results);
}
/** /**
* @deprecated * @deprecated
* @return bool * @return bool
*/ */
public static function get_email_results() { public static function get_email_results()
Deprecation::notice('2.0', 'Use config API instead'); {
return Config::inst()->get('EnvironmentChecker', 'email_results'); Deprecation::notice('2.0', 'Use config API instead');
} return Config::inst()->get('EnvironmentChecker', 'email_results');
}
} }

View File

@ -4,34 +4,37 @@
* Check that the connection to the database is working, by ensuring that the table exists and that * Check that the connection to the database is working, by ensuring that the table exists and that
* the table contains some records. * the table contains some records.
*/ */
class DatabaseCheck implements EnvironmentCheck { class DatabaseCheck implements EnvironmentCheck
protected $checkTable; {
protected $checkTable;
/** /**
* By default, Member will be checked. * By default, Member will be checked.
* *
* @param string $checkTable * @param string $checkTable
*/ */
function __construct($checkTable = "Member") { public function __construct($checkTable = "Member")
$this->checkTable = $checkTable; {
} $this->checkTable = $checkTable;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
if(!DB::getConn()->hasTable($this->checkTable)) { {
return array(EnvironmentCheck::ERROR, "$this->checkTable not present in the database"); if (!DB::getConn()->hasTable($this->checkTable)) {
} return array(EnvironmentCheck::ERROR, "$this->checkTable not present in the database");
}
$count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value(); $count = DB::query("SELECT COUNT(*) FROM \"$this->checkTable\"")->value();
if($count > 0) { if ($count > 0) {
return array(EnvironmentCheck::OK, ""); return array(EnvironmentCheck::OK, "");
} else { } else {
return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records"); return array(EnvironmentCheck::WARNING, "$this->checkTable queried ok but has no records");
} }
} }
} }

View File

@ -8,109 +8,120 @@
* Requires curl to present, so ensure to check it before with the following: * 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> * <code>EnvironmentCheckSuite::register('check', 'HasFunctionCheck("curl_init")', "Does PHP have CURL support?");</code>
*/ */
class ExternalURLCheck implements EnvironmentCheck { class ExternalURLCheck implements EnvironmentCheck
/** {
* @var array /**
*/ * @var array
protected $urls = array(); */
protected $urls = array();
/** /**
* @var Int Timeout in seconds. * @var Int Timeout in seconds.
*/ */
protected $timeout; protected $timeout;
/** /**
* @param string $urls Space-separated list of absolute URLs. * @param string $urls Space-separated list of absolute URLs.
* @param int $timeout * @param int $timeout
*/ */
function __construct($urls, $timeout = 15) { public function __construct($urls, $timeout = 15)
if($urls) $this->urls = explode(' ', $urls); {
$this->timeout = $timeout; if ($urls) {
} $this->urls = explode(' ', $urls);
}
$this->timeout = $timeout;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
$urls = $this->getURLs(); {
$urls = $this->getURLs();
$chs = array(); $chs = array();
foreach($urls as $url) { foreach ($urls as $url) {
$ch = curl_init(); $ch = curl_init();
$chs[] = $ch; $chs[] = $ch;
curl_setopt_array($ch, $this->getCurlOpts($url)); curl_setopt_array($ch, $this->getCurlOpts($url));
} }
// Parallel execution for faster performance // Parallel execution for faster performance
$mh = curl_multi_init(); $mh = curl_multi_init();
foreach($chs as $ch) curl_multi_add_handle($mh,$ch); foreach ($chs as $ch) {
curl_multi_add_handle($mh, $ch);
}
$active = null; $active = null;
// Execute the handles // Execute the handles
do { do {
$mrc = curl_multi_exec($mh, $active); $mrc = curl_multi_exec($mh, $active);
curl_multi_select($mh); curl_multi_select($mh);
} while ($active > 0); } while ($active > 0);
while ($active && $mrc == CURLM_OK) { while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) { if (curl_multi_select($mh) != -1) {
do { do {
$mrc = curl_multi_exec($mh, $active); $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM); } while ($mrc == CURLM_CALL_MULTI_PERFORM);
} }
} }
$hasError = false; $hasError = false;
$msgs = array(); $msgs = array();
foreach($chs as $ch) { foreach ($chs as $ch) {
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); $url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if(curl_errno($ch) || $code >= 400) { if (curl_errno($ch) || $code >= 400) {
$hasError = true; $hasError = true;
$msgs[] = sprintf( $msgs[] = sprintf(
'Error retrieving "%s": %s (Code: %s)', 'Error retrieving "%s": %s (Code: %s)',
$url, $url,
curl_error($ch), curl_error($ch),
$code $code
); );
} else { } else {
$msgs[] = sprintf( $msgs[] = sprintf(
'Success retrieving "%s" (Code: %s)', 'Success retrieving "%s" (Code: %s)',
$url, $url,
$code $code
); );
} }
} }
// Close the handles // Close the handles
foreach($chs as $ch) curl_multi_remove_handle($mh, $ch); foreach ($chs as $ch) {
curl_multi_close($mh); curl_multi_remove_handle($mh, $ch);
}
curl_multi_close($mh);
if($hasError) { if ($hasError) {
return array(EnvironmentCheck::ERROR, implode(', ', $msgs)); return array(EnvironmentCheck::ERROR, implode(', ', $msgs));
} else { } else {
return array(EnvironmentCheck::OK, implode(', ', $msgs)); return array(EnvironmentCheck::OK, implode(', ', $msgs));
} }
} }
/** /**
* @return array * @return array
*/ */
protected function getCurlOpts($url) { protected function getCurlOpts($url)
return array( {
CURLOPT_URL => $url, return array(
CURLOPT_HEADER => 0, CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => 1, CURLOPT_HEADER => 0,
CURLOPT_FAILONERROR => 1, CURLOPT_RETURNTRANSFER => 1,
CURLOPT_TIMEOUT => $this->timeout, CURLOPT_FAILONERROR => 1,
); CURLOPT_TIMEOUT => $this->timeout,
} );
}
/** /**
* @return array * @return array
*/ */
protected function getURLs() { protected function getURLs()
return $this->urls; {
} return $this->urls;
}
} }

View File

@ -19,160 +19,165 @@
* 'Check a calculator.json exists only' * 'Check a calculator.json exists only'
* ); * );
*/ */
class FileAccessibilityAndValidationCheck implements EnvironmentCheck { class FileAccessibilityAndValidationCheck implements EnvironmentCheck
/** {
* @var int /**
*/ * @var int
const CHECK_SINGLE = 1; */
const CHECK_SINGLE = 1;
/** /**
* @var int * @var int
*/ */
const CHECK_ALL = 2; const CHECK_ALL = 2;
/** /**
* Absolute path to a file or folder, compatible with glob(). * Absolute path to a file or folder, compatible with glob().
* *
* @var string * @var string
*/ */
protected $path; protected $path;
/** /**
* Constant, check for a single file to match age criteria, or all of them. * Constant, check for a single file to match age criteria, or all of them.
* *
* @var int * @var int
*/ */
protected $fileTypeValidateFunc; protected $fileTypeValidateFunc;
/** /**
* Constant, check for a single file to match age criteria, or all of them. * Constant, check for a single file to match age criteria, or all of them.
* *
* @var int * @var int
*/ */
protected $checkType; protected $checkType;
/** /**
* @param string $path * @param string $path
* @param string $fileTypeValidateFunc * @param string $fileTypeValidateFunc
* @param null|int $checkType * @param null|int $checkType
*/ */
function __construct($path, $fileTypeValidateFunc = 'noVidation', $checkType = null) { public function __construct($path, $fileTypeValidateFunc = 'noVidation', $checkType = null)
$this->path = $path; {
$this->fileTypeValidateFunc = ($fileTypeValidateFunc)? $fileTypeValidateFunc:'noVidation'; $this->path = $path;
$this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE; $this->fileTypeValidateFunc = ($fileTypeValidateFunc)? $fileTypeValidateFunc:'noVidation';
} $this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
$origStage = Versioned::get_reading_mode(); {
Versioned::set_reading_mode('Live'); $origStage = Versioned::get_reading_mode();
Versioned::set_reading_mode('Live');
$files = $this->getFiles(); $files = $this->getFiles();
if($files){ if ($files) {
$fileTypeValidateFunc = $this->fileTypeValidateFunc; $fileTypeValidateFunc = $this->fileTypeValidateFunc;
if(method_exists ($this, $fileTypeValidateFunc)){ if (method_exists($this, $fileTypeValidateFunc)) {
$invalidFiles = array(); $invalidFiles = array();
$validFiles = array(); $validFiles = array();
foreach($files as $file){ foreach ($files as $file) {
if($this->$fileTypeValidateFunc($file)){ if ($this->$fileTypeValidateFunc($file)) {
$validFiles[] = $file; $validFiles[] = $file;
}else{ } else {
$invalidFiles[] = $file; $invalidFiles[] = $file;
} }
} }
// If at least one file was valid, count as passed // If at least one file was valid, count as passed
if($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) { if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
$validFileList = "\n"; $validFileList = "\n";
foreach($validFiles as $vf){ foreach ($validFiles as $vf) {
$validFileList .= $vf."\n"; $validFileList .= $vf."\n";
} }
if($fileTypeValidateFunc == 'noVidation') { if ($fileTypeValidateFunc == 'noVidation') {
$checkReturn = array( $checkReturn = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
sprintf('At least these file(s) accessible: %s', $validFileList) sprintf('At least these file(s) accessible: %s', $validFileList)
); );
}else{ } else {
$checkReturn = array( $checkReturn = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
sprintf('At least these file(s) passed file type validate function "%s": %s', $fileTypeValidateFunc, $validFileList) sprintf('At least these file(s) passed file type validate function "%s": %s', $fileTypeValidateFunc, $validFileList)
); );
} }
} else { } else {
if (count($invalidFiles) == 0) $checkReturn = array(EnvironmentCheck::OK, 'All files valideted'); if (count($invalidFiles) == 0) {
else { $checkReturn = array(EnvironmentCheck::OK, 'All files valideted');
$invalidFileList = "\n"; } else {
foreach($invalidFiles as $vf){ $invalidFileList = "\n";
$invalidFileList .= $vf."\n"; foreach ($invalidFiles as $vf) {
} $invalidFileList .= $vf."\n";
}
if($fileTypeValidateFunc == 'noVidation'){ if ($fileTypeValidateFunc == 'noVidation') {
$checkReturn = array( $checkReturn = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
sprintf('File(s) not accessible: %s', $invalidFileList) sprintf('File(s) not accessible: %s', $invalidFileList)
); );
}else{ } else {
$checkReturn = array( $checkReturn = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
sprintf('File(s) not passing the file type validate function "%s": %s', $fileTypeValidateFunc, $invalidFileList) sprintf('File(s) not passing the file type validate function "%s": %s', $fileTypeValidateFunc, $invalidFileList)
); );
} }
}
}
} else {
$checkReturn = array(
EnvironmentCheck::ERROR,
sprintf("Invalid file type validation method name passed: %s ", $fileTypeValidateFunc)
);
}
} else {
$checkReturn = array(
EnvironmentCheck::ERROR,
sprintf("No files accessible at path %s", $this->path)
);
}
} Versioned::set_reading_mode($origStage);
}
}else{
$checkReturn = array(
EnvironmentCheck::ERROR,
sprintf("Invalid file type validation method name passed: %s ", $fileTypeValidateFunc)
);
}
}else{ return $checkReturn;
$checkReturn = array( }
EnvironmentCheck::ERROR,
sprintf("No files accessible at path %s", $this->path)
);
}
Versioned::set_reading_mode($origStage); /**
* @param string $file
*
* @return bool
*/
private function jsonValidate($file)
{
$json = json_decode(file_get_contents($file));
if (!$json) {
return false;
} else {
return true;
}
}
return $checkReturn; /**
} * @param string $file
*
* @return bool
*/
protected function noVidation($file)
{
return true;
}
/** /**
* @param string $file * Gets a list of absolute file paths.
* *
* @return bool * @return array
*/ */
private function jsonValidate($file){ protected function getFiles()
$json = json_decode(file_get_contents($file)); {
if(!$json) { return glob($this->path);
return false; }
}else{
return true;
}
}
/**
* @param string $file
*
* @return bool
*/
protected function noVidation($file) {
return true;
}
/**
* Gets a list of absolute file paths.
*
* @return array
*/
protected function getFiles() {
return glob($this->path);
}
} }

View File

@ -19,117 +19,125 @@
* 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "' * 'FileAgeCheck("' . BASE_PATH . '/../backups/*' . '", "-1 day", '>', " . FileAgeCheck::CHECK_SINGLE) . "'
* ); * );
*/ */
class FileAgeCheck implements EnvironmentCheck { class FileAgeCheck implements EnvironmentCheck
/** {
* @var int /**
*/ * @var int
const CHECK_SINGLE = 1; */
const CHECK_SINGLE = 1;
/** /**
* @var int * @var int
*/ */
const CHECK_ALL = 2; const CHECK_ALL = 2;
/** /**
* Absolute path to a file or folder, compatible with glob(). * Absolute path to a file or folder, compatible with glob().
* *
* @var string * @var string
*/ */
protected $path; protected $path;
/** /**
* Relative date specification, compatible with strtotime(). * Relative date specification, compatible with strtotime().
* *
* @var string * @var string
*/ */
protected $relativeAge; protected $relativeAge;
/** /**
* The function to use for checking file age: so filemtime(), filectime(), or fileatime(). * The function to use for checking file age: so filemtime(), filectime(), or fileatime().
* *
* @var string * @var string
*/ */
protected $checkFn; protected $checkFn;
/** /**
* Constant, check for a single file to match age criteria, or all of them. * Constant, check for a single file to match age criteria, or all of them.
* *
* @var int * @var int
*/ */
protected $checkType; protected $checkType;
/** /**
* Type of comparison (either > or <). * Type of comparison (either > or <).
* *
* @var string * @var string
*/ */
protected $compareOperand; protected $compareOperand;
/** /**
* @param string $path * @param string $path
* @param string $relativeAge * @param string $relativeAge
* @param string $compareOperand * @param string $compareOperand
* @param null|int $checkType * @param null|int $checkType
* @param string $checkFn * @param string $checkFn
*/ */
function __construct($path, $relativeAge, $compareOperand = '>', $checkType = null, $checkFn = 'filemtime') { public function __construct($path, $relativeAge, $compareOperand = '>', $checkType = null, $checkFn = 'filemtime')
$this->path = $path; {
$this->relativeAge = $relativeAge; $this->path = $path;
$this->checkFn = $checkFn; $this->relativeAge = $relativeAge;
$this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE; $this->checkFn = $checkFn;
$this->compareOperand = $compareOperand; $this->checkType = ($checkType) ? $checkType : self::CHECK_SINGLE;
} $this->compareOperand = $compareOperand;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
$cutoffTime = strtotime($this->relativeAge, SS_Datetime::now()->Format('U')); {
$files = $this->getFiles(); $cutoffTime = strtotime($this->relativeAge, SS_Datetime::now()->Format('U'));
$invalidFiles = array(); $files = $this->getFiles();
$validFiles = array(); $invalidFiles = array();
$checkFn = $this->checkFn; $validFiles = array();
$allValid = true; $checkFn = $this->checkFn;
if($files) foreach($files as $file) { $allValid = true;
$fileTime = $checkFn($file); if ($files) {
$valid = ($this->compareOperand == '>') ? ($fileTime >= $cutoffTime) : ($fileTime <= $cutoffTime); foreach ($files as $file) {
if($valid) { $fileTime = $checkFn($file);
$validFiles[] = $file; $valid = ($this->compareOperand == '>') ? ($fileTime >= $cutoffTime) : ($fileTime <= $cutoffTime);
} else { if ($valid) {
$invalidFiles[] = $file; $validFiles[] = $file;
if($this->checkType == self::CHECK_ALL) { } else {
return array( $invalidFiles[] = $file;
EnvironmentCheck::ERROR, if ($this->checkType == self::CHECK_ALL) {
sprintf( return array(
'File "%s" doesn\'t match age check (compare %s: %s, actual: %s)', EnvironmentCheck::ERROR,
$file, $this->compareOperand, date('c', $cutoffTime), date('c', $fileTime) 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 at least one file was valid, count as passed
if($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) { if ($this->checkType == self::CHECK_SINGLE && count($invalidFiles) < count($files)) {
return array(EnvironmentCheck::OK, ''); return array(EnvironmentCheck::OK, '');
} else { } else {
if (count($invalidFiles) == 0) return array(EnvironmentCheck::OK, ''); if (count($invalidFiles) == 0) {
else return array( return array(EnvironmentCheck::OK, '');
EnvironmentCheck::ERROR, } else {
sprintf('No files matched criteria (%s %s)', $this->compareOperand, date('c', $cutoffTime)) return array(
); EnvironmentCheck::ERROR,
} sprintf('No files matched criteria (%s %s)', $this->compareOperand, date('c', $cutoffTime))
);
}
}
}
} /**
* Gets a list of absolute file paths.
/** *
* Gets a list of absolute file paths. * @return array
* */
* @return array protected function getFiles()
*/ {
protected function getFiles() { return glob($this->path);
return glob($this->path); }
}
} }

View File

@ -3,66 +3,75 @@
/** /**
* Check that the given file is writable. * Check that the given file is writable.
*/ */
class FileWriteableCheck implements EnvironmentCheck { class FileWriteableCheck implements EnvironmentCheck
/** {
* @var string /**
*/ * @var string
protected $path; */
protected $path;
/** /**
* @param string $path The full path. If a relative path, it will relative to the BASE_PATH. * @param string $path The full path. If a relative path, it will relative to the BASE_PATH.
*/ */
function __construct($path) { public function __construct($path)
$this->path = $path; {
} $this->path = $path;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
if($this->path[0] == '/') $filename = $this->path; {
else $filename = BASE_PATH . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $this->path); 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); if (file_exists($filename)) {
else $isWriteable = is_writeable(dirname($filename)); $isWriteable = is_writeable($filename);
} else {
$isWriteable = is_writeable(dirname($filename));
}
if(!$isWriteable) { if (!$isWriteable) {
if(function_exists('posix_getgroups')) { if (function_exists('posix_getgroups')) {
$userID = posix_geteuid(); $userID = posix_geteuid();
$user = posix_getpwuid($userID); $user = posix_getpwuid($userID);
$currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename) ); $currentOwnerID = fileowner(file_exists($filename) ? $filename : dirname($filename));
$currentOwner = posix_getpwuid($currentOwnerID); $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]'. "; $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']) { if ($user['name'] == $currentOwner['name']) {
$message .= "We recommend that you make the file writeable."; $message .= "We recommend that you make the file writeable.";
} else { } 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";
}
$groups = posix_getgroups(); return array(EnvironmentCheck::ERROR, $message);
$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 { return array(EnvironmentCheck::OK,'');
$message = "The webserver user needs to be able to write to this file:\n$filename"; }
}
return array(EnvironmentCheck::ERROR, $message);
}
return array(EnvironmentCheck::OK,'');
}
} }

View File

@ -3,26 +3,32 @@
/** /**
* Check that the given class exists. * Check that the given class exists.
*/ */
class HasClassCheck implements EnvironmentCheck { class HasClassCheck implements EnvironmentCheck
/** {
* @var string /**
*/ * @var string
protected $className; */
protected $className;
/** /**
* @param string $className The name of the class to look for. * @param string $className The name of the class to look for.
*/ */
function __construct($className) { public function __construct($className)
$this->className = $className; {
} $this->className = $className;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public 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'); if (class_exists($this->className)) {
} return array(EnvironmentCheck::OK, 'Class ' . $this->className.' exists');
} else {
return array(EnvironmentCheck::ERROR, 'Class ' . $this->className.' doesn\'t exist');
}
}
} }

View File

@ -3,26 +3,32 @@
/** /**
* Check that the given function exists. * Check that the given function exists.
*/ */
class HasFunctionCheck implements EnvironmentCheck { class HasFunctionCheck implements EnvironmentCheck
/** {
* @var string /**
*/ * @var string
protected $functionName; */
protected $functionName;
/** /**
* @param string $functionName The name of the function to look for. * @param string $functionName The name of the function to look for.
*/ */
function __construct($functionName) { public function __construct($functionName)
$this->functionName = $functionName; {
} $this->functionName = $functionName;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
if(function_exists($this->functionName)) return array(EnvironmentCheck::OK, $this->functionName.'() exists'); {
else return array(EnvironmentCheck::ERROR, $this->functionName.'() doesn\'t exist'); if (function_exists($this->functionName)) {
} return array(EnvironmentCheck::OK, $this->functionName.'() exists');
} else {
return array(EnvironmentCheck::ERROR, $this->functionName.'() doesn\'t exist');
}
}
} }

View File

@ -5,62 +5,69 @@
* *
* Only checks socket connection with HELO command, not actually sending the email. * Only checks socket connection with HELO command, not actually sending the email.
*/ */
class SMTPConnectCheck implements EnvironmentCheck { class SMTPConnectCheck implements EnvironmentCheck
/** {
* @var string /**
*/ * @var string
protected $host; */
protected $host;
/** /**
* @var int * @var int
*/ */
protected $port; protected $port;
/** /**
* Timeout (in seconds). * Timeout (in seconds).
* *
* @var int * @var int
*/ */
protected $timeout; protected $timeout;
/** /**
* @param null|string $host * @param null|string $host
* @param null|int $port * @param null|int $port
* @param int $timeout * @param int $timeout
*/ */
function __construct($host = null, $port = null, $timeout = 15) { public function __construct($host = null, $port = null, $timeout = 15)
$this->host = ($host) ? $host : ini_get('SMTP'); {
if(!$this->host) $this->host = 'localhost'; $this->host = ($host) ? $host : ini_get('SMTP');
if (!$this->host) {
$this->host = 'localhost';
}
$this->port = ($port) ? $port : ini_get('smtp_port'); $this->port = ($port) ? $port : ini_get('smtp_port');
if(!$this->port) $this->port = 25; if (!$this->port) {
$this->port = 25;
}
$this->timeout = $timeout; $this->timeout = $timeout;
} }
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
$f = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout); {
if(!$f) { $f = @fsockopen($this->host, $this->port, $errno, $errstr, $this->timeout);
return array( if (!$f) {
EnvironmentCheck::ERROR, return array(
sprintf("Couldn't connect to SMTP on %s:%s (Error: %s %s)", $this->host, $this->port, $errno, $errstr) 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"); fwrite($f, "HELO its_me\r\n");
$response = fread($f, 26); $response = fread($f, 26);
if(substr($response, 0, 3) != '220') { if (substr($response, 0, 3) != '220') {
return array( return array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
sprintf("Invalid mail server response: %s", $response) sprintf("Invalid mail server response: %s", $response)
); );
} }
return array(EnvironmentCheck::OK, ''); return array(EnvironmentCheck::OK, '');
} }
} }

View File

@ -5,49 +5,52 @@
* *
* If there are no indexes of given class found, the returned status will still be "OK". * If there are no indexes of given class found, the returned status will still be "OK".
*/ */
class SolrIndexCheck implements EnvironmentCheck { class SolrIndexCheck implements EnvironmentCheck
/** {
* @var null|string /**
*/ * @var null|string
protected $indexClass; */
protected $indexClass;
/** /**
* @param string $indexClass Limit the index checks to the specified class and all its subclasses. * @param string $indexClass Limit the index checks to the specified class and all its subclasses.
*/ */
function __construct($indexClass = null) { public function __construct($indexClass = null)
$this->indexClass = $indexClass; {
} $this->indexClass = $indexClass;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
*/ */
function check() { public function check()
$brokenCores = array(); {
$brokenCores = array();
if (!class_exists('Solr')) { if (!class_exists('Solr')) {
return array( return array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'Class `Solr` not found. Is the fulltextsearch module installed?' 'Class `Solr` not found. Is the fulltextsearch module installed?'
); );
} }
$service = Solr::service(); $service = Solr::service();
foreach (Solr::get_indexes($this->indexClass) as $index) { foreach (Solr::get_indexes($this->indexClass) as $index) {
$core = $index->getIndexName(); $core = $index->getIndexName();
if (!$service->coreIsActive($core)) { if (!$service->coreIsActive($core)) {
$brokenCores[] = $core; $brokenCores[] = $core;
} }
} }
if (!empty($brokenCores)) { if (!empty($brokenCores)) {
return array( return array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'The following indexes are unavailable: ' . implode($brokenCores, ', ') 'The following indexes are unavailable: ' . implode($brokenCores, ', ')
); );
} }
return array(EnvironmentCheck::OK, 'Expected indexes are available.'); return array(EnvironmentCheck::OK, 'Expected indexes are available.');
} }
} }

View File

@ -5,53 +5,54 @@
* *
* Note that Director::test() will be used rather than a CURL check. * Note that Director::test() will be used rather than a CURL check.
*/ */
class URLCheck implements EnvironmentCheck { class URLCheck implements EnvironmentCheck
/** {
* @var string /**
*/ * @var string
protected $url; */
protected $url;
/** /**
* @var string * @var string
*/ */
protected $testString; protected $testString;
/* /*
* @param string $url The URL to check, relative to the site (homepage is ''). * @param string $url The URL to check, relative to the site (homepage is '').
* @param string $testString An optional piece of text to search for on the homepage. * @param string $testString An optional piece of text to search for on the homepage.
*/ */
function __construct($url = '', $testString = '') { public function __construct($url = '', $testString = '')
$this->url = $url; {
$this->testString = $testString; $this->url = $url;
} $this->testString = $testString;
}
/** /**
* @inheritdoc * @inheritdoc
* *
* @return array * @return array
* *
* @throws SS_HTTPResponse_Exception * @throws SS_HTTPResponse_Exception
*/ */
function check() { public function check()
$response = Director::test($this->url); {
$response = Director::test($this->url);
if($response->getStatusCode() != 200) { if ($response->getStatusCode() != 200) {
return array( return array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
sprintf('Error retrieving "%s" (Code: %d)', $this->url, $response->getStatusCode()) sprintf('Error retrieving "%s" (Code: %d)', $this->url, $response->getStatusCode())
); );
} elseif ($this->testString && (strpos($response->getBody(), $this->testString) === false)) {
} else if($this->testString && (strpos($response->getBody(), $this->testString) === false)) { return array(
return array( EnvironmentCheck::WARNING,
EnvironmentCheck::WARNING, sprintf('Success retrieving "%s", but string "%s" not found', $this->url, $this->testString)
sprintf('Success retrieving "%s", but string "%s" not found', $this->url, $this->testString) );
); } else {
return array(
} else { EnvironmentCheck::OK,
return array( sprintf('Success retrieving "%s"', $this->url)
EnvironmentCheck::OK, );
sprintf('Success retrieving "%s"', $this->url) }
); }
}
}
} }

View File

@ -3,12 +3,14 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class DevCheckControllerTest extends SapphireTest { class DevCheckControllerTest extends SapphireTest
public function testIndexCreatesChecker() { {
$controller = new DevCheckController(); public function testIndexCreatesChecker()
{
$controller = new DevCheckController();
$request = new SS_HTTPRequest('GET', 'example.com'); $request = new SS_HTTPRequest('GET', 'example.com');
$this->assertInstanceOf('EnvironmentChecker', $controller->index($request)); $this->assertInstanceOf('EnvironmentChecker', $controller->index($request));
} }
} }

View File

@ -3,21 +3,23 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class DevHealthControllerTest extends SapphireTest { class DevHealthControllerTest extends SapphireTest
public function testIndexCreatesChecker() { {
$controller = new DevHealthController(); public function testIndexCreatesChecker()
{
$controller = new DevHealthController();
$request = new SS_HTTPRequest('GET', 'example.com'); $request = new SS_HTTPRequest('GET', 'example.com');
// we need to fake authenticated access as BasicAuth::requireLogin doesn't like empty // we need to fake authenticated access as BasicAuth::requireLogin doesn't like empty
// permission type strings, which is what health check uses. // permission type strings, which is what health check uses.
define('ENVCHECK_BASICAUTH_USERNAME', 'foo'); define('ENVCHECK_BASICAUTH_USERNAME', 'foo');
define('ENVCHECK_BASICAUTH_PASSWORD', 'bar'); define('ENVCHECK_BASICAUTH_PASSWORD', 'bar');
$_SERVER['PHP_AUTH_USER'] = 'foo'; $_SERVER['PHP_AUTH_USER'] = 'foo';
$_SERVER['PHP_AUTH_PW'] = 'bar'; $_SERVER['PHP_AUTH_PW'] = 'bar';
$this->assertInstanceOf('EnvironmentChecker', $controller->index($request)); $this->assertInstanceOf('EnvironmentChecker', $controller->index($request));
} }
} }

View File

@ -1,89 +1,100 @@
<?php <?php
class EnvironmentCheckerTest extends SapphireTest { class EnvironmentCheckerTest extends SapphireTest
{
public function setUpOnce()
{
parent::setUpOnce();
public function setUpOnce() { Phockito::include_hamcrest();
parent::setUpOnce(); }
Phockito::include_hamcrest(); public function setUp()
} {
parent::setUp();
public function setUp() { Config::nest();
parent::setUp(); }
Config::nest(); public function tearDown()
} {
Config::unnest();
public function tearDown() { parent::tearDown();
Config::unnest(); }
parent::tearDown(); public function testOnlyLogsWithErrors()
} {
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true);
Config::inst()->update('EnvironmentChecker', 'log_results_error', true);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckNoErrors());
$checker = Phockito::spy(
'EnvironmentChecker',
'test suite',
'test'
);
public function testOnlyLogsWithErrors() { $response = $checker->index();
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true); Phockito::verify($checker, 0)->log(anything(), anything());
Config::inst()->update('EnvironmentChecker', 'log_results_error', true); EnvironmentCheckSuite::reset();
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckNoErrors()); }
$checker = Phockito::spy(
'EnvironmentChecker',
'test suite',
'test'
);
$response = $checker->index(); public function testLogsWithWarnings()
Phockito::verify($checker, 0)->log(anything(), anything()); {
EnvironmentCheckSuite::reset(); Config::inst()->update('EnvironmentChecker', 'log_results_warning', true);
} Config::inst()->update('EnvironmentChecker', 'log_results_error', false);
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors());
$checker = Phockito::spy(
'EnvironmentChecker',
'test suite',
'test'
);
public function testLogsWithWarnings() { $response = $checker->index();
Config::inst()->update('EnvironmentChecker', 'log_results_warning', true); Phockito::verify($checker, 1)->log(containsString('warning'), anything());
Config::inst()->update('EnvironmentChecker', 'log_results_error', false); Phockito::verify($checker, 0)->log(containsString('error'), anything());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings()); EnvironmentCheckSuite::reset();
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors()); }
$checker = Phockito::spy(
'EnvironmentChecker',
'test suite',
'test'
);
$response = $checker->index(); public function testLogsWithErrors()
Phockito::verify($checker, 1)->log(containsString('warning'), anything()); {
Phockito::verify($checker, 0)->log(containsString('error'), anything()); Config::inst()->update('EnvironmentChecker', 'log_results_error', false);
EnvironmentCheckSuite::reset(); Config::inst()->update('EnvironmentChecker', 'log_results_error', true);
} EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings());
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors());
public function testLogsWithErrors() { $checker = Phockito::spy(
Config::inst()->update('EnvironmentChecker', 'log_results_error', false); 'EnvironmentChecker',
Config::inst()->update('EnvironmentChecker', 'log_results_error', true); 'test suite',
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckWarnings()); 'test'
EnvironmentCheckSuite::register('test suite', new EnvironmentCheckerTest_CheckErrors()); );
$checker = Phockito::spy(
'EnvironmentChecker',
'test suite',
'test'
);
$response = $checker->index();
Phockito::verify($checker, 0)->log(containsString('warning'), anything());
Phockito::verify($checker, 1)->log(containsString('error'), anything());
EnvironmentCheckSuite::reset();
}
$response = $checker->index();
Phockito::verify($checker, 0)->log(containsString('warning'), anything());
Phockito::verify($checker, 1)->log(containsString('error'), anything());
EnvironmentCheckSuite::reset();
}
} }
class EnvironmentCheckerTest_CheckNoErrors implements EnvironmentCheck, TestOnly{ class EnvironmentCheckerTest_CheckNoErrors implements EnvironmentCheck, TestOnly
public function check() { {
return array(EnvironmentCheck::OK, ''); public function check()
} {
return array(EnvironmentCheck::OK, '');
}
} }
class EnvironmentCheckerTest_CheckWarnings implements EnvironmentCheck, TestOnly{ class EnvironmentCheckerTest_CheckWarnings implements EnvironmentCheck, TestOnly
public function check() { {
return array(EnvironmentCheck::WARNING, "test warning"); public function check()
} {
return array(EnvironmentCheck::WARNING, "test warning");
}
} }
class EnvironmentCheckerTest_CheckErrors implements EnvironmentCheck, TestOnly{ class EnvironmentCheckerTest_CheckErrors implements EnvironmentCheck, TestOnly
public function check() { {
return array(EnvironmentCheck::ERROR, "test error"); public function check()
} {
return array(EnvironmentCheck::ERROR, "test error");
}
} }

View File

@ -3,15 +3,17 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class DatabaseCheckTest extends SapphireTest { class DatabaseCheckTest extends SapphireTest
public function testCheckReportsValidConnection() { {
$check = new DatabaseCheck(); public function testCheckReportsValidConnection()
{
$check = new DatabaseCheck();
$expected = array( $expected = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
'', '',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
} }

View File

@ -3,17 +3,19 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class ExternalURLCheckTest extends SapphireTest { class ExternalURLCheckTest extends SapphireTest
public function testCheckReportsMissingPages() { {
$this->markTestSkipped('ExternalURLCheck seems faulty on some systems'); public function testCheckReportsMissingPages()
{
$this->markTestSkipped('ExternalURLCheck seems faulty on some systems');
$check = new ExternalURLCheck('http://missing-site/'); $check = new ExternalURLCheck('http://missing-site/');
$expected = array( $expected = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'Success retrieving "http://missing-site/" (Code: 404)', 'Success retrieving "http://missing-site/" (Code: 404)',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
} }

View File

@ -3,23 +3,26 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class FileWritableCheckTest extends SapphireTest { class FileWritableCheckTest extends SapphireTest
public function testCheckReportsWritablePaths() { {
$check = new FileWriteableCheck(TEMP_FOLDER); public function testCheckReportsWritablePaths()
{
$check = new FileWriteableCheck(TEMP_FOLDER);
$expected = array( $expected = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
'', '',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
public function testCheckReportsNonWritablePaths() { public function testCheckReportsNonWritablePaths()
$check = new FileWriteableCheck('/var'); {
$check = new FileWriteableCheck('/var');
$result = $check->check(); $result = $check->check();
$this->assertEquals(EnvironmentCheck::ERROR, $result[0]); $this->assertEquals(EnvironmentCheck::ERROR, $result[0]);
} }
} }

View File

@ -3,26 +3,29 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class HasClassCheckTest extends SapphireTest { class HasClassCheckTest extends SapphireTest
public function testCheckReportsMissingClasses() { {
$check = new HasClassCheck('foo'); public function testCheckReportsMissingClasses()
{
$check = new HasClassCheck('foo');
$expected = array( $expected = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'Class foo doesn\'t exist', 'Class foo doesn\'t exist',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
public function testCheckReportsFoundClasses() { public function testCheckReportsFoundClasses()
$check = new HasClassCheck('stdClass'); {
$check = new HasClassCheck('stdClass');
$expected = array( $expected = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
'Class stdClass exists', 'Class stdClass exists',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
} }

View File

@ -3,26 +3,29 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class HasFunctionCheckTest extends SapphireTest { class HasFunctionCheckTest extends SapphireTest
public function testCheckReportsMissingFunctions() { {
$check = new HasFunctionCheck('foo'); public function testCheckReportsMissingFunctions()
{
$check = new HasFunctionCheck('foo');
$expected = array( $expected = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'foo() doesn\'t exist', 'foo() doesn\'t exist',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
public function testCheckReportsFoundFunctions() { public function testCheckReportsFoundFunctions()
$check = new HasFunctionCheck('class_exists'); {
$check = new HasFunctionCheck('class_exists');
$expected = array( $expected = array(
EnvironmentCheck::OK, EnvironmentCheck::OK,
'class_exists() exists', 'class_exists() exists',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
} }

View File

@ -3,15 +3,17 @@
/** /**
* @mixin PHPUnit_Framework_TestCase * @mixin PHPUnit_Framework_TestCase
*/ */
class URLCheckTest extends SapphireTest { class URLCheckTest extends SapphireTest
public function testCheckReportsMissingPages() { {
$check = new URLCheck('foo', 'bar'); public function testCheckReportsMissingPages()
{
$check = new URLCheck('foo', 'bar');
$expected = array( $expected = array(
EnvironmentCheck::ERROR, EnvironmentCheck::ERROR,
'Error retrieving "foo" (Code: 404)', 'Error retrieving "foo" (Code: 404)',
); );
$this->assertEquals($expected, $check->check()); $this->assertEquals($expected, $check->check());
} }
} }