GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — integration ( 0212ae...79ce02 )
by Nicolas
04:20
created

GenericExceptionHandler::handler()   D

Complexity

Conditions 13
Paths 348

Size

Total Lines 70
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 70
rs 4.1971
cc 13
eloc 38
nc 348
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @package core
4
 */
5
6
/**
7
 * GenericExceptionHandler will handle any uncaught exceptions thrown in
8
 * Symphony. Additionally, all errors in Symphony that are raised to Exceptions
9
 * will be handled by this class.
10
 * It is possible for Exceptions to be caught by their own `ExceptionHandler` which can
11
 * override the `render` function so that it can be displayed to the user appropriately.
12
 */
13
class GenericExceptionHandler
14
{
15
    /**
16
     * Whether the `GenericExceptionHandler` should handle exceptions. Defaults to true
17
     * @var boolean
18
     */
19
    public static $enabled = true;
20
21
    /**
22
     * An instance of the Symphony Log class, used to write errors to the log
23
     * @var Log
24
     */
25
    private static $_Log = null;
26
27
    /**
28
     * Initialise will set the error handler to be the `__CLASS__::handler` function.
29
     *
30
     * @param Log $Log
31
     *  An instance of a Symphony Log object to write errors to
32
     */
33
    public static function initialise(Log $Log = null)
34
    {
35
        if (!is_null($Log)) {
36
            self::$_Log = $Log;
37
        }
38
39
        set_exception_handler(array(__CLASS__, 'handler'));
40
        register_shutdown_function(array(__CLASS__, 'shutdown'));
41
    }
42
43
    /**
44
     * Retrieves a window of lines before and after the line where the error
45
     * occurred so that a developer can help debug the exception
46
     *
47
     * @param integer $line
48
     *  The line where the error occurred.
49
     * @param string $file
50
     *  The file that holds the logic that caused the error.
51
     * @param integer $window
52
     *  The number of lines either side of the line where the error occurred
53
     *  to show
54
     * @return array
55
     */
56
    protected static function __nearbyLines($line, $file, $window = 5)
57
    {
58
        if (!file_exists($file)) {
59
            return array();
60
        }
61
62
        return array_slice(file($file), ($line - 1) - $window, $window * 2, true);
63
    }
64
65
    /**
66
     * The handler function is given an Exception and will call it's render
67
     * function to display the Exception to a user. After calling the render
68
     * function, the output is displayed and then exited to prevent any further
69
     * logic from occurring.
70
     *
71
     * @param Exception $e
72
     *  The Exception object
73
     * @return string
74
     *  The result of the Exception's render function
75
     */
76
    public static function handler(Exception $e)
0 ignored issues
show
Unused Code introduced by
The parameter $e is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
77
    {
78
        $output = '';
79
80
        try {
81
            // Instead of just throwing an empty page, return a 404 page.
82
            if (self::$enabled !== true) {
83
                $e = new FrontendPageNotFoundException();
84
            };
85
86
            $exception_type = get_class($e);
87
88
            if (class_exists("{$exception_type}Handler") && method_exists("{$exception_type}Handler", 'render')) {
89
                $class = "{$exception_type}Handler";
90
            } else {
91
                $class = __CLASS__;
92
            }
93
94
            // Exceptions should be logged if they are not caught.
95
            if (self::$_Log instanceof Log) {
96
                if (method_exists($e, 'getAdditional')) {
97
                    $exception = $e->getAdditional()->error;
98
                } else {
99
                    $exception = $e;
100
                }
101
102
                self::$_Log->pushExceptionToLog($exception, true);
0 ignored issues
show
Unused Code introduced by
The call to Log::pushExceptionToLog() has too many arguments starting with true.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
103
            }
104
105
            $output = call_user_func(array($class, 'render'), $e);
106
107
        // If an exception was raised trying to render the exception, fall back
108
        // to the generic exception handler
109
        } catch (Exception $e) {
110
            try {
111
                $output = call_user_func(array('GenericExceptionHandler', 'render'), $e);
112
113
            // If the generic exception handler couldn't do it, well we're in bad
114
            // shape, just output a plaintext response!
115
            } catch (Exception $e) {
116
                echo "<pre>";
117
                echo 'A severe error occurred whilst trying to handle an exception, check the Symphony log for more details' . PHP_EOL;
118
                echo $e->getMessage() . ' on ' . $e->getLine() . ' of file ' . $e->getFile() . PHP_EOL;
119
                exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method handler() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
120
            }
121
        }
122
123
        // Pending nothing disasterous, we should have `$e` and `$output` values here.
124
        if (!headers_sent()) {
125
            cleanup_session_cookies(APP_MODE);
126
127
            // Inspect the exception to determine the best status code
128
            $httpStatus = null;
129
            if ($e instanceof SymphonyErrorPage) {
130
                $httpStatus = $e->getHttpStatusCode();
131
            } elseif ($e instanceof FrontendPageNotFoundException) {
132
                $httpStatus = Page::HTTP_STATUS_NOT_FOUND;
133
            }
134
135
            if (!$httpStatus || $httpStatus == Page::HTTP_STATUS_OK) {
136
                $httpStatus = Page::HTTP_STATUS_ERROR;
137
            }
138
139
            Page::renderStatusCode($httpStatus);
140
            header('Content-Type: text/html; charset=utf-8');
141
        }
142
143
        echo $output;
144
        exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method handler() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
145
    }
146
147
    /**
148
     * Returns the path to the error-template by looking at the `WORKSPACE/template/`
149
     * directory, then at the `TEMPLATES`  directory for the convention `*.tpl`. If
150
     * the template is not found, `false` is returned
151
     *
152
     * @since Symphony 2.3
153
     * @param string $name
154
     *  Name of the template
155
     * @return mixed
156
     *  String, which is the path to the template if the template is found,
157
     *  false otherwise
158
     */
159 View Code Duplication
    public static function getTemplate($name)
160
    {
161
        $format = '%s/%s.tpl';
162
163
        if (file_exists($template = sprintf($format, WORKSPACE . '/template', $name))) {
164
            return $template;
165
        } elseif (file_exists($template = sprintf($format, TEMPLATE, $name))) {
166
            return $template;
167
        } else {
168
            return false;
169
        }
170
    }
171
172
    /**
173
     * The render function will take an Exception and output a HTML page
174
     *
175
     * @param Exception $e
176
     *  The Exception object
177
     * @return string
178
     *  An HTML string
179
     */
180
    public static function render(Exception $e)
181
    {
182
        $lines = null;
183
184
        foreach (self::__nearByLines($e->getLine(), $e->getFile()) as $line => $string) {
185
            $lines .= sprintf(
186
                '<li%s><strong>%d</strong> <code>%s</code></li>',
187
                (($line+1) == $e->getLine() ? ' class="error"' : null),
188
                ++$line,
189
                str_replace("\t", '&nbsp;&nbsp;&nbsp;&nbsp;', htmlspecialchars($string))
190
            );
191
        }
192
193
        $trace = null;
194
195
        foreach ($e->getTrace() as $t) {
196
            $trace .= sprintf(
197
                '<li><code><em>[%s:%d]</em></code></li><li><code>&#160;&#160;&#160;&#160;%s%s%s();</code></li>',
198
                (isset($t['file']) ? $t['file'] : null),
199
                (isset($t['line']) ? $t['line'] : null),
200
                (isset($t['class']) ? $t['class'] : null),
201
                (isset($t['type']) ? $t['type'] : null),
202
                $t['function']
203
            );
204
        }
205
206
        $queries = null;
207
208 View Code Duplication
        if (is_object(Symphony::Database())) {
209
            $debug = Symphony::Database()->debug();
210
211
            if (!empty($debug)) {
212
                foreach ($debug as $query) {
213
                    $queries .= sprintf(
214
                        '<li><em>[%01.4f]</em><code> %s;</code> </li>',
215
                        (isset($query['execution_time']) ? $query['execution_time'] : null),
216
                        htmlspecialchars($query['query'])
217
                    );
218
                }
219
            }
220
        }
221
222
        return self::renderHtml(
223
            'fatalerror.generic',
224
            ($e instanceof ErrorException ? GenericErrorHandler::$errorTypeStrings[$e->getSeverity()] : 'Fatal Error'),
225
            $e->getMessage(),
226
            $e->getFile(),
227
            $e->getLine(),
228
            $lines,
229
            $trace,
230
            $queries
231
        );
232
    }
233
234
    /**
235
     * The shutdown function will capture any fatal errors and format them as a
236
     * usual Symphony page.
237
     *
238
     * @since Symphony 2.4
239
     */
240
    public static function shutdown()
241
    {
242
        $last_error = error_get_last();
243
244
        if (!is_null($last_error) && $last_error['type'] === E_ERROR) {
245
            $code = $last_error['type'];
246
            $message = $last_error['message'];
247
            $file = $last_error['file'];
248
            $line = $last_error['line'];
249
250
            try {
251
                // Log the error message
252
                if (self::$_Log instanceof Log) {
253
                    self::$_Log->pushToLog(sprintf(
254
                        '%s %s: %s%s%s',
255
                        __CLASS__,
256
                        $code,
257
                        $message,
258
                        ($line ? " on line $line" : null),
259
                        ($file ? " of file $file" : null)
260
                    ), $code);
261
                }
262
263
                ob_clean();
264
265
                // Display the error message
266
                echo self::renderHtml(
267
                    'fatalerror.fatal',
268
                    'Fatal Error',
269
                    $message,
270
                    $file,
271
                    $line
272
                );
273
            } catch (Exception $e) {
274
                echo "<pre>";
275
                echo 'A severe error occurred whilst trying to handle an exception, check the Symphony log for more details' . PHP_EOL;
276
                echo $e->getMessage() . ' on ' . $e->getLine() . ' of file ' . $e->getFile() . PHP_EOL;
277
            }
278
        }
279
    }
280
281
    /**
282
     * This function will fetch the desired `$template`, and output the
283
     * Exception in a user friendly way.
284
     *
285
     * @since Symphony 2.4
286
     * @param string $template
287
     *  The template name, which should correspond to something in the TEMPLATE
288
     *  directory, eg `fatalerror.fatal`.
289
     * @param string $heading
290
     * @param string $message
291
     * @param string $file
292
     * @param string $line
293
     * @param string $lines
294
     * @param string $trace
295
     * @param string $queries
296
     * @return string
297
     *  The HTML of the formatted error message.
298
     */
299
    public static function renderHtml($template, $heading, $message, $file = null, $line = null, $lines = null, $trace = null, $queries = null)
300
    {
301
        $html = sprintf(
302
            file_get_contents(self::getTemplate($template)),
303
            $heading,
304
            General::unwrapCDATA($message),
305
            $file,
306
            $line,
307
            $lines,
308
            $trace,
309
            $queries
310
        );
311
312
        $html = str_replace('{ASSETS_URL}', ASSETS_URL, $html);
313
        $html = str_replace('{SYMPHONY_URL}', SYMPHONY_URL, $html);
314
        $html = str_replace('{URL}', URL, $html);
315
316
        return $html;
317
    }
318
}
319
320
/**
321
 * `GenericErrorHandler` will catch any warnings or notices thrown by PHP and
322
 * raise the errors to Exceptions so they can be dealt with by the
323
 * `GenericExceptionHandler`. The type of errors that are raised to Exceptions
324
 * depends on the `error_reporting` level. All errors raised, except
325
 * `E_NOTICE` and `E_STRICT` are written to the Symphony log.
326
 */
327
class GenericErrorHandler
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
328
{
329
    /**
330
     * Whether the error handler is enabled or not, defaults to true.
331
     * Setting to false will prevent any Symphony error handling from occurring
332
     * @var boolean
333
     */
334
    public static $enabled = true;
335
336
    /**
337
     * An instance of the Log class, used to write errors to the log
338
     * @var Log
339
     */
340
    private static $_Log = null;
341
342
    /**
343
     * Whether to log errors or not.
344
     * This one is to be used temporarily, e.g., when PHP function is
345
     * supposed to error out and throw warning and log should be kept clean.
346
     *
347
     * @since Symphony 2.2.2
348
     * @var boolean
349
     * @example
350
     *  GenericErrorHandler::$logDisabled = true;
351
     *  DoSomethingThatEndsWithWarningsYouDoNotWantInLogs();
352
     *  GenericErrorHandler::$logDisabled = false;
353
     */
354
    public static $logDisabled = false;
355
356
    /**
357
     * An associative array with the PHP error constant as a key, and
358
     * a string describing that constant as the value
359
     * @var array
360
     */
361
    public static $errorTypeStrings = array(
362
        E_ERROR                 => 'Fatal Error',
363
        E_WARNING               => 'Warning',
364
        E_PARSE                 => 'Parsing Error',
365
        E_NOTICE                => 'Notice',
366
367
        E_CORE_ERROR            => 'Core Error',
368
        E_CORE_WARNING          => 'Core Warning',
369
        E_COMPILE_ERROR         => 'Compile Error',
370
        E_COMPILE_WARNING       => 'Compile Warning',
371
372
        E_USER_NOTICE           => 'User Notice',
373
        E_USER_WARNING          => 'User Warning',
374
        E_USER_ERROR            => 'User Error',
375
376
        E_STRICT                => 'Strict Notice',
377
        E_RECOVERABLE_ERROR     => 'Recoverable Error',
378
        E_DEPRECATED            => 'Deprecated Warning'
379
    );
380
381
    /**
382
     * Initialise will set the error handler to be the `__CLASS__::handler`
383
     * function.
384
     *
385
     * @param Log|null $Log (optional)
386
     *  An instance of a Symphony Log object to write errors to
387
     */
388
    public static function initialise(Log $Log = null)
389
    {
390
        if (!is_null($Log)) {
391
            self::$_Log = $Log;
392
        }
393
394
        set_error_handler(array(__CLASS__, 'handler'), error_reporting());
395
    }
396
397
    /**
398
     * Determines if the error handler is enabled by checking that error_reporting
399
     * is set in the php config and that $enabled is true
400
     *
401
     * @return boolean
402
     */
403
    public static function isEnabled()
404
    {
405
        return (bool)error_reporting() && self::$enabled;
406
    }
407
408
    /**
409
     * The handler function will write the error to the `$Log` if it is not `E_NOTICE`
410
     * or `E_STRICT` before raising the error as an Exception. This allows all `E_WARNING`
411
     * to actually be captured by an Exception handler.
412
     *
413
     * @param integer $code
414
     *  The error code, one of the PHP error constants
415
     * @param string $message
416
     *  The message of the error, this will be written to the log and
417
     *  displayed as the exception message
418
     * @param string $file
419
     *  The file that holds the logic that caused the error. Defaults to null
420
     * @param integer $line
421
     *  The line where the error occurred.
422
     * @throws ErrorException
423
     * @return string
424
     *  Usually a string of HTML that will displayed to a user
425
     */
426
    public static function handler($code, $message, $file = null, $line = null)
427
    {
428
        // Only log if the error won't be raised to an exception and the error is not `E_NOTICE` or `E_STRICT`
429
        if (!self::$logDisabled && !in_array($code, array(E_NOTICE, E_STRICT)) && self::$_Log instanceof Log) {
430
            self::$_Log->pushToLog(sprintf(
431
                '%s %s: %s%s%s',
432
                __CLASS__,
433
                $code,
434
                $message,
435
                ($line ? " on line $line" : null),
436
                ($file ? " of file $file" : null)
437
            ), $code);
438
        }
439
440
        if (self::isEnabled()) {
441
            throw new ErrorException($message, 0, $code, $file, $line);
442
        }
443
    }
444
}
445