2007-07-19 12:40:28 +02:00
|
|
|
<?php
|
2015-07-24 00:53:41 +02:00
|
|
|
|
2016-08-19 00:51:35 +02:00
|
|
|
namespace SilverStripe\Dev;
|
|
|
|
|
|
|
|
use SilverStripe\Control\Director;
|
2016-12-23 03:41:41 +01:00
|
|
|
use SilverStripe\Control\HTTPRequest;
|
2016-08-19 00:51:35 +02:00
|
|
|
use SilverStripe\Core\Injector\Injector;
|
2016-06-15 06:03:16 +02:00
|
|
|
use SilverStripe\ORM\DB;
|
2016-06-23 01:37:22 +02:00
|
|
|
use SilverStripe\Security\Permission;
|
|
|
|
use SilverStripe\Security\Security;
|
|
|
|
|
2008-02-25 03:10:37 +01:00
|
|
|
/**
|
2008-03-16 23:13:31 +01:00
|
|
|
* Supports debugging and core error handling.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
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:
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2009-08-19 08:03:57 +02:00
|
|
|
* - Notice
|
2008-03-16 23:13:31 +01:00
|
|
|
* - Warning
|
|
|
|
* - Error
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
2008-03-16 23:13:31 +01:00
|
|
|
* Uncaught exceptions are currently passed to the debug
|
|
|
|
* reporter as standard PHP errors.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
API CHANGE: Renamed conflicting classes to have an "SS_" namespace, and renamed existing "SS" namespace to "SS_". The affected classes are: HTTPRequest, HTTPResponse, Query, Database, SSBacktrace, SSCli, SSDatetime, SSDatetimeTest, SSLog, SSLogTest, SSLogEmailWriter, SSLogErrorEmailFormatter, SSLogErrorFileFormatter, SSLogFileWriter and SSZendLog.
MINOR: Replaced usage of renamed classes with the new namespaced name.
From: Andrew Short <andrewjshort@gmail.com>
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@90075 467b73ca-7a2a-4603-9d3b-597d59a354a9
2009-10-26 04:06:31 +01:00
|
|
|
* Errors handled by this class are passed along to {@link SS_Log}.
|
|
|
|
* For configuration information, see the {@link SS_Log}
|
2009-08-19 07:41:58 +02:00
|
|
|
* class documentation.
|
2014-08-15 08:53:05 +02:00
|
|
|
*
|
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
|
2007-07-19 12:40:28 +02:00
|
|
|
*/
|
2016-11-29 00:31:16 +01:00
|
|
|
class Debug
|
|
|
|
{
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Show the contents of val in a debug-friendly way.
|
|
|
|
* Debug::show() is intended to be equivalent to dprintr()
|
2016-12-23 03:41:41 +01:00
|
|
|
* Does not work on live mode.
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
|
|
|
* @param mixed $val
|
|
|
|
* @param bool $showHeader
|
2016-12-23 03:41:41 +01:00
|
|
|
* @param HTTPRequest|null $request
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2016-12-23 03:41:41 +01:00
|
|
|
public static function show($val, $showHeader = true, HTTPRequest $request = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
// Don't show on live
|
|
|
|
if (Director::isLive()) {
|
|
|
|
return;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
2016-12-23 03:41:41 +01:00
|
|
|
|
|
|
|
echo static::create_debug_view($request)
|
|
|
|
->debugVariable($val, static::caller(), $showHeader);
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-23 03:41:41 +01:00
|
|
|
* Close out the show dumper.
|
|
|
|
* Does not work on live mode
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
|
|
|
* @param mixed $val
|
2016-12-23 03:41:41 +01:00
|
|
|
* @param bool $showHeader
|
|
|
|
* @param HTTPRequest $request
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2016-12-23 03:41:41 +01:00
|
|
|
public static function endshow($val, $showHeader = true, HTTPRequest $request = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
// Don't show on live
|
|
|
|
if (Director::isLive()) {
|
|
|
|
return;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
2016-12-23 03:41:41 +01:00
|
|
|
|
|
|
|
echo static::create_debug_view($request)
|
|
|
|
->debugVariable($val, static::caller(), $showHeader);
|
|
|
|
|
|
|
|
die();
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Quick dump of a variable.
|
2016-12-23 03:41:41 +01:00
|
|
|
* Note: This method will output in live!
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
|
|
|
* @param mixed $val
|
2016-12-23 03:41:41 +01:00
|
|
|
* @param HTTPRequest $request Current request to influence output format
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2016-12-23 03:41:41 +01:00
|
|
|
public static function dump($val, HTTPRequest $request = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
echo self::create_debug_view($request)
|
|
|
|
->renderVariable($val, self::caller());
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-23 03:41:41 +01:00
|
|
|
* Get debug text for this object
|
|
|
|
*
|
2016-11-29 00:31:16 +01:00
|
|
|
* @param mixed $val
|
2016-12-23 03:41:41 +01:00
|
|
|
* @param HTTPRequest $request
|
2016-11-29 00:31:16 +01:00
|
|
|
* @return string
|
|
|
|
*/
|
2016-12-23 03:41:41 +01:00
|
|
|
public static function text($val, HTTPRequest $request = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
return static::create_debug_view($request)
|
|
|
|
->debugVariableText($val);
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-12-23 03:41:41 +01:00
|
|
|
* Show a debugging message.
|
|
|
|
* Does not work on live mode
|
2016-11-29 00:31:16 +01:00
|
|
|
*
|
|
|
|
* @param string $message
|
|
|
|
* @param bool $showHeader
|
2016-12-23 03:41:41 +01:00
|
|
|
* @param HTTPRequest|null $request
|
2016-11-29 00:31:16 +01:00
|
|
|
*/
|
2016-12-23 03:41:41 +01:00
|
|
|
public static function message($message, $showHeader = true, HTTPRequest $request = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
// Don't show on live
|
|
|
|
if (Director::isLive()) {
|
|
|
|
return;
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
2016-12-23 03:41:41 +01:00
|
|
|
|
|
|
|
echo static::create_debug_view($request)
|
|
|
|
->renderMessage($message, static::caller(), $showHeader);
|
2016-11-29 00:31:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create an instance of an appropriate DebugView object.
|
|
|
|
*
|
2016-12-23 03:41:41 +01:00
|
|
|
* @param HTTPRequest $request Optional request to target this view for
|
2016-11-29 00:31:16 +01:00
|
|
|
* @return DebugView
|
|
|
|
*/
|
2016-12-23 03:41:41 +01:00
|
|
|
public static function create_debug_view(HTTPRequest $request = null)
|
2016-11-29 00:31:16 +01:00
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
$service = static::supportsHTML($request)
|
|
|
|
? DebugView::class
|
|
|
|
: CliDebugView::class;
|
2016-11-29 00:31:16 +01:00
|
|
|
return Injector::inst()->get($service);
|
|
|
|
}
|
|
|
|
|
2016-12-23 03:41:41 +01:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2016-11-29 00:31:16 +01:00
|
|
|
/**
|
|
|
|
* Check if the user has permissions to run URL debug tools,
|
|
|
|
* else redirect them to log in.
|
|
|
|
*/
|
|
|
|
public static function require_developer_login()
|
|
|
|
{
|
2016-12-23 03:41:41 +01:00
|
|
|
// Don't require login for dev mode
|
2016-11-29 00:31:16 +01:00
|
|
|
if (Director::isDev()) {
|
|
|
|
return;
|
|
|
|
}
|
2016-12-23 03:41:41 +01:00
|
|
|
|
2016-11-29 00:31:16 +01:00
|
|
|
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(
|
|
|
|
'
|
2013-06-21 00:32:08 +02:00
|
|
|
SELECT "ID" FROM "Permission"
|
|
|
|
INNER JOIN "Group_Members" ON "Permission"."GroupID" = "Group_Members"."GroupID"
|
2014-08-15 08:53:05 +02:00
|
|
|
WHERE "Permission"."Code" = ?
|
|
|
|
AND "Permission"."Type" = ?
|
2013-06-21 00:32:08 +02:00
|
|
|
AND "Group_Members"."MemberID" = ?',
|
2016-11-29 00:31:16 +01:00
|
|
|
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();
|
|
|
|
}
|
2007-07-19 12:40:28 +02:00
|
|
|
}
|