unyx /
nyx
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 number of the line which got executed resulting in the inspected trace. |
||
| 90 | * |
||
| 91 | * @return int The number of the line, or 0 if the line is unknown. |
||
| 92 | */ |
||
| 93 | public function getLine() : int |
||
| 94 | { |
||
| 95 | return $this->line; |
||
| 96 | } |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Returns the fully qualified name of the class which contained the code that resulted in the inspected trace. |
||
| 100 | * |
||
| 101 | * @return string The fully qualified name of the class, or an empty string if the class is unknown or the |
||
| 102 | * code was not contained in a class. |
||
| 103 | */ |
||
| 104 | public function getClass() : string |
||
| 105 | { |
||
| 106 | return $this->class; |
||
| 107 | } |
||
| 108 | |||
| 109 | /** |
||
| 110 | * Returns the namespace of the class which contained the code that resulted in the inspected trace. |
||
| 111 | * |
||
| 112 | * @return string The namespace, or an empty string if: the namespace is unknown; the class is unknown |
||
| 113 | * or was contained in the global namespace; the code was not contained in a class. |
||
| 114 | */ |
||
| 115 | public function getNamespace() : string |
||
| 116 | { |
||
| 117 | return $this->namespace; |
||
| 118 | } |
||
| 119 | |||
| 120 | /** |
||
| 121 | * Returns the shortened name (without the namespace) of the class which contained the code that |
||
| 122 | * resulted in the inspected trace. |
||
| 123 | * |
||
| 124 | * @return string The shortened name of the class, or an empty string if the class is unknown or the |
||
| 125 | * code was not contained in a class. |
||
| 126 | */ |
||
| 127 | public function getShortClass() : string |
||
| 128 | { |
||
| 129 | return $this->shortClass; |
||
| 130 | } |
||
| 131 | |||
| 132 | /** |
||
| 133 | * Returns the name of the function/method which got executed resulting in the inspected trace. |
||
| 134 | * |
||
| 135 | * @return string The name of the function/method, or an empty string if the name is unknown or the |
||
| 136 | * code was not executed inside a function/method. |
||
| 137 | */ |
||
| 138 | public function getFunction() : string |
||
| 139 | { |
||
| 140 | return $this->function; |
||
| 141 | } |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Returns the type of the function/method call (static or dynamic). |
||
| 145 | * |
||
| 146 | * @return string The type of the call, or an empty string if the type is unknown. |
||
| 147 | */ |
||
| 148 | public function getType() : string |
||
| 149 | { |
||
| 150 | return $this->type; |
||
| 151 | } |
||
| 152 | |||
| 153 | /** |
||
| 154 | * Returns the arguments which were passed to the function resulting in the inspected trace. |
||
| 155 | * |
||
| 156 | * @return array The arguments (context) of the call, or an empty array if there were none or |
||
| 157 | * they are unknown. |
||
| 158 | */ |
||
| 159 | public function getArgs() : array |
||
| 160 | { |
||
| 161 | return $this->args; |
||
| 162 | } |
||
| 163 | |||
| 164 | /** |
||
| 165 | * Returns the path to the file assigned to the current frame. |
||
| 166 | * |
||
| 167 | * @return string The path, or an empty string if the path is unknown. |
||
| 168 | */ |
||
| 169 | public function getFile() : string |
||
| 170 | { |
||
| 171 | return $this->file; |
||
| 172 | } |
||
| 173 | |||
| 174 | /** |
||
| 175 | * Returns the contents of the file assigned to this frame as a string. |
||
| 176 | * |
||
| 177 | * @return string Returns either the contents of the assigned file or an empty string if no file is assigned |
||
| 178 | * or its contents could not be fetched. |
||
| 179 | */ |
||
| 180 | public function getFileContents() : string |
||
| 181 | { |
||
| 182 | // No point in continuing if there is no file assigned to this frame. |
||
| 183 | if (!$this->file || $this->file === 'Unknown') { |
||
| 184 | return ''; |
||
| 185 | } |
||
| 186 | |||
| 187 | // If the contents aren't cached yet, grab them into our rudimentary in-memory cache. |
||
| 188 | // Note: This may cache a boolean false if the retrieval fails for whatever reason. We're gonna handle |
||
| 189 | // that afterwards and return an empty string instead. |
||
| 190 | if (!isset(static::$files[$this->file])) { |
||
|
0 ignored issues
–
show
|
|||
| 191 | 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.
}
}
Loading history...
|
|||
| 192 | } |
||
| 193 | |||
| 194 | // Return the cached contents of the file or an empty string if no contents could be fetched. |
||
| 195 | 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.
}
}
Loading history...
|
|||
| 196 | } |
||
| 197 | |||
| 198 | /** |
||
| 199 | * Returns the contents of the file assigned to this frame as an array of lines optionally sliced from |
||
| 200 | * the given starting line to the given ending line. The arguments used work in exactly the same way as |
||
| 201 | * {@see array_splice()}. |
||
| 202 | * |
||
| 203 | * Note: Lines are 0-indexed. |
||
| 204 | * |
||
| 205 | * @param int $offset The starting offset. |
||
| 206 | * @param int $length The length of the resulting subset. |
||
| 207 | * @return string[]|null The resulting array of lines or an empty array when no file contents are available. |
||
|
0 ignored issues
–
show
|
|||
| 208 | */ |
||
| 209 | public function getFileLines(int $offset = 0, int $length = null) : array |
||
| 210 | { |
||
| 211 | // Return null right away if we are not able to grab the file contents for any reason. |
||
| 212 | if (!$contents = $this->getFileContents()) { |
||
| 213 | return []; |
||
| 214 | } |
||
| 215 | |||
| 216 | // Explode the contents into an array by line breaks and return the slice. Note: Normally we'd simply read |
||
| 217 | // the contents into an array directly by using file(), but to avoid code duplication and to keep caching |
||
| 218 | // simple it's done as-is. |
||
| 219 | return array_slice(explode("\n", $contents), $offset, $length, true); |
||
| 220 | } |
||
| 221 | |||
| 222 | /** |
||
| 223 | * {@inheritDoc} |
||
| 224 | */ |
||
| 225 | public function serialize() : string |
||
| 226 | { |
||
| 227 | $data = $this->toArray(); |
||
| 228 | |||
| 229 | if (!empty($data['args'])) { |
||
| 230 | $data['args'] = $this->flattenArgs($data['args']); |
||
| 231 | } |
||
| 232 | |||
| 233 | return serialize($data); |
||
| 234 | } |
||
| 235 | |||
| 236 | /** |
||
| 237 | * {@inheritDoc} |
||
| 238 | */ |
||
| 239 | public function unserialize($data) |
||
| 240 | { |
||
| 241 | $this->setData(unserialize($data)); |
||
| 242 | } |
||
| 243 | |||
| 244 | /** |
||
| 245 | * {@inheritDoc} |
||
| 246 | */ |
||
| 247 | public function toArray() : array |
||
| 248 | { |
||
| 249 | return [ |
||
| 250 | 'file' => $this->file, |
||
| 251 | 'line' => $this->line, |
||
| 252 | 'function' => $this->function, |
||
| 253 | 'class' => $this->class, |
||
| 254 | 'type' => $this->type, |
||
| 255 | 'args' => $this->args |
||
| 256 | ]; |
||
| 257 | } |
||
| 258 | |||
| 259 | /** |
||
| 260 | * Sets the Frame's data. |
||
| 261 | * |
||
| 262 | * @param array $data The Frame's data, in the same format as returned by \Exception::getTrace(). |
||
| 263 | * @return $this |
||
| 264 | */ |
||
| 265 | protected function setData(array $data) : Frame |
||
| 266 | { |
||
| 267 | $this->file = $data['file'] ?? ''; |
||
| 268 | $this->line = $data['line'] ?? 0; |
||
| 269 | $this->class = $data['class'] ?? ''; |
||
| 270 | $this->function = $data['function'] ?? ''; |
||
| 271 | $this->type = $data['type'] ?? ''; |
||
| 272 | $this->args = $data['args'] ?? []; |
||
| 273 | |||
| 274 | // If we're dealing with a class, try to get its namespace and short name. |
||
| 275 | if ($this->class) { |
||
| 276 | $parts = explode('\\', $this->class); |
||
| 277 | |||
| 278 | $this->shortClass = array_pop($parts); |
||
| 279 | $this->namespace = implode('\\', $parts); |
||
| 280 | } else { |
||
| 281 | // Otherwise initialize with zero-values. |
||
| 282 | $this->shortClass = ''; |
||
| 283 | $this->namespace = ''; |
||
| 284 | } |
||
| 285 | |||
| 286 | return $this; |
||
| 287 | } |
||
| 288 | |||
| 289 | /** |
||
| 290 | * Flattens the args to make them easier to serialize. |
||
| 291 | * |
||
| 292 | * @param array $args The args to flatten. |
||
| 293 | * @param int $depth The current nesting depth. |
||
| 294 | * @return array The flattened args. |
||
| 295 | */ |
||
| 296 | protected function flattenArgs(array $args, int $depth = 0) : array |
||
| 297 | { |
||
| 298 | $result = []; |
||
| 299 | |||
| 300 | foreach ($args as $key => $value) { |
||
| 301 | if (is_object($value)) { |
||
| 302 | $result[$key] = ['object', get_class($value)]; |
||
| 303 | } elseif (is_array($value)) { |
||
| 304 | if ($depth > $this->nestingLimit) { |
||
| 305 | $result[$key] = ['array', '*DEEP NESTED ARRAY*']; |
||
| 306 | } else { |
||
| 307 | $result[$key] = ['array', $this->flattenArgs($value, ++$depth)]; |
||
| 308 | } |
||
| 309 | } elseif (null === $value) { |
||
| 310 | $result[$key] = ['null', null]; |
||
| 311 | } elseif (is_bool($value)) { |
||
| 312 | $result[$key] = ['boolean', $value]; |
||
| 313 | } elseif (is_resource($value)) { |
||
| 314 | $result[$key] = ['resource', get_resource_type($value)]; |
||
| 315 | } elseif ($value instanceof \__PHP_Incomplete_Class) { |
||
| 316 | // Special case of object - is_object() will return false. |
||
| 317 | $array = new \ArrayObject($value); |
||
| 318 | $result[$key] = ['incomplete-object', $array['__PHP_Incomplete_Class_Name']]; |
||
| 319 | } else { |
||
| 320 | $result[$key] = ['string', (string) $value]; |
||
| 321 | } |
||
| 322 | } |
||
| 323 | |||
| 324 | return $result; |
||
| 325 | } |
||
| 326 | } |
||
| 327 |
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
SomeClassto useselfinstead: