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; |
||
2 | |||
3 | // External dependencies |
||
4 | use nyx\core; |
||
5 | use nyx\utils; |
||
6 | |||
7 | /** |
||
8 | * Frame |
||
9 | * |
||
10 | * Represents a single frame from a diagnostic inspection, ie. from a stack trace. |
||
11 | * |
||
12 | * @package Nyx\Diagnostics\Debug |
||
13 | * @version 0.1.0 |
||
14 | * @author Michal Chojnacki <[email protected]> |
||
15 | * @copyright 2012-2016 Nyx Dev Team |
||
16 | * @link http://docs.muyo.io/nyx/diagnostics/debug.html |
||
17 | * @todo setData() validation. |
||
18 | */ |
||
19 | class Frame implements core\interfaces\Serializable |
||
20 | { |
||
21 | /** |
||
22 | * The traits of a Frame instance. |
||
23 | */ |
||
24 | use core\traits\Serializable; |
||
25 | use utils\traits\Jetget; |
||
26 | |||
27 | /** |
||
28 | * @var int The line in which the error occurred. |
||
29 | */ |
||
30 | private $line; |
||
31 | |||
32 | /** |
||
33 | * @var string The namespace the error occurred in, if any. |
||
34 | */ |
||
35 | private $namespace; |
||
36 | |||
37 | /** |
||
38 | * @var string The fully-qualified name (ie. with namespace) of the class the error occurred in, if any. |
||
39 | */ |
||
40 | private $class; |
||
41 | |||
42 | /** |
||
43 | * @var string The short name (ie. without namespace) of the class the error occurred in, if any. |
||
44 | */ |
||
45 | private $shortClass; |
||
46 | |||
47 | /** |
||
48 | * @var string The name of the function/method the error occurred in. |
||
49 | */ |
||
50 | private $function; |
||
51 | |||
52 | /** |
||
53 | * @var string The type of the error. |
||
54 | */ |
||
55 | private $type; |
||
56 | |||
57 | /** |
||
58 | * @var array The context the error occurred in. |
||
59 | */ |
||
60 | private $args; |
||
61 | |||
62 | /** |
||
63 | * @var string The path to the file the error occurred in. |
||
64 | */ |
||
65 | private $file; |
||
66 | |||
67 | /** |
||
68 | * @var int The nesting limit of flattened args. |
||
69 | */ |
||
70 | private $nestingLimit = 10; |
||
71 | |||
72 | /** |
||
73 | * @var array An array of cached file paths => file contents. Kept static to reduce IO overhead when |
||
74 | * multiple Frames are assigned to the same files. |
||
75 | */ |
||
76 | private static $files; |
||
77 | |||
78 | /** |
||
79 | * Constructs the Frame. |
||
80 | * |
||
81 | * @param array $data The frame's data, in the format returned by \Exception::getTrace(). |
||
82 | */ |
||
83 | public function __construct(array $data) |
||
84 | { |
||
85 | $this->setData($data); |
||
86 | } |
||
87 | |||
88 | /** |
||
89 | * Returns the Frame's data as an array. |
||
90 | * |
||
91 | * @return array $data The Frame's data, in the same format as returned by \Exception::getTrace(). |
||
92 | */ |
||
93 | public function getData() : array |
||
94 | { |
||
95 | return [ |
||
96 | 'file' => $this->file, |
||
97 | 'line' => $this->line, |
||
98 | 'function' => $this->function, |
||
99 | 'class' => $this->class, |
||
100 | 'type' => $this->type, |
||
101 | 'args' => $this->args |
||
102 | ]; |
||
103 | } |
||
104 | |||
105 | /** |
||
106 | * Sets the Frame's data. |
||
107 | * |
||
108 | * @param array $data The Frame's data, in the same format as returned by \Exception::getTrace(). |
||
109 | */ |
||
110 | public function setData(array $data) |
||
111 | { |
||
112 | $this->line = isset($data['line']) ? $data['line'] : null; |
||
113 | $this->class = isset($data['class']) ? $data['class'] : null; |
||
114 | $this->function = isset($data['function']) ? $data['function'] : null; |
||
115 | $this->type = isset($data['type']) ? $data['type'] : null; |
||
116 | $this->args = isset($data['args']) ? (array) $data['args'] : []; |
||
117 | $this->file = isset($data['file']) ? $data['file'] : null; |
||
118 | |||
119 | // If we're dealing with a class, try to get its namespace and short name. |
||
120 | if (null !== $this->class) { |
||
121 | $parts = explode('\\', $this->class); |
||
122 | |||
123 | $this->shortClass = array_pop($parts); |
||
124 | $this->namespace = implode('\\', $parts); |
||
125 | } |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Returns the line which got executed resulting in the inspected trace. |
||
130 | * |
||
131 | * @return int|null |
||
132 | */ |
||
133 | public function getLine() |
||
134 | { |
||
135 | return $this->line; |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Returns the name of the class which got executed resulting in the inspected trace. |
||
140 | * |
||
141 | * @return string|null |
||
142 | */ |
||
143 | public function getClass() |
||
144 | { |
||
145 | return $this->class; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Returns the namespace of the class which got executed resulting in the inspected trace. |
||
150 | * |
||
151 | * @return string|null |
||
152 | */ |
||
153 | public function getNamespace() |
||
154 | { |
||
155 | return $this->namespace; |
||
156 | } |
||
157 | |||
158 | /** |
||
159 | * Returns the shortened name (without the namespace) of the class which got executed resulting in the |
||
160 | * inspected trace. |
||
161 | * |
||
162 | * @return string|null |
||
163 | */ |
||
164 | public function getShortClass() |
||
165 | { |
||
166 | return $this->shortClass; |
||
167 | } |
||
168 | |||
169 | /** |
||
170 | * Returns the function/method which got executed resulting in the inspected trace. |
||
171 | * |
||
172 | * @return string|null |
||
173 | */ |
||
174 | public function getFunction() |
||
175 | { |
||
176 | return $this->function; |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Returns the type of the function/method call (static or dynamic). |
||
181 | * |
||
182 | * @return string|null |
||
183 | */ |
||
184 | public function getType() |
||
185 | { |
||
186 | return $this->type; |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * Returns the arguments which were passed to the function resulting in the inspected trace. |
||
191 | * |
||
192 | * @return array |
||
193 | */ |
||
194 | public function getArgs() : array |
||
195 | { |
||
196 | return $this->args; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Returns the path to the file assigned to the current frame. |
||
201 | * |
||
202 | * @return string |
||
203 | */ |
||
204 | public function getFile() |
||
205 | { |
||
206 | return $this->file; |
||
207 | } |
||
208 | |||
209 | /** |
||
210 | * Returns the contents of the file assigned to this frame as a string. |
||
211 | * |
||
212 | * @return string|bool Returns either the contents of the assigned file or false if no file is assigned |
||
213 | * or its contents could not be fetched. |
||
214 | */ |
||
215 | public function getFileContents() |
||
216 | { |
||
217 | // No point in continuing if there is no file assigned to this frame. |
||
218 | if (!$this->file || $this->file === 'Unknown') { |
||
219 | return false; |
||
220 | } |
||
221 | |||
222 | // If the assigned file's contents are already cached, return them right away. |
||
223 | // Note: "False" might also be cached instead of the actual file contents if retrieval |
||
224 | // of the contents failed once already. |
||
225 | if (isset(static::$files[$this->file])) { |
||
0 ignored issues
–
show
|
|||
226 | return static::$files[$this->file]; |
||
0 ignored issues
–
show
Since
$files is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $files to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
227 | } |
||
228 | |||
229 | // Otherwise grab the contents, cache them and return them. |
||
230 | return static::$files[$this->file] = file_get_contents($this->file); |
||
0 ignored issues
–
show
Since
$files is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self , or increasing the visibility of $files to at least protected.
Let’s assume you have a class which uses late-static binding: class YourClass
{
private static $someVariable;
public static function getSomeVariable()
{
return static::$someVariable;
}
}
The code above will run fine in your PHP runtime. However, if you now create a
sub-class and call the class YourSubClass extends YourClass { }
YourSubClass::getSomeVariable(); // Will cause an access error.
In the case above, it makes sense to update class SomeClass
{
private static $someVariable;
public static function getSomeVariable()
{
return self::$someVariable; // self works fine with private.
}
}
![]() |
|||
231 | } |
||
232 | |||
233 | /** |
||
234 | * Returns the contents of the file assigned to this frame as an array of lines optionally sliced from |
||
235 | * the given starting line to the given ending line. The arguments used work in exactly the same way as |
||
236 | * {@see array_splice()}. |
||
237 | * |
||
238 | * Note: Lines are 0-indexed. |
||
239 | * |
||
240 | * @param int $offset The starting offset. |
||
241 | * @param int $length The length of the resulting subset. |
||
242 | * @return string[]|null The resulting array of lines or an empty array when no file contents are available. |
||
243 | */ |
||
244 | public function getFileLines(int $offset = 0, int $length = null) : array |
||
245 | { |
||
246 | // Return null right away if we are not able to grab the file contents for any reason. |
||
247 | if (!$contents = $this->getFileContents()) { |
||
248 | return []; |
||
249 | } |
||
250 | |||
251 | // Explode the contents into an array by line breaks and return the slice. Note: Normally we'd simply read |
||
252 | // the contents into an array directly by using file(), but to avoid code duplication and to keep caching |
||
253 | // simple it's done as-is. |
||
254 | return array_slice(explode("\n", $contents), $offset, $length, true); |
||
255 | } |
||
256 | |||
257 | /** |
||
258 | * Returns the file path (if present) with the part common for all frames replaced by an ellipsis and slashes |
||
259 | * replaced by soft slashes for presentation purposes (word wrapping). |
||
260 | * |
||
261 | * @return string |
||
262 | * @todo Replace the dirname() calls with a required string parameter for the path which shall get cut out. |
||
263 | */ |
||
264 | public function getPrettyPath() |
||
265 | { |
||
266 | if ($path = $this->file) { |
||
267 | $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); |
||
268 | $path = str_replace($dirname, "…", $path); |
||
269 | } |
||
270 | |||
271 | return $path; |
||
272 | } |
||
273 | |||
274 | /** |
||
275 | * {@inheritDoc} |
||
276 | */ |
||
277 | public function serialize() |
||
278 | { |
||
279 | $data = $this->toArray(); |
||
280 | |||
281 | !empty($data['args']) && $data['args'] = $this->flattenArgs($data['args']); |
||
282 | |||
283 | return serialize($data); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * {@inheritDoc} |
||
288 | */ |
||
289 | public function unserialize($data) |
||
290 | { |
||
291 | $this->setData(unserialize($data)); |
||
292 | } |
||
293 | |||
294 | /** |
||
295 | * {@inheritDoc} |
||
296 | */ |
||
297 | public function toArray() : array |
||
298 | { |
||
299 | return $this->getData(); |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Flattens the args to make them easier to serialize. |
||
304 | * |
||
305 | * @param array $args The args to flatten. |
||
306 | * @param int $level The current nesting depth. |
||
307 | * @return array The flattened args. |
||
308 | */ |
||
309 | protected function flattenArgs(array $args, $level = 0) |
||
310 | { |
||
311 | $result = []; |
||
312 | |||
313 | foreach ($args as $key => $value) { |
||
314 | if (is_object($value)) { |
||
315 | $result[$key] = ['object', get_class($value)]; |
||
316 | } elseif (is_array($value)) { |
||
317 | if ($level > $this->nestingLimit) { |
||
318 | $result[$key] = ['array', '*DEEP NESTED ARRAY*']; |
||
319 | } else { |
||
320 | $result[$key] = ['array', $this->flattenArgs($value, ++$level)]; |
||
321 | } |
||
322 | } elseif (null === $value) { |
||
323 | $result[$key] = ['null', null]; |
||
324 | } elseif (is_bool($value)) { |
||
325 | $result[$key] = ['boolean', $value]; |
||
326 | } elseif (is_resource($value)) { |
||
327 | $result[$key] = ['resource', get_resource_type($value)]; |
||
328 | } |
||
329 | // Special case of object, is_object will return false. |
||
330 | elseif ($value instanceof \__PHP_Incomplete_Class) { |
||
331 | $array = new \ArrayObject($value); |
||
332 | $result[$key] = ['incomplete-object', $array['__PHP_Incomplete_Class_Name']]; |
||
333 | } else { |
||
334 | $result[$key] = ['string', (string) $value]; |
||
335 | } |
||
336 | } |
||
337 | |||
338 | return $result; |
||
339 | } |
||
340 | } |
||
341 |
Let’s assume you have a class which uses late-static binding:
The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the
getSomeVariable()
on that sub-class, you will receive a runtime error:In the case above, it makes sense to update
SomeClass
to useself
instead: