Commit 5f77d18b authored by Penny Leach's avatar Penny Leach
Browse files

changed the exception handling stuff a lot. adding new exception types

has a bit more overhead now but they're handled much nicer. Exception
and MaharaException should now NEVER be thrown directly
parent 59844ee8
...@@ -32,7 +32,7 @@ require(get_config('docroot') . 'auth/user.php'); ...@@ -32,7 +32,7 @@ require(get_config('docroot') . 'auth/user.php');
/** /**
* Unknown user exception * Unknown user exception
*/ */
class AuthUnknownUserException extends Exception {} class AuthUnknownUserException extends UserException {}
/** /**
* Base authentication class. Provides a common interface with which * Base authentication class. Provides a common interface with which
......
...@@ -26,9 +26,6 @@ ...@@ -26,9 +26,6 @@
defined('INTERNAL') || die(); defined('INTERNAL') || die();
/** Thrown if the key requested doesn't exist */
class UserKeyInvalidException extends Exception {}
/** /**
* The user class represents a single logged in user in the system. The user * The user class represents a single logged in user in the system. The user
* has several properties that can be accessed and set, including account * has several properties that can be accessed and set, including account
...@@ -88,7 +85,7 @@ class User { ...@@ -88,7 +85,7 @@ class User {
*/ */
public function get($key) { public function get($key) {
if (!isset($this->defaults[$key])) { if (!isset($this->defaults[$key])) {
throw new UserKeyInvalidException($key); throw new InvalidArgumentException($key);
} }
if (null !== ($value = $this->SESSION->get("user/$key"))) { if (null !== ($value = $this->SESSION->get("user/$key"))) {
return $value; return $value;
...@@ -101,7 +98,7 @@ class User { ...@@ -101,7 +98,7 @@ class User {
*/ */
public function set($key, $value) { public function set($key, $value) {
if (!isset($this->defaults[$key])) { if (!isset($this->defaults[$key])) {
throw new UserKeyInvalidException($key); throw new InvalidArgumentException($key);
} }
$this->SESSION->set("user/$key", $value); $this->SESSION->set("user/$key", $value);
} }
......
...@@ -54,4 +54,7 @@ $string['unrecoverableerrortitle'] = '%s - Site Unavailable'; ...@@ -54,4 +54,7 @@ $string['unrecoverableerrortitle'] = '%s - Site Unavailable';
$string['parameterexception'] = 'A required parameter was missing'; $string['parameterexception'] = 'A required parameter was missing';
$string['accessdeniedexception'] = 'You do not have access to view this page'; $string['accessdeniedexception'] = 'You do not have access to view this page';
?> $string['viewnotfoundexceptiontitle'] = 'View not found';
$string['viewnotfoundexceptionmessage'] = 'You tried to access a view that didn\'t exist!';
?>
\ No newline at end of file
...@@ -130,19 +130,19 @@ function log_message ($message, $loglevel, $escape, $backtrace, $file=null, $lin ...@@ -130,19 +130,19 @@ function log_message ($message, $loglevel, $escape, $backtrace, $file=null, $lin
} }
// Get nice backtrace information if required // Get nice backtrace information if required
$backtrace = ($trace) ? $trace : debug_backtrace(); $trace = ($trace) ? $trace : debug_backtrace();
// If the last caller was the 'error' function then it came from a PHP warning // If the last caller was the 'error' function then it came from a PHP warning
if (!is_null($file)) { if (!is_null($file)) {
$filename = $file; $filename = $file;
$linenum = $line; $linenum = $line;
} }
else { else {
$filename = $backtrace[1]['file']; $filename = $trace[1]['file'];
$linenum = $backtrace[1]['line']; $linenum = $trace[1]['line'];
} }
if (!function_exists('get_config') || get_config('log_backtrace_levels') & $loglevel) { if (!function_exists('get_config') || get_config('log_backtrace_levels') & $loglevel) {
list($textbacktrace, $htmlbacktrace) = log_build_backtrace($backtrace); list($textbacktrace, $htmlbacktrace) = log_build_backtrace($trace);
} }
else { else {
$textbacktrace = $htmlbacktrace = ''; $textbacktrace = $htmlbacktrace = '';
...@@ -232,7 +232,7 @@ function log_build_backtrace($backtrace) { ...@@ -232,7 +232,7 @@ function log_build_backtrace($backtrace) {
$calls = array(); $calls = array();
// Remove the call to log_message // Remove the call to log_message
array_shift($backtrace); //array_shift($backtrace);
foreach ($backtrace as $bt) { foreach ($backtrace as $bt) {
$bt['file'] = (isset($bt['file'])) ? $bt['file'] : 'Unknown'; $bt['file'] = (isset($bt['file'])) ? $bt['file'] : 'Unknown';
...@@ -381,52 +381,96 @@ function exception (Exception $e) { ...@@ -381,52 +381,96 @@ function exception (Exception $e) {
// get language string based on class name // get language string based on class name
// rather than by switch on class name // rather than by switch on class name
if ($USER) { if ($USER) {
$logged = false;
if (!($e instanceof MaharaException) || get_class($e == 'MaharaException')) {
log_warn("An exception was thrown of class " . get_class($e) . ". \nTHIS IS BAD "
. "and should be changed to something extending MaharaException.\n"
. "Original trace follows", true, false);
log_message($e->getMessage(), LOG_LEVEL_WARN, true, true, $e->getFile(), $e->getLine(), $e->getTrace());
$e = new SystemException($e->getMessage());
$e->set_log_off();
}
$e->handle_exception($logged);
}
}
interface MaharaThrowable {
public function render_exception();
}
// Standard exceptions - top level exception class.
// all exceptions should extend one of these three.
/**
* Very top of the tree for exceptions in Mahara.
* Nothing should extend this directly.
* Contains a few helper functions for all exceptions.
*/
class MaharaException extends Exception {
protected $log = true;
public function get_string() {
$args = func_get_args();
if (function_exists('get_string')) { if (function_exists('get_string')) {
$outputmessage = get_string('unrecoverableerror', 'error'); $args[0] = strtolower(get_class($this)) . $args[0];
if (!function_exists('get_config') || !$sitename = @get_config('sitename')) { $args[1] = 'error';
$sitename = 'Mahara'; $str = call_user_func_array('get_string', $args);
if (strpos($str, '[[') !== 0) {
return $str;
} }
$outputtitle = get_string('unrecoverableerrortitle', 'error', $sitename);
$parameterexception = get_string('parameterexception', 'error');
$accessdeniedexception = get_string('accessdeniedexception', 'error');
} }
else {
// sensible english defaults $tag = func_get_arg(0);
$outputmessage = 'A nonrecoverable error occured. ' $strings = $this->strings();
. 'This probably means you have encountered a bug in the system'; if (array_key_exists($tag, $strings)) {
$outputtitle = 'Mahara - Site Unavailable'; return $strings[$tag];
$parameterexception = 'A required parameter was missing';
$accessdeniedexception = 'You do not have access to view this page';
} }
switch (get_class($e)) {
case 'ConfigSanityException': return 'An error occured';
$outputmessage = $message = get_string('configsanityexception', 'error', $e->getMessage()); }
break;
case 'ParameterException': public function get_sitename() {
$outputmessage = $message = $parameterexception . ' ' . $e->getMessage(); if (!function_exists('get_config') || !$sitename = @get_config('sitename')) {
break; $sitename = 'Mahara';
case 'AccessDeniedException':
$outputmessage = $message = $accessdeniedexception . ' ' . $e->getMessage();
break;
default:
$message = $e->getMessage();
$outputmessage .= '<br> ' . $e->getMessage();
} }
return $sitename;
}
public function strings() {
return array('title' => $this->get_sitename() . ': Site unavailable');
}
log_message($message, LOG_LEVEL_WARN, true, true, $e->getFile(), $e->getLine(), $e->getTrace()); public function set_log() {
$this->log = true;
}
public function set_log_off() {
$this->log = false;
}
public function render_exception() {
return $this->getMessage();
}
public function handle_exception() {
$outputtitle = $this->get_string('title');
$outputmessage = $this->render_exception();
$message = strip_tags($outputmessage);
$message = htmlspecialchars_decode($message);
if (function_exists('smarty')) { if (function_exists('smarty')) {
$smarty = smarty(); $smarty = smarty();
$smarty->assign('title', $outputtitle); $smarty->assign('title', $outputtitle);
$smarty->assign('message', $outputmessage); $smarty->assign('message', $outputmessage);
$smarty->display('error.tpl'); $smarty->display('error.tpl');
die();
} }
} else {
else {
$outputtitle = 'Mahara - Site Unavailable';
$outputmessage = $e->getMessage();
}
echo <<<EOF echo <<<EOF
<html> <html>
<head> <head>
...@@ -449,49 +493,136 @@ $outputmessage ...@@ -449,49 +493,136 @@ $outputmessage
</body> </body>
</html> </html>
EOF; EOF;
die(); }
// end of printing stuff to the screen...
if (!empty($this->log)) {
log_message($message, LOG_LEVEL_WARN, true, true, $this->getFile(), $this->getLine(), $this->getTrace());
}
die();
}
}
/**
* SystemException - this is basically a bug in the system.
*/
class SystemException extends MaharaException implements MaharaThrowable {
public function render_exception () {
return $this->get_string('message');
}
public function strings() {
return array_merge(parent::strings(),
array('message' => 'A nonrecoverable error occured. '
. 'This probably means you have encountered a bug in the system'));
}
} }
/**
* ConfigException - something is misconfigured that's causing a problem.
* Generally these will be the fault of admins
*/
class ConfigException extends MaharaException implements MaharaThrowable {
public function render_exception () {
return $this->getMessage();
}
public function strings() {
return array_merge(parent::strings(),
array('message' => $this->get_sitename()
. ' is misconfigured and this is causing problems. '
. 'You probably need to contact an administrator to get this fixed. '
. ' Details, if any, follow'));
}
}
/**
* UserException - the user has done something they shouldn't (or tried to)
*/
class UserException extends MaharaException implements MaharaThrowable {
protected $log = false;
// Standard exceptions public function render_exception () {
return $this->get_string('message') . '<br><br>' . $this->getMessage();
}
public function strings() {
return array_merge(parent::strings(),
array('message' => 'Something in the way you\'re interacting with '
. $this->get_sitename()
.' is causing an error.<br>Details if any, follow'));
}
}
/** /**
* The configuration that Mahara is trying to be run in is insane * The configuration that Mahara is trying to be run in is insane
*/ */
class ConfigSanityException extends Exception {} class ConfigSanityException extends ConfigException {
public function strings() {
return array_merge(parent::strings(), array('message' => ''));
}
}
/** /**
* An SQL related error occured * An SQL related error occured
*/ */
class SQLException extends Exception {} class SQLException extends SystemException {}
/** /**
* An exception generated by invalid GET or POST parameters * An exception generated by invalid GET or POST parameters
*/ */
class ParameterException extends Exception {} class ParameterException extends UserException {
function strings() {
return array_merge(parent::strings(), array('message' => 'A required parameter was missing'));
}
}
/** /**
* An exception generated when e-mail can't be sent * An exception generated when e-mail can't be sent
*/ */
class EmailException extends Exception {} class EmailException extends SystemException {}
/** /**
* Exception - artefact not found * Exception - artefact not found
*/ */
class ArtefactNotFoundException extends Exception {} class ArtefactNotFoundException extends UserException {}
/** /**
* Exception - view not found * Exception - view not found
*/ */
class ViewNotFoundException extends Exception {} class ViewNotFoundException extends UserException {}
/** /**
* Exception - anything to do with template parsing * Exception - anything to do with template parsing
*/ */
class TemplateParserException extends Exception {} class TemplateParserException extends ConfigException {}
/** /**
* Exception - Access denied. Throw this if a user is trying to view something they can't * Exception - Access denied. Throw this if a user is trying to view something they can't
*/ */
class AccessDeniedException extends Exception {} class AccessDeniedException extends UserException {
public function strings() {
return array_merge(parent::strings(),
array('message' => 'You do not have access to view this page',
'title' => 'Access denied'));
}
public function render_exception() {
header("HTTP/1.0 403 Forbidden", true);
return parent::render_exception();
}
}
?> ?>
...@@ -29,7 +29,7 @@ defined('INTERNAL') || die(); ...@@ -29,7 +29,7 @@ defined('INTERNAL') || die();
/** /**
* Class to use for installation exceptions * Class to use for installation exceptions
*/ */
class InstallationException extends Exception {} class InstallationException extends SystemException {}
/** /**
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<div class="content"> <div class="content">
<div class="box-cnrs"><span class="cnr-tl"><span class="cnr-tr"><span class="cnr-bl"><span class="cnr-br"> <div class="box-cnrs"><span class="cnr-tl"><span class="cnr-tr"><span class="cnr-bl"><span class="cnr-br">
<div class="maincontent"> <div class="maincontent">
<h4>{$title}</h4>
{$message} {$message}
</div> </div>
</span></span></span></span></div> </span></span></span></span></div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment