mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
1b8d295767
API CHANGE: Debug::showError(), Debug::showLines(), Debug::log(), and Debug::header() removed NEW: Logging provided ZendLog has been removed and monolog introduced instead as a dependency. The “ErrorLogger” injection point is now the used as the logger that errors are fed into, and implements PSR-3’s Psr\Log\LoggerInterface. The SS_ERROR_LOG setting expect a Monolog Logger to be provided as the ErrorLogger.
207 lines
5.7 KiB
PHP
207 lines
5.7 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Supports debugging and core error handling.
|
|
*
|
|
* Attaches custom methods to the default error handling hooks
|
|
* in PHP. Currently, two levels of error are supported:
|
|
*
|
|
* - Notice
|
|
* - Warning
|
|
* - Error
|
|
*
|
|
* Uncaught exceptions are currently passed to the debug
|
|
* reporter as standard PHP errors.
|
|
*
|
|
* Errors handled by this class are passed along to {@link SS_Log}.
|
|
* For configuration information, see the {@link SS_Log}
|
|
* class documentation.
|
|
*
|
|
* @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
|
|
*
|
|
* @package framework
|
|
* @subpackage dev
|
|
*/
|
|
class Debug {
|
|
|
|
/**
|
|
* Show the contents of val in a debug-friendly way.
|
|
* Debug::show() is intended to be equivalent to dprintr()
|
|
*/
|
|
public static function show($val, $showHeader = true) {
|
|
if(!Director::isLive()) {
|
|
if($showHeader) {
|
|
$caller = Debug::caller();
|
|
if(Director::is_ajax() || Director::is_cli())
|
|
echo "Debug ($caller[class]$caller[type]$caller[function]() in " . basename($caller['file'])
|
|
. ":$caller[line])\n";
|
|
else
|
|
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]()"
|
|
. " \nin " . basename($caller['file']) . ":$caller[line])</span>\n</h3>\n";
|
|
}
|
|
|
|
echo Debug::text($val);
|
|
|
|
if(!Director::is_ajax() && !Director::is_cli()) echo "</div>";
|
|
else echo "\n\n";
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns the caller for a specific method
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function caller() {
|
|
$bt = debug_backtrace();
|
|
$caller = $bt[2];
|
|
$caller['line'] = $bt[1]['line'];
|
|
$caller['file'] = $bt[1]['file'];
|
|
if(!isset($caller['class'])) $caller['class'] = '';
|
|
if(!isset($caller['type'])) $caller['type'] = '';
|
|
return $caller;
|
|
}
|
|
|
|
/**
|
|
* Close out the show dumper
|
|
*
|
|
* @param mixed $val
|
|
*/
|
|
public 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]()"
|
|
. " \nin " . basename($caller['file']) . ":$caller[line])</span>\n</h3>\n";
|
|
echo Debug::text($val);
|
|
die();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Quick dump of a variable.
|
|
*
|
|
* @param mixed $val
|
|
*/
|
|
public static function dump($val) {
|
|
self::create_debug_view()->writeVariable($val, self::caller());
|
|
}
|
|
|
|
/**
|
|
* ??
|
|
*
|
|
* @param unknown_type $val
|
|
* @return unknown
|
|
*/
|
|
public static function text($val) {
|
|
if(is_object($val)) {
|
|
if(method_exists($val, 'hasMethod')) {
|
|
$hasDebugMethod = $val->hasMethod('debug');
|
|
} else {
|
|
$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";
|
|
}
|
|
$val = $result . "</ul>\n";
|
|
|
|
} else if (is_object($val)) {
|
|
$val = var_export($val, true);
|
|
} else if (is_bool($val)) {
|
|
$val = $val ? 'true' : 'false';
|
|
$val = '(bool) ' . $val;
|
|
} else {
|
|
if(!Director::is_cli() && !Director::is_ajax()) {
|
|
$val = "<pre style=\"font-family: Courier new\">" . htmlentities($val, ENT_COMPAT, 'UTF-8')
|
|
. "</pre>\n";
|
|
}
|
|
}
|
|
|
|
return $val;
|
|
}
|
|
|
|
/**
|
|
* Show a debugging message
|
|
*/
|
|
public static function message($message, $showHeader = true) {
|
|
if(!Director::isLive()) {
|
|
$caller = Debug::caller();
|
|
$file = basename($caller['file']);
|
|
if(Director::is_cli()) {
|
|
if($showHeader) echo "Debug (line $caller[line] of $file):\n ";
|
|
echo $message . "\n";
|
|
} else {
|
|
echo "<p class=\"message warning\">\n";
|
|
if($showHeader) echo "<b>Debug (line $caller[line] of $file):</b>\n ";
|
|
echo Convert::raw2xml($message) . "</p>\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create an instance of an appropriate DebugView object.
|
|
*
|
|
* @return DebugView
|
|
*/
|
|
public static function create_debug_view() {
|
|
$service = Director::is_cli() || Director::is_ajax()
|
|
? 'CliDebugView'
|
|
: 'DebugView';
|
|
return Injector::inst()->get($service);
|
|
}
|
|
|
|
/**
|
|
* Check if the user has permissions to run URL debug tools,
|
|
* else redirect them to log in.
|
|
*/
|
|
public 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');
|
|
|
|
// @TODO - Rewrite safely using DataList::filter
|
|
$memberID = $_SESSION['loggedInAs'];
|
|
$permission = DB::prepared_query('
|
|
SELECT "ID" FROM "Permission"
|
|
INNER JOIN "Group_Members" ON "Permission"."GroupID" = "Group_Members"."GroupID"
|
|
WHERE "Permission"."Code" = ?
|
|
AND "Permission"."Type" = ?
|
|
AND "Group_Members"."MemberID" = ?',
|
|
array(
|
|
'ADMIN', // Code
|
|
Permission::GRANT_PERMISSION, // Type
|
|
$memberID // MemberID
|
|
)
|
|
)->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'];
|
|
header($_SERVER['SERVER_PROTOCOL'] . " 302 Found");
|
|
header("Location: " . Director::baseURL() . Security::login_url());
|
|
die();
|
|
}
|
|
}
|