mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
248 lines
7.2 KiB
PHP
248 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Dev;
|
|
|
|
use SilverStripe\Control\Director;
|
|
use SilverStripe\Control\HTTPRequest;
|
|
use SilverStripe\Core\Injector\Injector;
|
|
use SilverStripe\ORM\DB;
|
|
use SilverStripe\Security\Permission;
|
|
use SilverStripe\Security\Security;
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
class Debug
|
|
{
|
|
|
|
/**
|
|
* Show the contents of val in a debug-friendly way.
|
|
* Debug::show() is intended to be equivalent to dprintr()
|
|
* Does not work on live mode.
|
|
*
|
|
* @param mixed $val
|
|
* @param bool $showHeader
|
|
* @param HTTPRequest|null $request
|
|
*/
|
|
public static function show($val, $showHeader = true, HTTPRequest $request = null)
|
|
{
|
|
// Don't show on live
|
|
if (Director::isLive()) {
|
|
return;
|
|
}
|
|
|
|
echo static::create_debug_view($request)
|
|
->debugVariable($val, static::caller(), $showHeader);
|
|
}
|
|
|
|
/**
|
|
* Returns the caller for a specific method
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function caller()
|
|
{
|
|
$bt = debug_backtrace();
|
|
$caller = isset($bt[2]) ? $bt[2] : array();
|
|
$caller['line'] = $bt[1]['line'];
|
|
$caller['file'] = $bt[1]['file'];
|
|
if (!isset($caller['class'])) {
|
|
$caller['class'] = '';
|
|
}
|
|
if (!isset($caller['type'])) {
|
|
$caller['type'] = '';
|
|
}
|
|
if (!isset($caller['function'])) {
|
|
$caller['function'] = '';
|
|
}
|
|
return $caller;
|
|
}
|
|
|
|
/**
|
|
* Close out the show dumper.
|
|
* Does not work on live mode
|
|
*
|
|
* @param mixed $val
|
|
* @param bool $showHeader
|
|
* @param HTTPRequest $request
|
|
*/
|
|
public static function endshow($val, $showHeader = true, HTTPRequest $request = null)
|
|
{
|
|
// Don't show on live
|
|
if (Director::isLive()) {
|
|
return;
|
|
}
|
|
|
|
echo static::create_debug_view($request)
|
|
->debugVariable($val, static::caller(), $showHeader);
|
|
|
|
die();
|
|
}
|
|
|
|
/**
|
|
* Quick dump of a variable.
|
|
* Note: This method will output in live!
|
|
*
|
|
* @param mixed $val
|
|
* @param HTTPRequest $request Current request to influence output format
|
|
*/
|
|
public static function dump($val, HTTPRequest $request = null)
|
|
{
|
|
echo self::create_debug_view($request)
|
|
->renderVariable($val, self::caller());
|
|
}
|
|
|
|
/**
|
|
* Get debug text for this object
|
|
*
|
|
* @param mixed $val
|
|
* @param HTTPRequest $request
|
|
* @return string
|
|
*/
|
|
public static function text($val, HTTPRequest $request = null)
|
|
{
|
|
return static::create_debug_view($request)
|
|
->debugVariableText($val);
|
|
}
|
|
|
|
/**
|
|
* Show a debugging message.
|
|
* Does not work on live mode
|
|
*
|
|
* @param string $message
|
|
* @param bool $showHeader
|
|
* @param HTTPRequest|null $request
|
|
*/
|
|
public static function message($message, $showHeader = true, HTTPRequest $request = null)
|
|
{
|
|
// Don't show on live
|
|
if (Director::isLive()) {
|
|
return;
|
|
}
|
|
|
|
echo static::create_debug_view($request)
|
|
->renderMessage($message, static::caller(), $showHeader);
|
|
}
|
|
|
|
/**
|
|
* Create an instance of an appropriate DebugView object.
|
|
*
|
|
* @param HTTPRequest $request Optional request to target this view for
|
|
* @return DebugView
|
|
*/
|
|
public static function create_debug_view(HTTPRequest $request = null)
|
|
{
|
|
$service = static::supportsHTML($request)
|
|
? DebugView::class
|
|
: CliDebugView::class;
|
|
return Injector::inst()->get($service);
|
|
}
|
|
|
|
/**
|
|
* Determine if the given request supports html output
|
|
*
|
|
* @param HTTPRequest $request
|
|
* @return bool
|
|
*/
|
|
protected static function supportsHTML(HTTPRequest $request = null)
|
|
{
|
|
// No HTML output in CLI
|
|
if (Director::is_cli()) {
|
|
return false;
|
|
}
|
|
|
|
// Get current request if registered
|
|
if (!$request && Injector::inst()->has(HTTPRequest::class)) {
|
|
$request = Injector::inst()->get(HTTPRequest::class);
|
|
}
|
|
if (!$request) {
|
|
return false;
|
|
}
|
|
// Request must include text/html
|
|
$accepted = $request->getAcceptMimetypes(false);
|
|
|
|
// Explicit opt in
|
|
if (in_array('text/html', $accepted)) {
|
|
return true;
|
|
};
|
|
|
|
// Implicit opt-out
|
|
if (in_array('application/json', $accepted)) {
|
|
return false;
|
|
}
|
|
|
|
// Fallback to wildcard comparison
|
|
if (in_array('*/*', $accepted)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if the user has permissions to run URL debug tools,
|
|
* else redirect them to log in.
|
|
*/
|
|
public static function require_developer_login()
|
|
{
|
|
// Don't require login for dev mode
|
|
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['SilverStripe\\Security\\Security']['Message']['message']
|
|
= "You need to login with developer access to make use of debugging tools.";
|
|
$_SESSION['SilverStripe\\Security\\Security']['Message']['type'] = 'warning';
|
|
$_SESSION['BackURL'] = $_SERVER['REQUEST_URI'];
|
|
header($_SERVER['SERVER_PROTOCOL'] . " 302 Found");
|
|
header("Location: " . Director::baseURL() . Security::login_url());
|
|
die();
|
|
}
|
|
}
|