Issues (3)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Debugger.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace Xicrow\PhpDebug;
3
4
/**
5
 * Class Debugger
6
 *
7
 * @package Xicrow\PhpDebug
8
 */
9
class Debugger
10
{
11
    /**
12
     * @var string|null
13
     */
14
    public static $documentRoot = null;
15
16
    /**
17
     * @var bool
18
     */
19
    public static $showCalledFrom = true;
20
21
    /**
22
     * @var bool
23
     */
24
    public static $output = true;
25
26
    /**
27
     * @var array
28
     */
29
    public static $style = [
30
        'output_format'        => '<pre style="margin-top: 0; padding: 5px; font-family: Menlo, Monaco, Consolas, monospace; font-weight: bold; font-size: 12px; background-color: #18171B; border: none; border-radius: 0; color: #FF8400; display: block; z-index: 1000; overflow: auto;">%s</pre>',
31
        'called_from_format'   => '<pre style="margin-bottom: 0; padding: 5px; font-family: Menlo, Monaco, Consolas, monospace; font-weight: normal; font-size: 12px; background-color: #18171B; border: none; border-radius: 0; color: #AAAAAA; display: block; z-index: 1000;  overflow: auto;">%s</pre>',
32
        'debug_null_format'    => '<span style="color: #B729D9;">%s</span>',
33
        'debug_boolean_format' => '<span style="color: #B729D9;">%s</span>',
34
        'debug_integer_format' => '<span style="color: #1299DA;">%s</span>',
35
        'debug_double_format'  => '<span style="color: #1299DA;">%s</span>',
36
        'debug_string_format'  => '<span style="color: #1299DA;">"</span>%s<span style="color: #1299DA;">"</span>',
37
    ];
38
39
    /**
40
     * @param string $data
41
     * @param array  $options
42
     *
43
     * @codeCoverageIgnore
44
     */
45
    public static function output($data, array $options = [])
46
    {
47
        $options = array_merge([
48
            'trace_offset' => 0,
49
        ], $options);
50
51
        if (!self::$output || !is_string($data)) {
52
            return;
53
        }
54
55
        if (php_sapi_name() == 'cli') {
56
            echo str_pad(' DEBUG ', 100, '-', STR_PAD_BOTH);
57
            echo "\n";
58
            if (self::$showCalledFrom) {
59
                echo self::getCalledFrom($options['trace_offset'] + 2);
60
                echo "\n";
61
            }
62
            echo $data;
63
            echo "\n";
64
        } else {
65
            if (self::$showCalledFrom) {
66
                echo sprintf(self::$style['called_from_format'], self::getCalledFrom($options['trace_offset'] + 2));
67
            }
68
            echo sprintf(self::$style['output_format'], $data);
69
        }
70
    }
71
72
    /**
73
     * @param mixed $data
74
     * @param array $options
75
     *
76
     * @codeCoverageIgnore
77
     */
78
    public static function debug($data, array $options = [])
79
    {
80
        $options = array_merge([
81
            'trace_offset' => 0,
82
        ], $options);
83
84
        self::output(self::getDebugInformation($data), $options);
85
    }
86
87
    /**
88
     * @param array $options
89
     *
90
     * @codeCoverageIgnore
91
     */
92
    public static function showTrace(array $options = [])
93
    {
94
        $options = array_merge([
95
            'trace_offset' => 0,
96
            'reverse'      => false,
97
        ], $options);
98
99
        $backtrace = ($options['reverse'] ? array_reverse(debug_backtrace()) : debug_backtrace());
100
101
        $output     = '';
102
        $traceIndex = ($options['reverse'] ? 1 : count($backtrace));
103
        foreach ($backtrace as $trace) {
104
            $output .= $traceIndex . ': ';
105
            $output .= self::getCalledFromTrace($trace);
106
            $output .= "\n";
107
108
            $traceIndex += ($options['reverse'] ? 1 : -1);
109
        }
110
111
        self::output($output, $options);
112
    }
113
114
    /**
115
     * @param string $class
116
     * @param bool   $output
117
     *
118
     * @return string
119
     */
120 1
    public static function reflectClass($class, $output = true)
121
    {
122 1
        $data = '';
123
124 1
        $reflectionClass = new \ReflectionClass($class);
125
126 1
        $comment = $reflectionClass->getDocComment();
127 1
        if (!empty($comment)) {
128 1
            $data .= $comment;
129 1
            $data .= "\n";
130
        }
131
132 1
        $data         .= 'class ' . $reflectionClass->name . '{';
133 1
        $firstElement = true;
134 1
        foreach ($reflectionClass->getProperties() as $reflectionProperty) {
135 1
            if (!$firstElement) {
136 1
                $data .= "\n";
137
            }
138 1
            $firstElement = false;
139
140 1
            $data .= self::reflectClassProperty($class, $reflectionProperty->name, false);
141
        }
142
143 1
        foreach ($reflectionClass->getMethods() as $reflectionMethod) {
144 1
            if (!$firstElement) {
145 1
                $data .= "\n";
146
            }
147 1
            $firstElement = false;
148
149 1
            $data .= self::reflectClassMethod($class, $reflectionMethod->name, false);
150
        }
151 1
        $data .= "\n";
152 1
        $data .= '}';
153
154 1
        if ($output) {
155 1
            self::output($data);
156
        }
157
158 1
        return $data;
159
    }
160
161
    /**
162
     * @param string $class
163
     * @param string $property
164
     *
165
     * @return string
166
     */
167 2
    public static function reflectClassProperty($class, $property, $output = true)
168
    {
169 2
        $data = '';
170
171 2
        $reflectionClass    = new \ReflectionClass($class);
172 2
        $reflectionProperty = new \ReflectionProperty($class, $property);
173
174 2
        $defaultPropertyValues = $reflectionClass->getDefaultProperties();
175
176 2
        $comment = $reflectionProperty->getDocComment();
177 2
        if (!empty($comment)) {
178 2
            $data .= "\n";
179 2
            $data .= "\t";
180 2
            $data .= $comment;
181
        }
182
183 2
        $data .= "\n";
184 2
        $data .= "\t";
185 2
        $data .= ($reflectionProperty->isPublic() ? 'public ' : '');
186 2
        $data .= ($reflectionProperty->isPrivate() ? 'private ' : '');
187 2
        $data .= ($reflectionProperty->isProtected() ? 'protected ' : '');
188 2
        $data .= ($reflectionProperty->isStatic() ? 'static ' : '');
189 2
        $data .= '$' . $reflectionProperty->name;
190 2
        if (isset($defaultPropertyValues[$property])) {
191 2
            $data .= ' = ' . self::getDebugInformation($defaultPropertyValues[$property]);
192
        }
193 2
        $data .= ';';
194
195 2
        if ($output) {
196 1
            self::output($data);
197
        }
198
199 2
        return $data;
200
    }
201
202
    /**
203
     * @param string $class
204
     * @param string $method
205
     * @param bool   $output
206
     *
207
     * @return string
208
     */
209 2
    public static function reflectClassMethod($class, $method, $output = true)
210
    {
211 2
        $data = '';
212
213 2
        $reflectionMethod = new \ReflectionMethod($class, $method);
214
215 2
        $comment = $reflectionMethod->getDocComment();
216 2
        if (!empty($comment)) {
217 2
            $data .= "\n";
218 2
            $data .= "\t";
219 2
            $data .= $comment;
220
        }
221
222 2
        $data .= "\n";
223 2
        $data .= "\t";
224 2
        $data .= ($reflectionMethod->isPublic() ? 'public ' : '');
225 2
        $data .= ($reflectionMethod->isPrivate() ? 'private ' : '');
226 2
        $data .= ($reflectionMethod->isProtected() ? 'protected ' : '');
227 2
        $data .= ($reflectionMethod->isStatic() ? 'static ' : '');
228 2
        $data .= 'function ' . $reflectionMethod->name . '(';
229 2
        if ($reflectionMethod->getNumberOfParameters()) {
230 2
            foreach ($reflectionMethod->getParameters() as $reflectionMethodParameterIndex => $reflectionMethodParameter) {
231 2
                $data .= ($reflectionMethodParameterIndex > 0 ? ', ' : '');
232 2
                $data .= '$' . $reflectionMethodParameter->name;
233 2
                if ($reflectionMethodParameter->isDefaultValueAvailable()) {
234 2
                    $defaultValue = self::getDebugInformation($reflectionMethodParameter->getDefaultValue());
235 2
                    $defaultValue = str_replace(["\n", "\t"], '', $defaultValue);
236 2
                    $data         .= ' = ' . $defaultValue;
237
                }
238
            }
239
        }
240 2
        $data .= ') {}';
241
242 2
        if ($output) {
243 1
            self::output($data);
244
        }
245
246 2
        return $data;
247
    }
248
249
    /**
250
     * @param int $index
251
     *
252
     * @return string
253
     */
254 1
    public static function getCalledFrom($index = 0)
255
    {
256 1
        $backtrace = debug_backtrace();
257
258 1
        if (!isset($backtrace[$index])) {
259 1
            return 'Unknown trace with index: ' . $index;
260
        }
261
262 1
        return self::getCalledFromTrace($backtrace[$index]);
263
    }
264
265
    /**
266
     * @param array $trace
267
     *
268
     * @return string
269
     */
270 1
    public static function getCalledFromTrace($trace)
271
    {
272
        // Get file and line number
273 1
        $calledFromFile = '';
274 1
        if (isset($trace['file'])) {
275 1
            $calledFromFile .= $trace['file'] . ' line ' . $trace['line'];
276 1
            $calledFromFile = str_replace('\\', '/', $calledFromFile);
277 1
            $calledFromFile = (!empty(self::$documentRoot) ? substr($calledFromFile, strlen(self::$documentRoot)) : $calledFromFile);
278 1
            $calledFromFile = trim($calledFromFile, '/');
279
        }
280
281
        // Get function call
282 1
        $calledFromFunction = '';
283 1
        if (isset($trace['function'])) {
284 1
            $calledFromFunction .= (isset($trace['class']) ? $trace['class'] : '');
285 1
            $calledFromFunction .= (isset($trace['type']) ? $trace['type'] : '');
286 1
            $calledFromFunction .= $trace['function'] . '()';
287
        }
288
289
        // Return called from
290 1
        if ($calledFromFile) {
291 1
            return $calledFromFile;
292 1
        } elseif ($calledFromFunction) {
293 1
            return $calledFromFunction;
294
        } else {
295
            return 'Unable to get called from trace';
296
        }
297
    }
298
299
    /**
300
     * @param mixed $data
301
     *
302
     * @return string
303
     */
304 1
    public static function getDebugInformation($data, array $options = [])
305
    {
306
        // Merge options with default options
307 1
        $options = array_merge([
308 1
            'depth'  => 25,
309
            'indent' => 0,
310 1
        ], $options);
311
312
        // Get data type
313 1
        $dataType = gettype($data);
314
315
        // Set name of method to get debug information for data
316 1
        $methodName = 'getDebugInformation' . ucfirst(strtolower($dataType));
317
318
        // Get result from debug information method
319 1
        $result = 'No method found supporting data type: ' . $dataType;
320 1
        if (method_exists('\Xicrow\PhpDebug\Debugger', $methodName)) {
321 1
            $result = (string)self::$methodName($data, [
322 1
                'depth'  => ($options['depth'] - 1),
323 1
                'indent' => ($options['indent'] + 1),
324
            ]);
325
        }
326
327
        // Format the result
328 1
        if (php_sapi_name() != 'cli' && !empty(self::$style['debug_' . strtolower($dataType) . '_format'])) {
329
            $result = sprintf(self::$style['debug_' . strtolower($dataType) . '_format'], $result);
330
        }
331
332
        // Return result
333 1
        return $result;
334
    }
335
336
    /**
337
     * @return string
338
     */
339 1
    private static function getDebugInformationString($data)
340
    {
341 1
        return (string)(php_sapi_name() == 'cli' ? '"' . $data . '"' : htmlentities($data, ENT_SUBSTITUTE));
342
    }
343
344
    /**
345
     * @return string
346
     */
347 1
    private static function getDebugInformationNull()
348
    {
349 1
        return 'NULL';
350
    }
351
352
    /**
353
     * @param boolean $data
354
     *
355
     * @return string
356
     */
357 1
    private static function getDebugInformationBoolean($data)
358
    {
359 1
        return ($data ? 'TRUE' : 'FALSE');
360
    }
361
362
    /**
363
     * @param integer $data
364
     *
365
     * @return string
366
     */
367 1
    private static function getDebugInformationInteger($data)
368
    {
369 1
        return (string)$data;
370
    }
371
372
    /**
373
     * @param double $data
374
     *
375
     * @return string
376
     */
377 1
    private static function getDebugInformationDouble($data)
378
    {
379 1
        return (string)$data;
380
    }
381
382
    /**
383
     * @param array $data
384
     *
385
     * @return string
386
     */
387 1
    private static function getDebugInformationArray($data, array $options = [])
388
    {
389 1
        $options = array_merge([
390 1
            'depth'  => 25,
391
            'indent' => 0,
392 1
        ], $options);
393
394 1
        $debugInfo = "[";
395
396 1
        $break = $end = null;
397 1
        if (!empty($data)) {
398 1
            $break = "\n" . str_repeat("\t", $options['indent']);
399 1
            $end   = "\n" . str_repeat("\t", $options['indent'] - 1);
400
        }
401
402 1
        $datas = [];
403 1
        if ($options['depth'] >= 0) {
404 1
            foreach ($data as $key => $val) {
405
                // Sniff for globals as !== explodes in < 5.4
406 1
                if ($key === 'GLOBALS' && is_array($val) && isset($val['GLOBALS'])) {
407
                    $val = '[recursion]';
408 1
                } elseif ($val !== $data) {
409 1
                    $val = static::getDebugInformation($val, $options);
410
                }
411 1
                $datas[] = $break . static::getDebugInformation($key) . ' => ' . $val;
412
            }
413
        } else {
414
            $datas[] = $break . '[maximum depth reached]';
415
        }
416
417 1
        return $debugInfo . implode(',', $datas) . $end . ']';
418
    }
419
420
    /**
421
     * @param object $data
422
     *
423
     * @return string
424
     */
425 1
    private static function getDebugInformationObject($data, array $options = [])
426
    {
427 1
        $options = array_merge([
428 1
            'depth'  => 25,
429
            'indent' => 0,
430 1
        ], $options);
431
432 1
        $debugInfo = '';
433 1
        $debugInfo .= 'object(' . get_class($data) . ') {';
434
435 1
        $break = "\n" . str_repeat("\t", $options['indent']);
436 1
        $end   = "\n" . str_repeat("\t", $options['indent'] - 1);
437
438 1
        if ($options['depth'] > 0 && method_exists($data, '__debugInfo')) {
439
            try {
440
                $debugArray = static::getDebugInformationArray($data->__debugInfo(), array_merge($options, [
0 ignored issues
show
Since getDebugInformationArray() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of getDebugInformationArray() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

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:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
441
                    'depth' => ($options['depth'] - 1),
442
                ]));
443
                $debugInfo  .= substr($debugArray, 1, -1);
444
445
                return $debugInfo . $end . '}';
446
            } catch (\Exception $e) {
447
                $message = $e->getMessage();
448
449
                return $debugInfo . "\n(unable to export object: $message)\n }";
450
            }
451
        }
452
453 1
        if ($options['depth'] > 0) {
454 1
            $props      = [];
455 1
            $objectVars = get_object_vars($data);
456 1
            foreach ($objectVars as $key => $value) {
457 1
                $value   = static::getDebugInformation($value, array_merge($options, [
458 1
                    'depth' => ($options['depth'] - 1),
459
                ]));
460 1
                $props[] = "$key => " . $value;
461
            }
462
463 1
            $ref     = new \ReflectionObject($data);
464
            $filters = [
465 1
                \ReflectionProperty::IS_PROTECTED => 'protected',
466
                \ReflectionProperty::IS_PRIVATE   => 'private',
467
            ];
468 1
            foreach ($filters as $filter => $visibility) {
469 1
                $reflectionProperties = $ref->getProperties($filter);
470 1
                foreach ($reflectionProperties as $reflectionProperty) {
471
                    $reflectionProperty->setAccessible(true);
472
                    $property = $reflectionProperty->getValue($data);
473
474
                    $value   = static::getDebugInformation($property, array_merge($options, [
475
                        'depth' => ($options['depth'] - 1),
476
                    ]));
477
                    $key     = $reflectionProperty->name;
478 1
                    $props[] = sprintf('[%s] %s => %s', $visibility, $key, $value);
479
                }
480
            }
481
482 1
            $debugInfo .= $break . implode($break, $props) . $end;
483
        }
484 1
        $debugInfo .= '}';
485
486 1
        return $debugInfo;
487
    }
488
489
    /**
490
     * @param resource $data
491
     *
492
     * @return string
493
     */
494 1
    private static function getDebugInformationResource($data)
495
    {
496 1
        return (string)$data . ' (' . get_resource_type($data) . ')';
497
    }
498
}
499