Error::handleException()   B
last analyzed

Complexity

Conditions 10
Paths 18

Size

Total Lines 47
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 32
c 1
b 0
f 0
nc 18
nop 2
dl 0
loc 47
ccs 0
cts 31
cp 0
crap 110
rs 7.6666

How to fix   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
declare(strict_types=1);
4
5
namespace Suricate;
6
7
use ErrorException;
8
9
/**
10
 * @property bool $report
11
 * @property bool $dumpContext
12
 * @property mixed $httpHandler Handler (object/closure/string) in charge of the error
13
 */
14
class Error extends Service
15
{
16
    protected $parametersList = ['report', 'dumpContext', 'httpHandler'];
17
    protected $errorHandlers = [];
18
19
    public static function handleException($e, $context = null)
20
    {
21
        foreach (Suricate::Error()->getErrorHandlers() as $customHandler) {
22
            $customHandler($e);
23
        }
24
25
        if ($e instanceof Exception\HttpException) {
26
            $httpHandler = Suricate::Error()->httpHandler;
27
            if (is_object($httpHandler) && $httpHandler instanceof \Closure) {
28
                $httpHandler($e);
29
                return;
30
            } elseif ($httpHandler != '') {
31
                $httpHandler = explode('::', $httpHandler);
32
33
                if (count($httpHandler) > 1) {
34
                    $userFunc = $httpHandler;
35
                } else {
36
                    $userFunc = head($httpHandler);
37
                }
38
                if (is_callable($userFunc)) {
39
                    call_user_func($userFunc, $e);
40
                }
41
                return;
42
            }
43
44
            Suricate::Error()->displayGenericHttpExceptionPage($e);
45
        }
46
47
        while (ob_get_level() > 1) {
48
            ob_end_clean();
49
        }
50
51
        $json = [];
52
        $error = $e;
53
        do {
54
            $json[] = [
55
                'type' => get_class($error),
56
                'code' => $error->getCode(),
57
                'message' => $error->getMessage(),
58
                'file' => $error->getFile(),
59
                'line' => $error->getLine(),
60
                'trace' => explode("\n", $error->getTraceAsString())
61
            ];
62
        } while (($error = $error->getPrevious()));
63
        Suricate::Logger()->error(json_encode($json));
64
65
        Suricate::Error()->displayExceptionPage($e, $context);
66
    }
67
68
    public static function handleError(
69
        $code,
70
        $message,
71
        $file,
72
        $line,
73
        $context = null
74
    ) {
75
        foreach (Suricate::Error()->getErrorHandlers() as $customHandler) {
76
            $customHandler(new ErrorException($message, $code, 0, $file, $line));
77
        }
78
        if (!(error_reporting() & $code)) {
79
            return false; // Silenced
80
        }
81
82
        static::handleException(
83
            new ErrorException($message, $code, 0, $file, $line),
84
            $context
85
        );
86
    }
87
88
    public static function handleShutdownError()
89
    {
90
        if (
91
            !is_null(($error = error_get_last())) &&
92
            static::isFatal($error['type'])
93
        ) {
94
            static::handleException(
95
                new ErrorException(
96
                    $error['message'],
97
                    $error['type'],
98
                    0,
99
                    $error['file'],
100
                    $error['line']
101
                )
102
            );
103
        }
104
    }
105
106
    private function displayExceptionPage($e, $context = null)
107
    {
108
        if ($this->report || $this->report === null) {
109
            echo '<html>' . "\n";
110
            echo '  <head>' . "\n";
111
            echo '      <title>Oops, Uncaught Exception</title>' . "\n";
112
            echo '      <style>' . "\n";
113
            echo '          body{font-family: "Open Sans",arial,sans-serif; background: #FFF; color:#333; margin:2em}' .
114
                "\n";
115
            echo '          code{background:#E0941B;border-radius:4px;padding:2px 6px}' .
116
                "\n";
117
            echo '      </style>' . "\n";
118
            echo '  </head>' . "\n";
119
            echo '  <body>' . "\n";
120
            echo '      <h1>Oops, uncaught exception !</h1>' . "\n";
121
            echo '      <h2>This is embarrassing, but server made a booboo</h2>' .
122
                "\n";
123
            echo '      <p><code>' . $e->getMessage() . '</code></p>' . "\n";
124
            echo '      <h3>From:</h3>' . "\n";
125
            echo '      <p><code>' .
126
                $e->getFile() .
127
                ' on line ' .
128
                $e->getLine() .
129
                '</code></p>' .
130
                "\n";
131
            echo '      <h3>Call stack</h3>' . "\n";
132
            echo '      <pre>' . $e->getTraceAsString() . '</pre>' . "\n";
133
            if ($this->dumpContext) {
134
                echo '<h3>Context:</h3>';
135
                _p($context);
136
            }
137
            echo '  </body>' . "\n";
138
            echo '</html>';
139
        } else {
140
            if ($e->getCode() <= 1) {
141
                $err = new Exception\HttpException(
142
                    '500',
143
                    'Internal server error'
144
                );
145
                $this->displayGenericHttpExceptionPage($err);
146
            }
147
        }
148
        exit(1);
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...
149
    }
150
151
    private function displayGenericHttpExceptionPage($e)
152
    {
153
        $response = Suricate::Request();
154
155
        if (
156
            is_readable(
157
                app_path() . '/views/Errors/' . $e->getStatusCode() . '.php'
158
            )
159
        ) {
160
            ob_start();
161
            include app_path() .
162
                '/views/Errors/' .
163
                $e->getStatusCode() .
164
                '.php';
165
            $body = ob_get_clean();
166
        } else {
167
            $innerHtml = '<h1>' . $e->getStatusCode() . '</h1>';
168
169
            $page = new Page();
170
            $body = $page->setTitle($e->getStatusCode())->render($innerHtml);
171
        }
172
173
        $response->setBody($body)->setHttpCode($e->getStatusCode());
174
        foreach ($e->getHeaders() as $header => $value) {
175
            $response->addHeader($header, $value);
176
        }
177
178
        $response->write();
179
        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...
180
    }
181
182
    public static function isFatal($errorType)
183
    {
184
        return in_array($errorType, [
185
            E_COMPILE_ERROR,
186
            E_CORE_ERROR,
187
            E_ERROR,
188
            E_PARSE
189
        ]);
190
    }
191
192
    public function getErrorHandlers(): array
193
    {
194
        return $this->errorHandlers;
195
    }
196
197
    public function addErrorHandler(callable $handler)
198
    {
199
        $this->errorHandlers[] = $handler;
200
    }
201
}
202