Debug::endshow()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 3
dl 0
loc 11
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Dev;
4
5
use SilverStripe\Control\Director;
6
use SilverStripe\Control\HTTPRequest;
7
use SilverStripe\Core\Injector\Injector;
8
use SilverStripe\ORM\DB;
9
use SilverStripe\Security\Permission;
10
use SilverStripe\Security\Security;
11
12
/**
13
 * Supports debugging and core error handling.
14
 *
15
 * Attaches custom methods to the default error handling hooks
16
 * in PHP. Currently, two levels of error are supported:
17
 *
18
 * - Notice
19
 * - Warning
20
 * - Error
21
 *
22
 * Uncaught exceptions are currently passed to the debug
23
 * reporter as standard PHP errors.
24
 *
25
 * Errors handled by this class are passed along to {@link SS_Log}.
26
 * For configuration information, see the {@link SS_Log}
27
 * class documentation.
28
 *
29
 * @todo add support for user defined config: Debug::die_on_notice(true | false)
30
 * @todo better way of figuring out the error context to display in highlighted source
31
 */
32
class Debug
33
{
34
35
    /**
36
     * Show the contents of val in a debug-friendly way.
37
     * Debug::show() is intended to be equivalent to dprintr()
38
     * Does not work on live mode.
39
     *
40
     * @param mixed $val
41
     * @param bool $showHeader
42
     * @param HTTPRequest|null $request
43
     */
44
    public static function show($val, $showHeader = true, HTTPRequest $request = null)
45
    {
46
        // Don't show on live
47
        if (Director::isLive()) {
48
            return;
49
        }
50
51
        echo static::create_debug_view($request)
52
            ->debugVariable($val, static::caller(), $showHeader);
53
    }
54
55
    /**
56
     * Returns the caller for a specific method
57
     *
58
     * @return array
59
     */
60
    public static function caller()
61
    {
62
        $bt = debug_backtrace();
63
        $caller = isset($bt[2]) ? $bt[2] : array();
64
        $caller['line'] = $bt[1]['line'];
65
        $caller['file'] = $bt[1]['file'];
66
        if (!isset($caller['class'])) {
67
            $caller['class'] = '';
68
        }
69
        if (!isset($caller['type'])) {
70
            $caller['type'] = '';
71
        }
72
        if (!isset($caller['function'])) {
73
            $caller['function'] = '';
74
        }
75
        return $caller;
76
    }
77
78
    /**
79
     * Close out the show dumper.
80
     * Does not work on live mode
81
     *
82
     * @param mixed $val
83
     * @param bool $showHeader
84
     * @param HTTPRequest $request
85
     */
86
    public static function endshow($val, $showHeader = true, HTTPRequest $request = null)
87
    {
88
        // Don't show on live
89
        if (Director::isLive()) {
90
            return;
91
        }
92
93
        echo static::create_debug_view($request)
94
            ->debugVariable($val, static::caller(), $showHeader);
95
96
        die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
97
    }
98
99
    /**
100
     * Quick dump of a variable.
101
     * Note: This method will output in live!
102
     *
103
     * @param mixed $val
104
     * @param HTTPRequest $request Current request to influence output format
105
     */
106
    public static function dump($val, HTTPRequest $request = null)
107
    {
108
        echo self::create_debug_view($request)
109
            ->renderVariable($val, self::caller());
110
    }
111
112
    /**
113
     * Get debug text for this object
114
     *
115
     * @param mixed $val
116
     * @param HTTPRequest $request
117
     * @return string
118
     */
119
    public static function text($val, HTTPRequest $request = null)
120
    {
121
        return static::create_debug_view($request)
122
            ->debugVariableText($val);
123
    }
124
125
    /**
126
     * Show a debugging message.
127
     * Does not work on live mode
128
     *
129
     * @param string $message
130
     * @param bool $showHeader
131
     * @param HTTPRequest|null $request
132
     */
133
    public static function message($message, $showHeader = true, HTTPRequest $request = null)
134
    {
135
        // Don't show on live
136
        if (Director::isLive()) {
137
            return;
138
        }
139
140
        echo static::create_debug_view($request)
141
            ->renderMessage($message, static::caller(), $showHeader);
142
    }
143
144
    /**
145
     * Create an instance of an appropriate DebugView object.
146
     *
147
     * @param HTTPRequest $request Optional request to target this view for
148
     * @return DebugView
149
     */
150
    public static function create_debug_view(HTTPRequest $request = null)
151
    {
152
        $service = static::supportsHTML($request)
153
            ? DebugView::class
154
            : CliDebugView::class;
155
        return Injector::inst()->get($service);
156
    }
157
158
    /**
159
     * Determine if the given request supports html output
160
     *
161
     * @param HTTPRequest $request
162
     * @return bool
163
     */
164
    protected static function supportsHTML(HTTPRequest $request = null)
165
    {
166
        // No HTML output in CLI
167
        if (Director::is_cli()) {
168
            return false;
169
        }
170
171
        // Get current request if registered
172
        if (!$request && Injector::inst()->has(HTTPRequest::class)) {
173
            $request = Injector::inst()->get(HTTPRequest::class);
174
        }
175
        if (!$request) {
176
            return false;
177
        }
178
        // Request must include text/html
179
        $accepted = $request->getAcceptMimetypes(false);
180
181
        // Explicit opt in
182
        if (in_array('text/html', $accepted)) {
183
            return true;
184
        };
185
186
        // Implicit opt-out
187
        if (in_array('application/json', $accepted)) {
188
            return false;
189
        }
190
191
        // Fallback to wildcard comparison
192
        if (in_array('*/*', $accepted)) {
193
            return true;
194
        }
195
        return false;
196
    }
197
198
    /**
199
     * Check if the user has permissions to run URL debug tools,
200
     * else redirect them to log in.
201
     */
202
    public static function require_developer_login()
203
    {
204
        // Don't require login for dev mode
205
        if (Director::isDev()) {
206
            return;
207
        }
208
209
        if (isset($_SESSION['loggedInAs'])) {
210
            // We have to do some raw SQL here, because this method is called in Object::defineMethods().
211
            // This means we have to be careful about what objects we create, as we don't want Object::defineMethods()
212
            // being called again.
213
            // This basically calls Permission::checkMember($_SESSION['loggedInAs'], 'ADMIN');
214
215
            // @TODO - Rewrite safely using DataList::filter
216
            $memberID = $_SESSION['loggedInAs'];
217
            $permission = DB::prepared_query(
218
                '
219
				SELECT "ID" FROM "Permission"
220
				INNER JOIN "Group_Members" ON "Permission"."GroupID" = "Group_Members"."GroupID"
221
				WHERE "Permission"."Code" = ?
222
				AND "Permission"."Type" = ?
223
				AND "Group_Members"."MemberID" = ?',
224
                array(
225
                    'ADMIN', // Code
226
                    Permission::GRANT_PERMISSION, // Type
227
                    $memberID // MemberID
228
                )
229
            )->value();
230
231
            if ($permission) {
232
                return;
233
            }
234
        }
235
236
        // This basically does the same as
237
        // Security::permissionFailure(null, "You need to login with developer access to make use of debugging tools.")
238
        // We have to do this because of how early this method is called in execution.
239
        $_SESSION['SilverStripe\\Security\\Security']['Message']['message']
240
            = "You need to login with developer access to make use of debugging tools.";
241
        $_SESSION['SilverStripe\\Security\\Security']['Message']['type'] =  'warning';
242
        $_SESSION['BackURL'] = $_SERVER['REQUEST_URI'];
243
        header($_SERVER['SERVER_PROTOCOL'] . " 302 Found");
244
        header("Location: " . Director::baseURL() . Security::login_url());
245
        die();
246
    }
247
}
248