Passed
Pull Request — master (#24)
by Mathieu
13:01 queued 10:10
created

Error   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 9
Bugs 1 Features 0
Metric Value
eloc 107
c 9
b 1
f 0
dl 0
loc 167
ccs 0
cts 95
cp 0
rs 10
wmc 23

6 Methods

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