This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace nyx\diagnostics\debug\handlers; |
|||||||||||
2 | ||||||||||||
3 | // Internal dependencies |
|||||||||||
4 | use nyx\diagnostics\debug\exceptions; |
|||||||||||
5 | use nyx\diagnostics\debug\interfaces; |
|||||||||||
6 | use nyx\diagnostics\debug; |
|||||||||||
7 | use nyx\diagnostics\definitions; |
|||||||||||
8 | ||||||||||||
9 | /** |
|||||||||||
10 | * Error Handler |
|||||||||||
11 | * |
|||||||||||
12 | * Converts errors of a severity equal to or above the given threshold into Exceptions for easier inspections |
|||||||||||
13 | * and more robust and cohesive handling. Does not modify any of the input data it gets (for instance, error |
|||||||||||
14 | * messages are left as is, so the Exception Handler can decide how to present them). |
|||||||||||
15 | * |
|||||||||||
16 | * Note: The internal error threshold {@see self::setThreshold()} can work decoupled from PHP's error_reporting() |
|||||||||||
17 | * level. For instance, if PHP is set to report all errors but this handler's threshold is set to warnings, |
|||||||||||
18 | * only warnings and higher levels of errors will get converted to exceptions. This handler *does not* |
|||||||||||
19 | * automatically turn off PHP's display_errors ini directive, meaning that under the above circumstances |
|||||||||||
20 | * all errors below warnings might get displayed by PHP's internal error handler unless you set the |
|||||||||||
21 | * directive to 0 yourself. |
|||||||||||
22 | * |
|||||||||||
23 | * @package Nyx\Diagnostics\Debug |
|||||||||||
24 | * @version 0.0.5 |
|||||||||||
25 | * @author Michal Chojnacki <[email protected]> |
|||||||||||
26 | * @copyright 2012-2016 Nyx Dev Team |
|||||||||||
27 | * @link http://docs.muyo.io/nyx/diagnostics/debug.html |
|||||||||||
28 | */ |
|||||||||||
29 | class Error extends debug\Handler implements interfaces\handlers\Error, interfaces\handlers\FatalError |
|||||||||||
30 | { |
|||||||||||
31 | /** |
|||||||||||
32 | * Used by various components (mostly logging facilities) to denote a userland deprecation notice without |
|||||||||||
33 | * actually throwing errors/exceptions (in a logging context etc.). |
|||||||||||
34 | */ |
|||||||||||
35 | const DEPRECATION = -100; |
|||||||||||
36 | ||||||||||||
37 | /** |
|||||||||||
38 | * @var int The error severity required to convert an error into an Exception. |
|||||||||||
39 | */ |
|||||||||||
40 | private $threshold; |
|||||||||||
41 | ||||||||||||
42 | /** |
|||||||||||
43 | * @var int The error severity this Handler has been initialized with. |
|||||||||||
44 | */ |
|||||||||||
45 | private $initialThreshold; |
|||||||||||
46 | ||||||||||||
47 | /** |
|||||||||||
48 | * Registers the given or a new Error Handler with PHP. |
|||||||||||
49 | * |
|||||||||||
50 | * @param interfaces\handlers\Error $handler An optional, already instantiated Error handler instance. |
|||||||||||
51 | * If none is given, a new one will be instantiated. |
|||||||||||
52 | * @param int $threshold {@see self::setThreshold()} Will be ignored if you provide |
|||||||||||
53 | * your own Error Handler instance. |
|||||||||||
54 | * @return Error An instance of the error handler which got registered. |
|||||||||||
55 | * Either the same as the given one or if none was given, |
|||||||||||
56 | * a new instance. |
|||||||||||
57 | */ |
|||||||||||
58 | public static function register(interfaces\handlers\Error $handler = null, $threshold = null) |
|||||||||||
59 | { |
|||||||||||
60 | // Use the given handler or instantiate a new one? |
|||||||||||
61 | $handler = $handler ?: new static($threshold); |
|||||||||||
62 | ||||||||||||
63 | // Note: Utilizing the error_types parameter of set_error_handler would probably simplify this handler |
|||||||||||
64 | // a little bit (and make it perform better due to a cutdown on error_reporting() calls in cases with |
|||||||||||
65 | // lots of errors reported but ignored here due to being below threshold) but setting the threshold |
|||||||||||
66 | // on the fly would become unusable/less robust. |
|||||||||||
67 | set_error_handler([$handler, 'handle']); |
|||||||||||
68 | ||||||||||||
69 | if ($handler instanceof interfaces\handlers\FatalError) { |
|||||||||||
70 | register_shutdown_function([$handler, 'onShutdown']); |
|||||||||||
71 | } |
|||||||||||
72 | ||||||||||||
73 | return $handler; |
|||||||||||
74 | } |
|||||||||||
75 | ||||||||||||
76 | /** |
|||||||||||
77 | * Constructs a new Error Handler instance. |
|||||||||||
78 | * |
|||||||||||
79 | * @param int $threshold {@see self::setThreshold()}. |
|||||||||||
80 | */ |
|||||||||||
81 | public function __construct($threshold = null) |
|||||||||||
82 | { |
|||||||||||
83 | $this->setThreshold($threshold); |
|||||||||||
84 | ||||||||||||
85 | // Keep track of the initial threshold so we can easily restore it later. |
|||||||||||
86 | $this->initialThreshold = $this->threshold; |
|||||||||||
87 | } |
|||||||||||
88 | ||||||||||||
89 | /** |
|||||||||||
90 | * Returns the error severity required to convert an error into an Exception. |
|||||||||||
91 | * |
|||||||||||
92 | * @return int |
|||||||||||
93 | */ |
|||||||||||
94 | public function getThreshold() |
|||||||||||
95 | { |
|||||||||||
96 | return $this->threshold; |
|||||||||||
97 | } |
|||||||||||
98 | ||||||||||||
99 | /** |
|||||||||||
100 | * Sets the error severity required to convert an error into an Exception. |
|||||||||||
101 | * |
|||||||||||
102 | * @param int $threshold The threshold. Passing null will make the handler use the current |
|||||||||||
103 | * error_reporting() level as reported by PHP. All non-null values will be |
|||||||||||
104 | * converted to integers. |
|||||||||||
105 | * @return $this |
|||||||||||
106 | */ |
|||||||||||
107 | public function setThreshold($threshold = null) |
|||||||||||
108 | { |
|||||||||||
109 | $this->threshold = null === $threshold ? error_reporting() : (int) $threshold; |
|||||||||||
110 | ||||||||||||
111 | return $this; |
|||||||||||
112 | } |
|||||||||||
113 | ||||||||||||
114 | /** |
|||||||||||
115 | * Sets the current threshold to the level this Handler has been initialized with. |
|||||||||||
116 | * |
|||||||||||
117 | * @return $this |
|||||||||||
118 | */ |
|||||||||||
119 | public function restoreThreshold() |
|||||||||||
120 | { |
|||||||||||
121 | return $this->setThreshold($this->initialThreshold); |
|||||||||||
122 | } |
|||||||||||
123 | ||||||||||||
124 | /** |
|||||||||||
125 | * {@inheritDoc} |
|||||||||||
126 | * |
|||||||||||
127 | * Converts errors of a severity equal to or above the given threshold into Exceptions for easier inspections |
|||||||||||
128 | * and more robust and cohesive handling. Ignores errors which do not meed the thresholds and returns false |
|||||||||||
129 | * for those instead, letting PHP's internal error handling handle such a case. |
|||||||||||
130 | * |
|||||||||||
131 | * @throws exceptions\Error When the given error severity meets both the error_reporting() and internal |
|||||||||||
132 | * thresholds. |
|||||||||||
133 | */ |
|||||||||||
134 | public function handle(int $type, string $message, string $file = null, int $line = null, array $context = []) : bool |
|||||||||||
135 | { |
|||||||||||
136 | // A threshold of 0 means the handler should ignore all errors. |
|||||||||||
137 | if (0 === $this->threshold) { |
|||||||||||
138 | return false; |
|||||||||||
139 | } |
|||||||||||
140 | ||||||||||||
141 | // Make sure that the severity is included in the error_reporting level (the handler will get called for |
|||||||||||
142 | // nearly every error regardless of the error_reporting setting) and that it fits our threshold as well. |
|||||||||||
143 | if (error_reporting() & $type and $this->threshold & $type) { |
|||||||||||
0 ignored issues
–
show
|
||||||||||||
144 | ||||||||||||
145 | // We will construct an Exception but won't throw it yet. Conditions might prevent us from doing it. |
|||||||||||
146 | $exception = new exceptions\Error($message, 0, $type, $file, $line, $context); |
|||||||||||
147 | ||||||||||||
148 | // Being Emitter Aware we are bound to comply to the Events Definition. |
|||||||||||
149 | // self::emitDebugEvent() will return false when no Emitter is present. Otherwise we'll get the |
|||||||||||
150 | // Exception after it's been processed by Event Listeners so we need to overwrite it here. |
|||||||||||
151 | if (null !== $response = $this->emitDebugEvent(definitions\Events::DEBUG_ERROR_BEFORE, $exception)) { |
|||||||||||
152 | $exception = $response; |
|||||||||||
153 | } |
|||||||||||
154 | ||||||||||||
155 | // First of all run all Conditions. The method will return true if we are to prevent throwing |
|||||||||||
156 | // the Exception and since technically this Handler *somehow* handled the situation, we will return |
|||||||||||
157 | // true so PHP knows about it. |
|||||||||||
158 | if ($this->runConditions($exception)) { |
|||||||||||
159 | return true; |
|||||||||||
160 | } |
|||||||||||
161 | ||||||||||||
162 | // Seems we weren't prevented, so let's do eet. |
|||||||||||
163 | throw $exception; |
|||||||||||
164 | } |
|||||||||||
165 | ||||||||||||
166 | return false; |
|||||||||||
167 | } |
|||||||||||
168 | ||||||||||||
169 | /** |
|||||||||||
170 | * {@inheritDoc} |
|||||||||||
171 | * |
|||||||||||
172 | * Attempts to catch the last error which occurred during script execution, convert it to an exception and |
|||||||||||
173 | * pass it to an Exception Handler that is known and usable by this class. |
|||||||||||
174 | * |
|||||||||||
175 | * @throws exceptions\FatalError When a fatal error meeting the threshold conditions has occurred. |
|||||||||||
176 | */ |
|||||||||||
177 | public function onShutdown() |
|||||||||||
178 | { |
|||||||||||
179 | // Since this gets registered as a shutdown function, upon shutdown we need to check whether an error |
|||||||||||
180 | // actually occurred. |
|||||||||||
181 | if (null === $error = error_get_last()) { |
|||||||||||
182 | return; |
|||||||||||
183 | } |
|||||||||||
184 | ||||||||||||
185 | // Even if the handler is set to ignore all errors, we are still going to kick in for the most fundamental |
|||||||||||
186 | // errors reported by PHP. |
|||||||||||
187 | if (0 === $this->threshold and !$this->isFatal($error['type'])) { |
|||||||||||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Using logical operators such as
and instead of && is generally not recommended.
PHP has two types of connecting operators (logical operators, and boolean operators):
The difference between these is the order in which they are executed. In most cases,
you would want to use a boolean operator like Let’s take a look at a few examples: // Logical operators have lower precedence:
$f = false or true;
// is executed like this:
($f = false) or true;
// Boolean operators have higher precedence:
$f = false || true;
// is executed like this:
$f = (false || true);
Logical Operators are used for Control-FlowOne case where you explicitly want to use logical operators is for control-flow such as this: $x === 5
or die('$x must be 5.');
// Instead of
if ($x !== 5) {
die('$x must be 5.');
}
Since // The following is currently a parse error.
$x === 5
or throw new RuntimeException('$x must be 5.');
These limitations lead to logical operators rarely being of use in current PHP code. ![]() |
||||||||||||
188 | return; |
|||||||||||
189 | } |
|||||||||||
190 | ||||||||||||
191 | // Instead of directly coupling this with our own exception handler, we'll try to see if an exception handler |
|||||||||||
192 | // is already registered... |
|||||||||||
193 | $handler = set_exception_handler(null); |
|||||||||||
194 | ||||||||||||
195 | // ... and then check if it's an instance of our own exception handler so that we can make use of it. |
|||||||||||
196 | // BTW Why isn't such a basic Exception Handler Interface a PSR yet? |
|||||||||||
197 | if (is_array($handler) && $handler[0] instanceof interfaces\handlers\Exception) { |
|||||||||||
198 | ||||||||||||
199 | // We will construct an Exception as we need to pass it to our Conditions. |
|||||||||||
200 | $exception = new exceptions\FatalError($error['message'], 0, $error['type'], $error['file'], $error['line']); |
|||||||||||
201 | ||||||||||||
202 | // Being Emitter Aware we are bound to comply to the Events Definition. |
|||||||||||
203 | // self::emitDebugEvent() will return false when no Emitter is present. Otherwise we'll get the |
|||||||||||
204 | // Exception after it's been processed by Event Listeners so we need to overwrite it here. |
|||||||||||
205 | if (false !== $response = $this->emitDebugEvent(definitions\Events::DEBUG_FATAL_ERROR_BEFORE, $exception)) { |
|||||||||||
206 | // Now, as per Events Definition, also emit a casual DEBUG_ERROR_BEFORE event. No need to check |
|||||||||||
207 | // for an Emitter now anymore, obviously. |
|||||||||||
208 | $exception = $this->emitDebugEvent(definitions\Events::DEBUG_ERROR_BEFORE, $response); |
|||||||||||
209 | } |
|||||||||||
210 | ||||||||||||
211 | // Run the Conditions but ignore the PREVENT signal. |
|||||||||||
212 | $this->runConditions($exception); |
|||||||||||
213 | ||||||||||||
214 | // Pass the Exception to the Exception Handler. |
|||||||||||
215 | /** @var interfaces\handlers\Exception[] $handler */ |
|||||||||||
216 | $handler[0]->handle($exception); |
|||||||||||
0 ignored issues
–
show
It seems like
$exception defined by $this->emitDebugEvent(\n...RROR_BEFORE, $response) on line 208 can be null ; however, nyx\diagnostics\debug\in...ers\Exception::handle() does not accept null , maybe add an additional type check?
Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code: /** @return stdClass|null */
function mayReturnNull() { }
function doesNotAcceptNull(stdClass $x) { }
// With potential error.
function withoutCheck() {
$x = mayReturnNull();
doesNotAcceptNull($x); // Potential error here.
}
// Safe - Alternative 1
function withCheck1() {
$x = mayReturnNull();
if ( ! $x instanceof stdClass) {
throw new \LogicException('$x must be defined.');
}
doesNotAcceptNull($x);
}
// Safe - Alternative 2
function withCheck2() {
$x = mayReturnNull();
if ($x instanceof stdClass) {
doesNotAcceptNull($x);
}
}
![]() |
||||||||||||
217 | } |
|||||||||||
218 | ||||||||||||
219 | exit; |
|||||||||||
220 | } |
|||||||||||
221 | ||||||||||||
222 | /** |
|||||||||||
223 | * Determines if given error type is considered a fatal error. |
|||||||||||
224 | * |
|||||||||||
225 | * Note: E_RECOVERABLE_ERROR and E_PARSE should as of PHP7 be entirely converted to Throwables so they |
|||||||||||
226 | * should be caught by an Exception Handler directly instead of first going through an Error Handler |
|||||||||||
227 | * and being converted to an Error Exception, let alone a FatalError Exception. We still keep them here |
|||||||||||
228 | * for edge cases, however. |
|||||||||||
229 | * |
|||||||||||
230 | * @param int $type The error type to check. |
|||||||||||
231 | * @return bool |
|||||||||||
232 | */ |
|||||||||||
233 | protected function isFatal($type) |
|||||||||||
234 | { |
|||||||||||
235 | return in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR, E_PARSE]); |
|||||||||||
236 | } |
|||||||||||
237 | } |
|||||||||||
238 |
PHP has two types of connecting operators (logical operators, and boolean operators):
and
&&
or
||
The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like
&&
, or||
.Let’s take a look at a few examples:
Logical Operators are used for Control-Flow
One case where you explicitly want to use logical operators is for control-flow such as this:
Since
die
introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined withthrow
at this point:These limitations lead to logical operators rarely being of use in current PHP code.