2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
2008-03-16 23:13:31 +01:00
|
|
|
* Supports debugging and core error handling.
|
|
|
|
*
|
2009-08-19 07:41:58 +02:00
|
|
|
* Attaches custom methods to the default error handling hooks
|
|
|
|
* in PHP. Currently, two levels of error are supported:
|
2008-03-16 23:13:31 +01:00
|
|
|
*
|
2009-08-19 08:03:57 +02:00
|
|
|
* - Notice
|
2008-03-16 23:13:31 +01:00
|
|
|
* - Warning
|
|
|
|
* - Error
|
|
|
|
*
|
|
|
|
* Uncaught exceptions are currently passed to the debug
|
|
|
|
* reporter as standard PHP errors.
|
|
|
|
*
|
2009-08-19 07:41:58 +02:00
|
|
|
* Errors handled by this class are passed along to {@link SSLog}.
|
|
|
|
* For configuration information, see the {@link SSLog}
|
|
|
|
* class documentation.
|
2008-03-16 23:13:31 +01:00
|
|
|
*
|
|
|
|
* @todo add support for user defined config: Debug::die_on_notice(true | false)
|
|
|
|
* @todo better way of figuring out the error context to display in highlighted source
|
2008-02-25 03:10:37 +01:00
|
|
|
*
|
|
|
|
* @package sapphire
|
2009-08-19 07:41:58 +02:00
|
|
|
* @subpackage dev
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
class Debug {
|
|
|
|
|
|
|
|
/**
|
2008-02-25 03:10:37 +01:00
|
|
|
* @var $custom_smtp_server string Custom mailserver for sending mails.
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
protected static $custom_smtp_server = '';
|
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
|
|
|
* @var $send_errors_to string Email address to send error notifications
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
protected static $send_errors_to;
|
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
|
|
|
* @var $send_warnings_to string Email address to send warning notifications
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
protected static $send_warnings_to;
|
|
|
|
|
2008-08-11 06:02:32 +02:00
|
|
|
/**
|
|
|
|
* String indicating the file where errors are logged.
|
|
|
|
* Filename is relative to the site root.
|
|
|
|
* The named file will have a terse log sent to it, and the full log (an
|
|
|
|
* encoded file containing backtraces and things) will go to a file of a similar
|
|
|
|
* name, but with the suffix ".full" added.
|
|
|
|
*/
|
|
|
|
protected static $log_errors_to = null;
|
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
|
|
|
* Show the contents of val in a debug-friendly way.
|
|
|
|
* Debug::show() is intended to be equivalent to dprintr()
|
|
|
|
*/
|
|
|
|
static function show($val, $showHeader = true) {
|
|
|
|
if(!Director::isLive()) {
|
|
|
|
if($showHeader) {
|
|
|
|
$caller = Debug::caller();
|
2008-08-13 03:47:05 +02:00
|
|
|
if(Director::is_ajax() || Director::is_cli())
|
2007-07-19 12:40:28 +02:00
|
|
|
echo "Debug ($caller[class]$caller[type]$caller[function]() in line $caller[line] of " . basename($caller['file']) . ")\n";
|
|
|
|
else
|
2008-03-16 23:13:31 +01:00
|
|
|
echo "<div style=\"background-color: white; text-align: left;\">\n<hr>\n<h3>Debug <span style=\"font-size: 65%\">($caller[class]$caller[type]$caller[function]() \n<span style=\"font-weight:normal\">in line</span> $caller[line] \n<span style=\"font-weight:normal\">of</span> " . basename($caller['file']) . ")</span>\n</h3>\n";
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
echo Debug::text($val);
|
|
|
|
|
2008-08-13 03:47:05 +02:00
|
|
|
if(!Director::is_ajax() && !Director::is_cli()) echo "</div>";
|
|
|
|
else echo "\n\n";
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2008-02-25 03:10:37 +01:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Close out the show dumper
|
|
|
|
*
|
|
|
|
* @param mixed $val
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function endshow($val) {
|
|
|
|
if(!Director::isLive()) {
|
|
|
|
$caller = Debug::caller();
|
|
|
|
echo "<hr>\n<h3>Debug \n<span style=\"font-size: 65%\">($caller[class]$caller[type]$caller[function]() \n<span style=\"font-weight:normal\">in line</span> $caller[line] \n<span style=\"font-weight:normal\">of</span> " . basename($caller['file']) . ")</span>\n</h3>\n";
|
|
|
|
echo Debug::text($val);
|
|
|
|
die();
|
|
|
|
}
|
|
|
|
}
|
2008-03-16 23:13:31 +01:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Quick dump of a variable.
|
|
|
|
*
|
|
|
|
* @param mixed $val
|
|
|
|
*/
|
2008-03-16 23:13:31 +01:00
|
|
|
static function dump($val) {
|
2008-08-09 08:40:50 +02:00
|
|
|
echo '<pre style="background-color:#ccc;padding:5px;font-size:14px;line-height:18px;">';
|
2008-08-09 08:24:30 +02:00
|
|
|
$caller = Debug::caller();
|
2008-08-09 08:40:50 +02:00
|
|
|
echo "<span style=\"font-size: 12px;color:#666;\">Line $caller[line] of " . basename($caller['file']) . ":</span>\n";
|
|
|
|
if (is_string($val)) print_r(wordwrap($val, 100));
|
|
|
|
else print_r($val);
|
2008-03-16 23:13:31 +01:00
|
|
|
echo '</pre>';
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* ??
|
|
|
|
*
|
|
|
|
* @param unknown_type $val
|
|
|
|
* @return unknown
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function text($val) {
|
2008-02-25 03:10:37 +01:00
|
|
|
if(is_object($val)) {
|
|
|
|
if(method_exists($val, 'hasMethod')) {
|
|
|
|
$hasDebugMethod = $val->hasMethod('debug');
|
2008-02-25 02:06:39 +01:00
|
|
|
} else {
|
2008-02-25 03:10:37 +01:00
|
|
|
$hasDebugMethod = method_exists($val, 'debug');
|
|
|
|
}
|
|
|
|
|
|
|
|
if($hasDebugMethod) {
|
|
|
|
return $val->debug();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(is_array($val)) {
|
|
|
|
$result = "<ul>\n";
|
|
|
|
foreach($val as $k => $v) {
|
|
|
|
$result .= "<li>$k = " . Debug::text($v) . "</li>\n";
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-02-25 03:10:37 +01:00
|
|
|
$val = $result . "</ul>\n";
|
2007-07-19 12:40:28 +02:00
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
} else if (is_object($val)) {
|
|
|
|
$val = var_export($val, true);
|
|
|
|
} else {
|
2008-08-13 03:47:05 +02:00
|
|
|
if(!Director::is_cli() && !Director::is_ajax()) {
|
2008-02-25 03:10:37 +01:00
|
|
|
$val = "<pre style=\"font-family: Courier new\">" . htmlentities($val) . "</pre>\n";
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-02-25 03:10:37 +01:00
|
|
|
|
|
|
|
return $val;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2007-09-14 05:19:34 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
|
|
|
* Show a debugging message
|
|
|
|
*/
|
|
|
|
static function message($message, $showHeader = true) {
|
|
|
|
if(!Director::isLive()) {
|
|
|
|
$caller = Debug::caller();
|
|
|
|
$file = basename($caller['file']);
|
2008-08-09 08:18:32 +02:00
|
|
|
if(Director::is_cli()) {
|
|
|
|
if($showHeader) echo "Debug (line $caller[line] of $file):\n ";
|
|
|
|
echo trim($message) . "\n";
|
|
|
|
} else {
|
|
|
|
echo "<p style=\"background-color: white; color: black; width: 95%; margin: 0.5em; padding: 0.3em; border: 1px #CCC solid\">\n";
|
|
|
|
if($showHeader) echo "<b>Debug (line $caller[line] of $file):</b>\n ";
|
|
|
|
echo Convert::raw2xml(trim($message)) . "</p>\n";
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
2009-07-27 05:52:40 +02:00
|
|
|
|
|
|
|
// Keep track of how many headers have been sent
|
|
|
|
static $headerCount = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a debug message in an HTTP header. Only works if you are
|
|
|
|
* on Dev, and headers have not yet been sent.
|
|
|
|
*
|
|
|
|
* @param string $msg
|
|
|
|
* @param string $prefix (optional)
|
|
|
|
* @return void
|
|
|
|
*/
|
2009-07-27 23:56:27 +02:00
|
|
|
static function header($msg, $prefix = null) {
|
2009-07-27 05:52:40 +02:00
|
|
|
if (Director::isDev() && !headers_sent()) {
|
|
|
|
self::$headerCount++;
|
|
|
|
header('SS-'.self::$headerCount.($prefix?'-'.$prefix:'').': '.$msg);
|
|
|
|
}
|
|
|
|
}
|
2008-08-09 08:24:30 +02:00
|
|
|
|
2008-08-11 00:52:52 +02:00
|
|
|
/**
|
|
|
|
* Log to a standard text file output.
|
|
|
|
*
|
|
|
|
* @param $message string to output
|
|
|
|
*/
|
|
|
|
static function log($message) {
|
|
|
|
$file = dirname(__FILE__).'/../../debug.log';
|
|
|
|
$now = date('r');
|
2009-07-17 01:48:41 +02:00
|
|
|
$oldcontent = (file_exists($file)) ? file_get_contents($file) : '';
|
2008-08-11 00:52:52 +02:00
|
|
|
$content = $oldcontent . "\n\n== $now ==\n$message\n";
|
|
|
|
file_put_contents($file, $content);
|
|
|
|
}
|
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
2008-08-13 23:49:52 +02:00
|
|
|
* Load error handlers into environment.
|
|
|
|
* Caution: The error levels default to E_ALL is the site is in dev-mode (set in main.php).
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
static function loadErrorHandlers() {
|
2008-08-13 01:50:28 +02:00
|
|
|
set_error_handler('errorHandler', error_reporting());
|
2008-02-25 03:10:37 +01:00
|
|
|
set_exception_handler('exceptionHandler');
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
2009-08-19 08:03:57 +02:00
|
|
|
static function noticeHandler($errno, $errstr, $errfile, $errline, $errcontext) {
|
|
|
|
if(error_reporting() == 0) return;
|
|
|
|
|
|
|
|
// Send out the error details to the logger for writing
|
|
|
|
SSLog::log(
|
|
|
|
array(
|
|
|
|
'errno' => $errno,
|
|
|
|
'errstr' => $errstr,
|
|
|
|
'errfile' => $errfile,
|
|
|
|
'errline' => $errline,
|
|
|
|
'errcontext' => $errcontext
|
|
|
|
),
|
|
|
|
SSLog::NOTICE
|
|
|
|
);
|
|
|
|
|
|
|
|
if(Director::isDev()) {
|
|
|
|
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Notice");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Handle a non-fatal warning error thrown by PHP interpreter.
|
|
|
|
*
|
|
|
|
* @param unknown_type $errno
|
|
|
|
* @param unknown_type $errstr
|
|
|
|
* @param unknown_type $errfile
|
|
|
|
* @param unknown_type $errline
|
|
|
|
* @param unknown_type $errcontext
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function warningHandler($errno, $errstr, $errfile, $errline, $errcontext) {
|
2009-08-19 05:55:23 +02:00
|
|
|
if(error_reporting() == 0) return;
|
2007-07-19 12:40:28 +02:00
|
|
|
if(self::$send_warnings_to) self::emailError(self::$send_warnings_to, $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
|
2009-08-19 05:55:23 +02:00
|
|
|
|
|
|
|
// Send out the error details to the logger for writing
|
|
|
|
SSLog::log(
|
|
|
|
array(
|
|
|
|
'errno' => $errno,
|
|
|
|
'errstr' => $errstr,
|
|
|
|
'errfile' => $errfile,
|
|
|
|
'errline' => $errline,
|
|
|
|
'errcontext' => $errcontext
|
|
|
|
),
|
|
|
|
SSLog::WARN
|
|
|
|
);
|
|
|
|
|
2008-08-11 06:02:32 +02:00
|
|
|
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Warning");
|
2007-09-14 05:19:34 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
if(Director::isDev()) {
|
2008-09-12 03:47:39 +02:00
|
|
|
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Warning");
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-14 05:19:34 +02:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Handle a fatal error, depending on the mode of the site (ie: Dev, Test, or Live).
|
|
|
|
*
|
|
|
|
* Runtime execution dies immediately once the error is generated.
|
|
|
|
*
|
|
|
|
* @param unknown_type $errno
|
|
|
|
* @param unknown_type $errstr
|
|
|
|
* @param unknown_type $errfile
|
|
|
|
* @param unknown_type $errline
|
|
|
|
* @param unknown_type $errcontext
|
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function fatalHandler($errno, $errstr, $errfile, $errline, $errcontext) {
|
|
|
|
if(self::$send_errors_to) self::emailError(self::$send_errors_to, $errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
2009-08-19 05:55:23 +02:00
|
|
|
|
|
|
|
// Send out the error details to the logger for writing
|
|
|
|
SSLog::log(
|
|
|
|
array(
|
|
|
|
'errno' => $errno,
|
|
|
|
'errstr' => $errstr,
|
|
|
|
'errfile' => $errfile,
|
|
|
|
'errline' => $errline,
|
|
|
|
'errcontext' => $errcontext
|
|
|
|
),
|
|
|
|
SSLog::ERR
|
|
|
|
);
|
|
|
|
|
2008-08-11 06:02:32 +02:00
|
|
|
self::log_error_if_necessary( $errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
|
|
|
|
|
|
|
if(Director::isDev() || Director::is_cli()) {
|
2009-08-19 05:55:23 +02:00
|
|
|
self::showError($errno, $errstr, $errfile, $errline, $errcontext, "Error");
|
2007-09-14 05:19:34 +02:00
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
} else {
|
2009-08-19 07:41:58 +02:00
|
|
|
self::friendlyError();
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-08-11 06:02:32 +02:00
|
|
|
exit(1);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-08-09 08:24:30 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Render a user-facing error page, using the default HTML error template
|
2008-10-01 16:43:43 +02:00
|
|
|
* rendered by {@link ErrorPage} if it exists. Doesn't use the standard {@link HTTPResponse} class
|
|
|
|
* the keep dependencies minimal.
|
|
|
|
*
|
|
|
|
* @uses ErrorPage
|
2008-08-09 08:24:30 +02:00
|
|
|
*
|
2008-10-01 16:43:43 +02:00
|
|
|
* @param int $statusCode HTTP Status Code (Default: 500)
|
|
|
|
* @param string $friendlyErrorMessage User-focused error message. Should not contain code pointers or "tech-speak".
|
|
|
|
* Used in the HTTP Header and ajax responses.
|
|
|
|
* @param string $friendlyErrorDetail Detailed user-focused message. Is just used if no {@link ErrorPage} is found
|
|
|
|
* for this specific status code.
|
|
|
|
* @return string HTML error message for non-ajax requests, plaintext for ajax-request.
|
2008-08-09 08:24:30 +02:00
|
|
|
*/
|
2008-10-01 16:43:43 +02:00
|
|
|
static function friendlyError($statusCode = 500, $friendlyErrorMessage = null, $friendlyErrorDetail = null) {
|
|
|
|
if(!$friendlyErrorMessage) $friendlyErrorMessage = 'There has been an error';
|
|
|
|
if(!$friendlyErrorDetail) $friendlyErrorDetail = 'The website server has not been able to respond to your request.';
|
2007-07-19 12:40:28 +02:00
|
|
|
|
2008-10-01 16:43:43 +02:00
|
|
|
if(!headers_sent()) header($_SERVER['SERVER_PROTOCOL'] . " $statusCode $friendlyErrorMessage");
|
2007-09-14 05:19:34 +02:00
|
|
|
|
2008-10-01 16:43:43 +02:00
|
|
|
if(Director::is_ajax()) {
|
|
|
|
echo $friendlyErrorMessage;
|
2007-07-19 12:40:28 +02:00
|
|
|
} else {
|
2009-05-20 00:11:33 +02:00
|
|
|
$errorFilePath = ErrorPage::get_filepath_for_errorcode($statusCode, Translatable::get_current_locale());
|
2009-04-29 03:20:24 +02:00
|
|
|
if(file_exists($errorFilePath)) {
|
2009-05-04 04:17:56 +02:00
|
|
|
echo file_get_contents($errorFilePath);
|
2007-07-19 12:40:28 +02:00
|
|
|
} else {
|
2008-10-01 16:43:43 +02:00
|
|
|
$renderer = new DebugView();
|
|
|
|
$renderer->writeHeader();
|
|
|
|
$renderer->writeInfo("Website Error", $friendlyErrorMessage, $friendlyErrorDetail);
|
|
|
|
|
|
|
|
if(Email::getAdminEmail()) {
|
|
|
|
$mailto = Email::obfuscate(Email::getAdminEmail());
|
|
|
|
$renderer->writeParagraph('Contact an administrator: ' . $mailto . '');
|
|
|
|
}
|
|
|
|
|
|
|
|
$renderer->writeFooter();
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-11 06:02:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an instance of an appropriate DebugView object.
|
|
|
|
*/
|
|
|
|
static function create_debug_view() {
|
2008-09-16 20:12:07 +02:00
|
|
|
if(Director::is_cli() || Director::is_ajax()) return new CliDebugView();
|
2008-08-11 06:02:32 +02:00
|
|
|
else return new DebugView();
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Render a developer facing error page, showing the stack trace and details
|
|
|
|
* of the code where the error occured.
|
|
|
|
*
|
|
|
|
* @param unknown_type $errno
|
|
|
|
* @param unknown_type $errstr
|
|
|
|
* @param unknown_type $errfile
|
|
|
|
* @param unknown_type $errline
|
|
|
|
* @param unknown_type $errcontext
|
|
|
|
*/
|
2008-09-12 03:47:39 +02:00
|
|
|
static function showError($errno, $errstr, $errfile, $errline, $errcontext, $errtype) {
|
|
|
|
if(!headers_sent()) {
|
|
|
|
$errText = "$errtype: \"$errstr\" at line $errline of $errfile";
|
|
|
|
$errText = str_replace(array("\n","\r")," ",$errText);
|
2008-10-01 16:43:43 +02:00
|
|
|
if(!headers_sent()) header($_SERVER['SERVER_PROTOCOL'] . " 500 $errText");
|
2008-09-16 20:15:26 +02:00
|
|
|
|
|
|
|
// if error is displayed through ajax with CliDebugView, use plaintext output
|
|
|
|
if(Director::is_ajax()) header('Content-Type: text/plain');
|
2008-09-12 03:47:39 +02:00
|
|
|
}
|
2008-09-16 20:12:07 +02:00
|
|
|
|
|
|
|
// Legacy error handling for customized prototype.js Ajax.Base.responseIsSuccess()
|
|
|
|
// if(Director::is_ajax()) echo "ERROR:\n";
|
|
|
|
|
|
|
|
$reporter = self::create_debug_view();
|
|
|
|
|
|
|
|
// Coupling alert: This relies on knowledge of how the director gets its URL, it could be improved.
|
|
|
|
$httpRequest = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_REQUEST['url'];
|
|
|
|
if(isset($_SERVER['REQUEST_METHOD'])) $httpRequest = $_SERVER['REQUEST_METHOD'] . ' ' . $httpRequest;
|
2008-08-11 06:02:32 +02:00
|
|
|
|
2008-09-16 20:12:07 +02:00
|
|
|
$reporter->writeHeader($httpRequest);
|
|
|
|
$reporter->writeError($httpRequest, $errno, $errstr, $errfile, $errline, $errcontext);
|
2008-08-11 06:02:32 +02:00
|
|
|
|
2008-09-16 20:12:07 +02:00
|
|
|
$lines = file($errfile);
|
2008-08-13 05:54:50 +02:00
|
|
|
|
2008-09-16 20:12:07 +02:00
|
|
|
// Make the array 1-based
|
|
|
|
array_unshift($lines,"");
|
|
|
|
unset($lines[0]);
|
2008-08-13 05:54:50 +02:00
|
|
|
|
2008-09-16 20:12:07 +02:00
|
|
|
$offset = $errline-10;
|
|
|
|
$lines = array_slice($lines, $offset, 16, true);
|
|
|
|
$reporter->writeSourceFragment($lines, $errline);
|
2008-08-11 06:02:32 +02:00
|
|
|
|
2009-01-20 22:30:12 +01:00
|
|
|
$reporter->writeTrace(($errcontext ? $errcontext : debug_backtrace()));
|
2008-09-16 20:12:07 +02:00
|
|
|
$reporter->writeFooter();
|
|
|
|
exit(1);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-08-09 08:18:32 +02:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Utility method to render a snippet of PHP source code, from selected file
|
|
|
|
* and highlighting the given line number.
|
|
|
|
*
|
|
|
|
* @param string $errfile
|
|
|
|
* @param int $errline
|
|
|
|
*/
|
2008-08-09 08:18:32 +02:00
|
|
|
static function showLines($errfile, $errline) {
|
|
|
|
$lines = file($errfile);
|
|
|
|
$offset = $errline-10;
|
|
|
|
$lines = array_slice($lines, $offset, 16);
|
|
|
|
echo '<pre>';
|
|
|
|
$offset++;
|
|
|
|
foreach($lines as $line) {
|
|
|
|
$line = htmlentities($line);
|
|
|
|
if ($offset == $errline) {
|
|
|
|
echo "<span>$offset</span> <span class=\"error\">$line</span>";
|
|
|
|
} else {
|
|
|
|
echo "<span>$offset</span> $line";
|
|
|
|
}
|
|
|
|
$offset++;
|
|
|
|
}
|
|
|
|
echo '</pre>';
|
|
|
|
}
|
2007-09-14 05:19:34 +02:00
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
2009-08-19 05:55:23 +02:00
|
|
|
* Dispatch an email notification message when an error is triggered.
|
|
|
|
* @deprecated 2.5
|
|
|
|
* To create error logs by email, use this code instead:
|
|
|
|
* <code>
|
|
|
|
* $emailWriter = new SSLogEmailWriter('my@email.com');
|
|
|
|
* SSLog::add_writer($emailWriter, SSLog::ERR);
|
|
|
|
* </code>
|
|
|
|
*
|
2008-09-22 18:03:19 +02:00
|
|
|
* @param string $emailAddress
|
|
|
|
* @param string $errno
|
|
|
|
* @param string $errstr
|
|
|
|
* @param string $errfile
|
|
|
|
* @param int $errline
|
|
|
|
* @param string $errcontext
|
|
|
|
* @param string $errorType "warning" or "error"
|
|
|
|
* @return boolean
|
2008-08-09 08:24:30 +02:00
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function emailError($emailAddress, $errno, $errstr, $errfile, $errline, $errcontext, $errorType = "Error") {
|
2009-08-19 05:55:23 +02:00
|
|
|
user_error('Debug::send_errors_to() and Debug::emailError() is deprecated. Please use SSLog instead.
|
|
|
|
See the class documentation for SSLog for more information.', E_USER_NOTICE);
|
|
|
|
$priority = ($errorType == 'Error') ? SSLog::ERR : SSLog::WARN;
|
|
|
|
$writer = new SSLogEmailWriter($emailAddress);
|
|
|
|
SSLog::add_writer($writer, $priority);
|
|
|
|
SSLog::log(
|
|
|
|
array(
|
|
|
|
'errno' => $errno,
|
|
|
|
'errstr' => $errstr,
|
|
|
|
'errfile' => $errfile,
|
|
|
|
'errline' => $errline,
|
|
|
|
'errcontext' => $errcontext
|
|
|
|
),
|
|
|
|
$priority
|
|
|
|
);
|
|
|
|
SSLog::remove_writer($writer);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
2008-08-11 06:02:32 +02:00
|
|
|
/**
|
|
|
|
* Log the given error, if self::$log_errors is set.
|
2008-09-22 18:03:19 +02:00
|
|
|
* Uses the native error_log() funtion in PHP.
|
|
|
|
*
|
|
|
|
* Format: [d-M-Y h:i:s] <type> at <file> line <line>: <errormessage> <url>
|
|
|
|
*
|
|
|
|
* @todo Detect script path for CLI errors
|
|
|
|
* @todo Log detailed errors to full file
|
2008-08-11 06:02:32 +02:00
|
|
|
*/
|
|
|
|
protected static function log_error_if_necessary($errno, $errstr, $errfile, $errline, $errcontext, $errtype) {
|
|
|
|
if(self::$log_errors_to) {
|
|
|
|
$shortFile = "../" . self::$log_errors_to;
|
|
|
|
$fullFile = $shortFile . '.full';
|
|
|
|
|
|
|
|
$relfile = Director::makeRelative($errfile);
|
|
|
|
if($relfile[0] == '/') $relfile = substr($relfile,1);
|
|
|
|
|
|
|
|
$urlSuffix = "";
|
|
|
|
if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] && isset($_SERVER['REQUEST_URI'])) {
|
|
|
|
$urlSuffix = " (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])";
|
|
|
|
}
|
|
|
|
|
|
|
|
error_log('[' . date('d-M-Y h:i:s') . "] $errtype at $relfile line $errline: $errstr$urlSuffix\n", 3, $shortFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
/**
|
|
|
|
* @param string $server IP-Address or domain
|
2009-08-19 07:41:58 +02:00
|
|
|
* @deprecated 2.5 See SSLog on setting up error email notification
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
static function set_custom_smtp_server($server) {
|
|
|
|
self::$custom_smtp_server = $server;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
2009-08-19 07:41:58 +02:00
|
|
|
* @deprecated 2.5 See SSLog on setting up error email notification
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
static function get_custom_smtp_server() {
|
|
|
|
return self::$custom_smtp_server;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send errors to the given email address.
|
|
|
|
* Can be used like so:
|
|
|
|
* if(Director::isLive()) Debug::send_errors_to("sam@silverstripe.com");
|
2009-08-19 05:55:23 +02:00
|
|
|
*
|
2009-08-19 07:41:58 +02:00
|
|
|
* @deprecated 2.5 See SSLog on setting up error email notification
|
|
|
|
*
|
2008-09-22 18:03:19 +02:00
|
|
|
* @param string $emailAddress The email address to send errors to
|
2008-12-04 23:38:32 +01:00
|
|
|
* @param string $sendWarnings Set to true to send warnings as well as errors (Default: false)
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2008-12-04 23:38:32 +01:00
|
|
|
static function send_errors_to($emailAddress, $sendWarnings = false) {
|
2007-07-19 12:40:28 +02:00
|
|
|
self::$send_errors_to = $emailAddress;
|
|
|
|
self::$send_warnings_to = $sendWarnings ? $emailAddress : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
2009-08-19 07:41:58 +02:00
|
|
|
* @deprecated 2.5 See SSLog on setting up error email notification
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
static function get_send_errors_to() {
|
|
|
|
return self::$send_errors_to;
|
|
|
|
}
|
2008-09-22 18:03:19 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $emailAddress
|
2009-08-19 07:41:58 +02:00
|
|
|
* @deprecated 2.5 See SSLog on setting up error email notification
|
2008-09-22 18:03:19 +02:00
|
|
|
*/
|
|
|
|
static function send_warnings_to($emailAddress) {
|
|
|
|
self::$send_warnings_to = $emailAddress;
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
2009-08-19 07:41:58 +02:00
|
|
|
* @deprecated 2.5 See SSLog on setting up error email notification
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
|
|
|
static function get_send_warnings_to() {
|
|
|
|
return self::$send_warnings_to;
|
|
|
|
}
|
2008-08-11 06:02:32 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Call this to enable logging of errors.
|
|
|
|
*/
|
|
|
|
static function log_errors_to($logFile = ".sserrors") {
|
|
|
|
self::$log_errors_to = $logFile;
|
|
|
|
}
|
|
|
|
|
2007-07-19 12:40:28 +02:00
|
|
|
static function caller() {
|
|
|
|
$bt = debug_backtrace();
|
|
|
|
$caller = $bt[2];
|
|
|
|
$caller['line'] = $bt[1]['line'];
|
|
|
|
$caller['file'] = $bt[1]['file'];
|
2007-08-27 07:13:43 +02:00
|
|
|
if(!isset($caller['class'])) $caller['class'] = '';
|
|
|
|
if(!isset($caller['type'])) $caller['type'] = '';
|
2007-07-19 12:40:28 +02:00
|
|
|
return $caller;
|
|
|
|
}
|
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
2009-08-19 05:55:23 +02:00
|
|
|
* @deprecated 2.5 Please use {@link SSBacktrace::backtrace()}
|
2008-08-09 08:24:30 +02:00
|
|
|
*/
|
2007-07-19 12:40:28 +02:00
|
|
|
static function backtrace($returnVal = false, $ignoreAjax = false) {
|
2009-08-19 05:55:23 +02:00
|
|
|
user_error('Debug::backtrace() is deprecated. Please use SSBacktrace::backtrace() instead', E_USER_NOTICE);
|
|
|
|
return SSBacktrace::backtrace($returnVal, $ignoreAjax);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-08-19 05:55:23 +02:00
|
|
|
* @deprecated 2.5 Please use {@link SSBacktrace::get_rendered_backtrace()}
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2009-08-19 05:55:23 +02:00
|
|
|
static function get_rendered_backtrace($bt, $plainText = false) {
|
|
|
|
user_error('Debug::get_rendered_backtrace() is deprecated. Please use SSBacktrace::get_rendered_backtrace() instead', E_USER_NOTICE);
|
|
|
|
return SSBacktrace::get_rendered_backtrace($bt, $plainText);
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2007-11-08 00:46:00 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the user has permissions to run URL debug tools,
|
|
|
|
* else redirect them to log in.
|
|
|
|
*/
|
|
|
|
static function require_developer_login() {
|
|
|
|
if(Director::isDev()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(isset($_SESSION['loggedInAs'])) {
|
|
|
|
// We have to do some raw SQL here, because this method is called in Object::defineMethods().
|
|
|
|
// This means we have to be careful about what objects we create, as we don't want Object::defineMethods()
|
|
|
|
// being called again.
|
|
|
|
// This basically calls Permission::checkMember($_SESSION['loggedInAs'], 'ADMIN');
|
|
|
|
|
|
|
|
$memberID = $_SESSION['loggedInAs'];
|
|
|
|
|
2008-11-24 10:31:14 +01:00
|
|
|
$groups = DB::query("SELECT \"GroupID\" from \"Group_Members\" WHERE \"MemberID\" = " . $memberID);
|
2007-11-08 00:46:00 +01:00
|
|
|
$groupCSV = implode($groups->column(), ',');
|
|
|
|
|
|
|
|
$permission = DB::query("
|
2008-11-24 10:31:14 +01:00
|
|
|
SELECT \"ID\"
|
|
|
|
FROM \"Permission\"
|
2007-11-08 00:46:00 +01:00
|
|
|
WHERE (
|
2008-11-24 10:31:14 +01:00
|
|
|
\"Code\" = 'ADMIN'
|
|
|
|
AND \"Type\" = " . Permission::GRANT_PERMISSION . "
|
|
|
|
AND \"GroupID\" IN ($groupCSV)
|
2007-11-08 00:46:00 +01:00
|
|
|
)
|
|
|
|
")->value();
|
|
|
|
|
|
|
|
if($permission) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This basically does the same as
|
|
|
|
// Security::permissionFailure(null, "You need to login with developer access to make use of debugging tools.");
|
|
|
|
// We have to do this because of how early this method is called in execution.
|
|
|
|
$_SESSION['Security']['Message']['message'] = "You need to login with developer access to make use of debugging tools.";
|
|
|
|
$_SESSION['Security']['Message']['type'] = 'warning';
|
|
|
|
$_SESSION['BackURL'] = $_SERVER['REQUEST_URI'];
|
2008-10-01 16:43:43 +02:00
|
|
|
header($_SERVER['SERVER_PROTOCOL'] . " 302 Found");
|
2007-11-08 00:46:00 +01:00
|
|
|
header("Location: " . Director::baseURL() . "Security/login");
|
|
|
|
die();
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
2008-09-22 18:03:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Generic callback, to catch uncaught exceptions when they bubble up to the top of the call chain.
|
|
|
|
*
|
|
|
|
* @ignore
|
2008-09-22 18:03:19 +02:00
|
|
|
* @param Exception $exception
|
2008-08-09 08:24:30 +02:00
|
|
|
*/
|
2008-02-25 03:10:37 +01:00
|
|
|
function exceptionHandler($exception) {
|
|
|
|
$errno = E_USER_ERROR;
|
|
|
|
$type = get_class($exception);
|
|
|
|
$message = "Uncaught " . $type . ": " . $exception->getMessage();
|
|
|
|
$file = $exception->getFile();
|
|
|
|
$line = $exception->getLine();
|
|
|
|
$context = $exception->getTrace();
|
|
|
|
Debug::fatalHandler($errno, $message, $file, $line, $context);
|
|
|
|
}
|
|
|
|
|
2008-08-09 08:24:30 +02:00
|
|
|
/**
|
|
|
|
* Generic callback to catch standard PHP runtime errors thrown by the interpreter
|
|
|
|
* or manually triggered with the user_error function.
|
2008-08-13 23:49:52 +02:00
|
|
|
* Caution: The error levels default to E_ALL is the site is in dev-mode (set in main.php).
|
2008-08-09 08:24:30 +02:00
|
|
|
*
|
|
|
|
* @ignore
|
2008-09-22 18:03:19 +02:00
|
|
|
* @param int $errno
|
|
|
|
* @param string $errstr
|
|
|
|
* @param string $errfile
|
|
|
|
* @param int $errline
|
2008-08-09 08:24:30 +02:00
|
|
|
*/
|
2009-03-22 09:38:14 +01:00
|
|
|
function errorHandler($errno, $errstr, $errfile, $errline) {
|
|
|
|
$bt = debug_backtrace();
|
2007-07-19 12:40:28 +02:00
|
|
|
switch($errno) {
|
|
|
|
case E_ERROR:
|
|
|
|
case E_CORE_ERROR:
|
|
|
|
case E_USER_ERROR:
|
2009-06-17 13:36:49 +02:00
|
|
|
Debug::fatalHandler($errno, $errstr, $errfile, $errline, null);
|
2007-07-19 12:40:28 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case E_WARNING:
|
|
|
|
case E_CORE_WARNING:
|
|
|
|
case E_USER_WARNING:
|
2009-06-17 13:36:49 +02:00
|
|
|
Debug::warningHandler($errno, $errstr, $errfile, $errline, null);
|
2007-07-19 12:40:28 +02:00
|
|
|
break;
|
2008-03-16 23:13:31 +01:00
|
|
|
|
2009-08-19 08:03:57 +02:00
|
|
|
case E_NOTICE:
|
|
|
|
case E_USER_NOTICE:
|
|
|
|
Debug::noticeHandler($errno, $errstr, $errfile, $errline, null);
|
|
|
|
break;
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|
|
|
|
}
|