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/Timer.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 Timer
6
 *
7
 * @package Xicrow\PhpDebug
8
 */
9
class Timer
10
{
11
    /**
12
     * @var array
13
     */
14
    public static $collection = [];
15
16
    /**
17
     * @var boolean|string
18
     */
19
    public static $currentItem = false;
20
21
    /**
22
     * @var array
23
     */
24
    public static $runningItems = [];
25
26
    /**
27
     * Force the unit to display elapsed times in (MS|S|M|H|D|W)
28
     *
29
     * @var null|string
30
     */
31
    public static $forceDisplayUnit = null;
32
33
    /**
34
     * Color threshold for output (5 => 'red', all items with values of 5 or higher will be red)
35
     *
36
     * @var array
37
     */
38
    public static $colorThreshold = [];
39
40
    /**
41
     * @var bool
42
     */
43
    public static $output = true;
44
45
    /**
46
     * @var array
47
     */
48
    public static $style = [
49
        '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; color: #FF8400; display: block; z-index: 1000;">%s</pre>',
50
        '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; color: #AAAAAA; display: block; z-index: 1000;">%s</pre>',
51
        'hover_style'        => 'background-color: #333333;',
52
    ];
53
54
    /**
55
     * @param string $data
56
     *
57
     * @codeCoverageIgnore
58
     */
59
    public static function output($data)
60
    {
61
        if (!self::$output || !is_string($data)) {
62
            return;
63
        }
64
65
        if (php_sapi_name() != 'cli') {
66
            echo sprintf(self::$style['called_from_format'], Debugger::getCalledFrom(2));
67
            echo sprintf(self::$style['output_format'], $data);
68
            echo '<style type="text/css">.xicrow-php-debug-timer:hover{ ' . self::$style['hover_style'] . ' }</style>';
69
        } else {
70
            echo Debugger::getCalledFrom(2);
71
            echo "\n";
72
            echo $data;
73
        }
74
    }
75
76
    /**
77
     *
78
     */
79 6
    public static function reset()
80
    {
81 6
        self::$collection   = [];
82 6
        self::$currentItem  = false;
83 6
        self::$runningItems = [];
84 6
    }
85
86
    /**
87
     * @param string|null $key
88
     * @param array       $data
89
     *
90
     * @return string
91
     */
92 6
    public static function add($key = null, $data = [])
93
    {
94
        // If no key is given
95 6
        if (is_null($key)) {
96
            // Set key to file and line
97
            $key = Debugger::getCalledFrom(2);
98
        }
99
100
        // If key is allready in use
101 6
        if (isset(self::$collection[$key])) {
102
            // Get original item
103 1
            $item = self::$collection[$key];
104
105
            // Set new item count
106 1
            $itemCount = (isset($item['count']) ? ($item['count'] + 1) : 2);
107
108
            // Set correct key for the original item
109 1
            if (strpos($item['key'], '#') === false) {
110 1
                self::$collection[$key] = array_merge($item, [
111 1
                    'key'   => $key . ' #1',
112 1
                    'count' => $itemCount,
113
                ]);
114
            } else {
115
                self::$collection[$key] = array_merge($item, [
116
                    'count' => $itemCount,
117
                ]);
118
            }
119
120
            // Set new key
121 1
            $key = $key . ' #' . $itemCount;
122
        }
123
124
        // Make sure various options are set
125 6
        if (!isset($data['key'])) {
126 6
            $data['key'] = $key;
127
        }
128 6
        if (!isset($data['parent'])) {
129 6
            $data['parent'] = self::$currentItem;
130
        }
131 6
        if (!isset($data['level'])) {
132 6
            $data['level'] = 0;
133 6
            if (isset($data['parent']) && isset(self::$collection[$data['parent']])) {
134 1
                $data['level'] = (self::$collection[$data['parent']]['level'] + 1);
135
            }
136
        }
137
138
        // Add item to collection
139 6
        self::$collection[$key] = $data;
140
141 6
        return $key;
142
    }
143
144
    /**
145
     * @param string|null $key
146
     *
147
     * @return string
148
     */
149 3
    public static function start($key = null)
150
    {
151
        // Add new item
152 3
        $key = self::add($key, [
153 3
            'start' => microtime(true),
154
        ]);
155
156
        // Set current item
157 3
        self::$currentItem = $key;
158
159
        // Add to running items
160 3
        self::$runningItems[$key] = true;
161
162 3
        return $key;
163
    }
164
165
    /**
166
     * @param string|null $key
167
     *
168
     * @return string
169
     */
170 2
    public static function stop($key = null)
171
    {
172
        // If no key is given
173 2
        if (is_null($key)) {
174
            // Get key of the last started item
175 1
            end(self::$runningItems);
176 1
            $key = key(self::$runningItems);
177
        }
178
179
        // Check for key duplicates, and find the last one not stopped
180 2
        if (isset(self::$collection[$key]) && isset(self::$collection[$key . ' #2'])) {
181 1
            $lastNotStopped = false;
182 1
            $currentKey     = $key;
183 1
            $currentIndex   = 1;
184 1
            while (isset(self::$collection[$currentKey])) {
185 1
                if (!isset(self::$collection[$currentKey]['stop'])) {
186 1
                    $lastNotStopped = $currentKey;
187
                }
188
189 1
                $currentIndex++;
190 1
                $currentKey = $key . ' #' . $currentIndex;
191
            }
192
193 1
            if ($lastNotStopped) {
194 1
                $key = $lastNotStopped;
195
            }
196
        }
197
198
        // If item exists in collection
199 2
        if (isset(self::$collection[$key])) {
200
            // Update the item
201 2
            self::$collection[$key]['stop'] = microtime(true);
202
203 2
            self::$currentItem = self::$collection[$key]['parent'];
204
        }
205
206 2
        if (isset(self::$runningItems[$key])) {
207 2
            unset(self::$runningItems[$key]);
208
        }
209
210 2
        return $key;
211
    }
212
213
    /**
214
     * @param string|null    $key
215
     * @param int|float|null $start
216
     * @param int|float|null $stop
217
     *
218
     * @return string
219
     */
220 2
    public static function custom($key = null, $start = null, $stop = null)
221
    {
222
        // Add new item
223 2
        self::add($key, [
224 2
            'start' => $start,
225 2
            'stop'  => $stop,
226
        ]);
227
228
        // If no stop value is given
229 2
        if (is_null($stop)) {
230
            // Set current item
231 1
            self::$currentItem = $key;
232
233
            // Add to running items
234 1
            self::$runningItems[$key] = true;
235
        }
236
237 2
        return $key;
238
    }
239
240
    /**
241
     * @param string|null           $key
242
     * @param string|array|\Closure $callback
243
     *
244
     * @return mixed
245
     */
246 1
    public static function callback($key = null, $callback)
247
    {
248
        // Get parameters for callback
249 1
        $callbackParams = func_get_args();
250 1
        unset($callbackParams[0], $callbackParams[1]);
251 1
        $callbackParams = array_values($callbackParams);
252
253
        // Get key if no key is given
254 1
        if (is_null($key)) {
255 1
            if (is_string($callback)) {
256 1
                $key = $callback;
257 1
            } elseif (is_array($callback)) {
258 1
                $keyArr = [];
259 1
                foreach ($callback as $k => $v) {
260 1
                    if (is_string($v)) {
261 1
                        $keyArr[] = $v;
262 1
                    } elseif (is_object($v)) {
263 1
                        $keyArr[] = get_class($v);
264
                    }
265
                }
266
267 1
                $key = implode('', $keyArr);
268 1
                if (count($keyArr) > 1) {
269 1
                    $method = array_pop($keyArr);
270 1
                    $key    = implode('/', $keyArr);
271 1
                    $key    .= '::' . $method;
272
                }
273
274 1
                unset($keyArr, $method);
275 1
            } elseif (is_object($callback) && $callback instanceof \Closure) {
276 1
                $key = 'closure';
277
            }
278 1
            $key = 'callback: ' . $key;
279
        }
280
281
        // Set default return value
282 1
        $returnValue = true;
283
284
        // Set error handler, to convert errors to exceptions
285 1
        set_error_handler(function ($errno, $errstr, $errfile, $errline, array $errcontext) {
0 ignored issues
show
The parameter $errcontext is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
286 1
            throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
287 1
        });
288
289
        try {
290
            // Start output buffer to capture any output
291 1
            ob_start();
292
293
            // Start profiler
294 1
            self::start($key);
295
296
            // Execute callback, and get result
297 1
            $callbackResult = call_user_func_array($callback, $callbackParams);
298
299
            // Stop profiler
300 1
            self::stop($key);
301
302
            // Get and clean output buffer
303 1
            $callbackOutput = ob_get_clean();
304 1
        } catch (\ErrorException $callbackException) {
305
            // Stop and clean output buffer
306 1
            ob_end_clean();
307
308
            // Show error message
309 1
            self::output('Invalid callback sent to Timer::callback: ' . str_replace('callback: ', '', $key));
310
311
            // Clear the item from the collection
312 1
            unset(self::$collection[$key]);
313
314
            // Clear callback result and output
315 1
            unset($callbackResult, $callbackOutput);
316
317
            // Set return value to false
318 1
            $returnValue = false;
319
        }
320
321
        // Restore error handler
322 1
        restore_error_handler();
323
324
        // Return result, output or true
325 1
        return (isset($callbackResult) ? $callbackResult : (!empty($callbackOutput) ? $callbackOutput : $returnValue));
326
    }
327
328
    /**
329
     * @param string|null $key
330
     * @param array       $options
331
     *
332
     * @codeCoverageIgnore
333
     */
334
    public static function show($key = null, $options = [])
335
    {
336
        $output = self::getStats($key, $options);
337
338
        if (!empty($output)) {
339
            self::output($output);
340
        }
341
    }
342
343
    /**
344
     * @param array $options
345
     *
346
     * @codeCoverageIgnore
347
     */
348
    public static function showAll($options = [])
349
    {
350
        // Stop started items
351
        if (count(self::$runningItems)) {
352
            foreach (self::$runningItems as $key => $value) {
353
                self::stop($key);
354
            }
355
        }
356
357
        // Output items
358
        $output    = '';
359
        $itemCount = 1;
360
        foreach (self::$collection as $key => $item) {
361
            $stats = self::getStats($key, $options);
362
363
            if (php_sapi_name() == 'cli') {
364
                $output .= (!empty($output) ? "\n" : '') . $stats;
365
            } else {
366
                $output .= '<div class="xicrow-php-debug-timer">';
367
                $output .= $stats;
368
                $output .= '</div>';
369
            }
370
371
            $itemCount++;
372
373
            unset($stats);
374
        }
375
        unset($itemCount);
376
377
        self::output($output);
378
    }
379
380
    /**
381
     * @param string|null $key
382
     * @param array       $options
383
     *
384
     * @return string
385
     */
386 1
    public static function getStats($key, $options = [])
387
    {
388
        // Merge options with default options
389 1
        $options = array_merge([
390
            // Show nested (boolean)
391 1
            'nested'         => true,
392
            // Prefix for nested items (string)
393
            'nested_prefix'  => '|-- ',
394
            // Max key length (int)
395
            'max_key_length' => 100,
396 1
        ], $options);
397
398
        // If item does not exist
399 1
        if (!isset(self::$collection[$key])) {
400 1
            return 'Unknow item in with key: ' . $key;
401
        }
402
403
        // Get item
404 1
        $item = self::$collection[$key];
405
406
        // Get item result
407 1
        $itemResult          = 'N/A';
408 1
        $itemResultFormatted = 'N/A';
409 1
        if (isset($item['start']) && isset($item['stop'])) {
410 1
            $itemResult          = (($item['stop'] - $item['start']) * 1000);
411 1
            $itemResultFormatted = self::formatMiliseconds($itemResult, 4, self::$forceDisplayUnit);
412
        }
413
414
        // Variable for output
415 1
        $output = '';
416
417
        // Prep key for output
418 1
        $outputName = '';
419 1
        $outputName .= ($options['nested'] ? str_repeat($options['nested_prefix'], $item['level']) : '');
420 1
        $outputName .= $item['key'];
421 1
        if (mb_strlen($outputName) > $options['max_key_length']) {
422 1
            $outputName = '~' . mb_substr($item['key'], -($options['max_key_length'] - 1));
423
        }
424
425
        // Add item stats
426 1
        $output .= str_pad($outputName, ($options['max_key_length'] + (strlen($outputName) - mb_strlen($outputName))), ' ');
427 1
        $output .= ' | ';
428 1
        $output .= str_pad($itemResultFormatted, 20, ' ', ($itemResult == 'N/A' ? STR_PAD_RIGHT : STR_PAD_LEFT));
429
430 1
        if (php_sapi_name() != 'cli' && is_array(self::$colorThreshold) && count(self::$colorThreshold)) {
431
            krsort(self::$colorThreshold);
432
            foreach (self::$colorThreshold as $value => $color) {
433
                if (is_numeric($itemResult) && $itemResult >= $value) {
434
                    $output = '<span style="color: ' . $color . ';">' . $output . '</span>';
435
                }
436
            }
437
        }
438
439 1
        return $output;
440
    }
441
442
    /**
443
     * @param int|float   $number
444
     * @param int         $precision
445
     * @param null|string $forceUnit
446
     *
447
     * @return string
448
     */
449 1
    public static function formatMiliseconds($number = 0, $precision = 2, $forceUnit = null)
450
    {
451
        $units = [
452 1
            'MS' => 1,
453
            'S'  => 1000,
454
            'M'  => 60,
455
            'H'  => 60,
456
            'D'  => 24,
457
            'W'  => 7,
458
        ];
459
460 1
        if (is_null($forceUnit)) {
461 1
            $forceUnit = self::$forceDisplayUnit;
462
        }
463
464 1
        $value = $number;
465 1
        if (!empty($forceUnit) && array_key_exists($forceUnit, $units)) {
466 1
            $unit = $forceUnit;
467 1
            foreach ($units as $k => $v) {
468 1
                $value = ($value / $v);
469 1
                if ($k == $unit) {
470 1
                    break;
471
                }
472
            }
473
        } else {
474 1
            $unit = '';
475 1
            foreach ($units as $k => $v) {
476 1
                if (empty($unit) || ($value / $v) > 1) {
477 1
                    $value = ($value / $v);
478 1
                    $unit  = $k;
479
                } else {
480 1
                    break;
481
                }
482
            }
483
        }
484
485 1
        return sprintf('%0.' . $precision . 'f', $value) . ' ' . str_pad($unit, 2, ' ', STR_PAD_RIGHT);
486
    }
487
}
488