Issues (1165)

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/SourceParser.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
3
class Kint_SourceParser
4
{
5
    private static $ignore = array(
6
        T_CLOSE_TAG => true,
7
        T_COMMENT => true,
8
        T_DOC_COMMENT => true,
9
        T_INLINE_HTML => true,
10
        T_OPEN_TAG => true,
11
        T_OPEN_TAG_WITH_ECHO => true,
12
        T_WHITESPACE => true,
13
    );
14
15
    /**
16
     * Things we need to do specially for operator tokens:
17
     * - Refuse to strip spaces around them
18
     * - Wrap the access path in parentheses if there
19
     *   are any of these in the final short parameter.
20
     */
21
    private static $operator = array(
22
        T_AND_EQUAL => true,
23
        T_BOOLEAN_AND => true,
24
        T_BOOLEAN_OR => true,
25
        T_ARRAY_CAST => true,
26
        T_BOOL_CAST => true,
27
        T_CLONE => true,
28
        T_CONCAT_EQUAL => true,
29
        T_DEC => true,
30
        T_DIV_EQUAL => true,
31
        T_DOUBLE_CAST => true,
32
        T_INC => true,
33
        T_INCLUDE => true,
34
        T_INCLUDE_ONCE => true,
35
        T_INSTANCEOF => true,
36
        T_INT_CAST => true,
37
        T_IS_EQUAL => true,
38
        T_IS_GREATER_OR_EQUAL => true,
39
        T_IS_IDENTICAL => true,
40
        T_IS_NOT_EQUAL => true,
41
        T_IS_NOT_IDENTICAL => true,
42
        T_IS_SMALLER_OR_EQUAL => true,
43
        T_LOGICAL_AND => true,
44
        T_LOGICAL_OR => true,
45
        T_LOGICAL_XOR => true,
46
        T_MINUS_EQUAL => true,
47
        T_MOD_EQUAL => true,
48
        T_MUL_EQUAL => true,
49
        T_NEW => true,
50
        T_OBJECT_CAST => true,
51
        T_OR_EQUAL => true,
52
        T_PLUS_EQUAL => true,
53
        T_REQUIRE => true,
54
        T_REQUIRE_ONCE => true,
55
        T_SL => true,
56
        T_SL_EQUAL => true,
57
        T_SR => true,
58
        T_SR_EQUAL => true,
59
        T_STRING_CAST => true,
60
        T_UNSET_CAST => true,
61
        T_XOR_EQUAL => true,
62
        '!' => true,
63
        '%' => true,
64
        '&' => true,
65
        '*' => true,
66
        '+' => true,
67
        '-' => true,
68
        '.' => true,
69
        '/' => true,
70
        ':' => true,
71
        '<' => true,
72
        '=' => true,
73
        '>' => true,
74
        '?' => true,
75
        '^' => true,
76
        '|' => true,
77
        '~' => true,
78
    );
79
80
    private static $strip = array(
81
        '(' => true,
82
        ')' => true,
83
        '[' => true,
84
        ']' => true,
85
        '{' => true,
86
        '}' => true,
87
        T_OBJECT_OPERATOR => true,
88
        T_DOUBLE_COLON => true,
89
    );
90
91
    public static function getFunctionCalls($source, $line, $function)
92
    {
93
        static $up = array(
94
            '(' => true,
95
            '[' => true,
96
            '{' => true,
97
            T_CURLY_OPEN => true,
98
            T_DOLLAR_OPEN_CURLY_BRACES => true,
99
        );
100
        static $down = array(
101
            ')' => true,
102
            ']' => true,
103
            '}' => true,
104
        );
105
        static $modifiers = array(
106
            '!' => true,
107
            '@' => true,
108
            '~' => true,
109
            '+' => true,
110
            '-' => true,
111
        );
112
113
        if (KINT_PHP53) {
114
            self::$strip[T_NS_SEPARATOR] = true;
115
        }
116
117
        if (KINT_PHP56) {
118
            self::$operator[T_POW] = true;
119
            self::$operator[T_POW_EQUAL] = true;
120
        }
121
122
        if (KINT_PHP70) {
123
            self::$operator[T_SPACESHIP] = true;
124
        }
125
126
        $tokens = token_get_all($source);
127
        $cursor = 1;
128
        $function_calls = array();
129
        $prev_tokens = array(null, null, null);
130
131
        if (is_array($function)) {
132
            $class = explode('\\', $function[0]);
133
            $class = strtolower(end($class));
134
            $function = strtolower($function[1]);
135
        } else {
136
            $class = null;
137
            $function = strtolower($function);
138
        }
139
140
        // Loop through tokens
141
        foreach ($tokens as $index => $token) {
142
            if (!is_array($token)) {
143
                continue;
144
            }
145
146
            // Count newlines for line number instead of using
147
            // $token[2] since it's not available until 5.2.2
148
            // Also note that certain situations (String tokens after whitespace)
149
            // may not have the correct line number unless you do this manually
150
            $cursor += substr_count($token[1], "\n");
151
            if ($cursor > $line) {
152
                break;
153
            }
154
155
            // Store the last real tokens for later
156
            if (isset(self::$ignore[$token[0]])) {
157
                continue;
158
            } else {
159
                $prev_tokens = array($prev_tokens[1], $prev_tokens[2], $token);
160
            }
161
162
            // Check if it's the right type to be the function we're looking for
163
            if ($token[0] !== T_STRING || strtolower($token[1]) !== $function) {
164
                continue;
165
            }
166
167
            // Check if it's a function call
168
            if ($tokens[self::realTokenIndex($tokens, $index, 1)] !== '(') {
169
                continue;
170
            }
171
172
            // Check if it matches the signature
173
            if ($class === null) {
174
                if ($prev_tokens[1] && in_array($prev_tokens[1][0], array(T_DOUBLE_COLON, T_OBJECT_OPERATOR))) {
175
                    continue;
176
                }
177
            } else {
178
                if (!$prev_tokens[1] || $prev_tokens[1][0] !== T_DOUBLE_COLON) {
179
                    continue;
180
                }
181
182
                if (!$prev_tokens[0] || $prev_tokens[0][0] !== T_STRING || strtolower($prev_tokens[0][1]) !== $class) {
183
                    continue;
184
                }
185
            }
186
187
            $inner_cursor = $cursor;
188
            $depth = 0; // The depth respective to the function call
189
            $offset = 1; // The offset from the function call
190
            $instring = false; // Whether we're in a string or not
191
            $realtokens = false; // Whether the string contains anything meaningful or not
192
            $params = array(); // All our collected parameters
193
            $shortparam = array(); // The short version of the parameter
194
            $param_start = 1; // The distance to the start of the parameter
195
196
            // Loop through the following tokens until the function call ends
197
            while (isset($tokens[$index + $offset])) {
198
                $token = $tokens[$index + $offset];
199
200
                // Ensure that the $inner_cursor is correct and
201
                // that $token is either a T_ constant or a string
202
                if (is_array($token)) {
203
                    $inner_cursor += substr_count($token[1], "\n");
204
                }
205
206
                if (!isset(self::$ignore[$token[0]]) && !isset($down[$token[0]])) {
207
                    $realtokens = true;
208
                }
209
210
                // If it's a token that makes us to up a level, increase the depth
211
                if (isset($up[$token[0]])) {
212
                    // If this is the first paren set the start of the param to just after it
213
                    if ($depth === 0) {
214
                        $param_start = $offset + 1;
215
                    } elseif ($depth === 1) {
216
                        $shortparam[] = $token;
217
                        $realtokens = false;
218
                    }
219
220
                    ++$depth;
221
                } elseif (isset($down[$token[0]])) {
222
                    --$depth;
223
224
                    // If this brings us down to the parameter level, and we've had
225
                    // real tokens since going up, fill the $shortparam with an ellipsis
226
                    if ($depth === 1) {
227
                        if ($realtokens) {
228
                            $shortparam[] = '...';
229
                        }
230
                        $shortparam[] = $token;
231
                    }
232
                } elseif ($token[0] === '"') {
233
                    // Strings use the same symbol for up and down, but we can
234
                    // only ever be inside one string, so just use a bool for that
235
                    if ($instring) {
236
                        --$depth;
237
                        if ($depth === 1) {
238
                            $shortparam[] = '...';
239
                        }
240
                    } else {
241
                        ++$depth;
242
                    }
243
244
                    $instring = !$instring;
245
246
                    $shortparam[] = '"';
247
                } elseif ($depth === 1) {
248
                    if ($token[0] === ',') {
249
                        $params[] = array(
250
                            'full' => array_slice($tokens, $index + $param_start, $offset - $param_start),
251
                            'short' => $shortparam,
252
                        );
253
                        $shortparam = array();
254
                        $param_start = $offset + 1;
255
                    } elseif ($token[0] === T_CONSTANT_ENCAPSED_STRING && strlen($token[1]) > 2) {
256
                        $shortparam[] = $token[1][0].'...'.$token[1][0];
257
                    } else {
258
                        $shortparam[] = $token;
259
                    }
260
                }
261
262
                // Depth has dropped to 0 (So we've hit the closing paren)
263
                if ($depth <= 0) {
264
                    $params[] = array(
265
                        'full' => array_slice($tokens, $index + $param_start, $offset - $param_start),
266
                        'short' => $shortparam,
267
                    );
268
269
                    break;
270
                }
271
272
                ++$offset;
273
            }
274
275
            // If we're not passed (or at) the line at the end
276
            // of the function call, we're too early so skip it
277
            if ($inner_cursor < $line) {
278
                continue;
279
            }
280
281
            // Format the final output parameters
282
            foreach ($params as &$param) {
283
                $name = self::tokensFormatted($param['short']);
284
                $expression = false;
285
                foreach ($name as $token) {
286
                    if (self::tokenIsOperator($token)) {
287
                        $expression = true;
288
                        break;
289
                    }
290
                }
291
292
                $param = array(
293
                    'name' => self::tokensToString($name),
294
                    'path' => self::tokensToString(self::tokensTrim($param['full'])),
295
                    'expression' => $expression,
296
                );
297
            }
298
299
            // Get the modifiers
300
            $mods = array();
301
            --$index;
302
303
            while (isset($tokens[$index])) {
304
                if (isset(self::$ignore[$tokens[$index][0]])) {
305
                    --$index;
306
                    continue;
307
                } elseif (is_array($tokens[$index]) && empty($mods)) {
308
                    if ($tokens[$index][0] === T_DOUBLE_COLON || $tokens[$index][0] === T_STRING || (KINT_PHP53 && $tokens[$index][0] === T_NS_SEPARATOR)) {
309
                        --$index;
310
                        continue;
311
                    } else {
312
                        break;
313
                    }
314
                } elseif (isset($modifiers[$tokens[$index][0]])) {
315
                    $mods[] = $tokens[$index];
316
                    --$index;
317
                    continue;
318
                } else {
319
                    break;
320
                }
321
            }
322
323
            $function_calls[] = array(
324
                'parameters' => $params,
325
                'modifiers' => $mods,
326
            );
327
        }
328
329
        return $function_calls;
330
    }
331
332
    private static function realTokenIndex(array $tokens, $index, $direction)
0 ignored issues
show
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
333
    {
334
        $index += $direction;
335
336
        while (isset($tokens[$index])) {
337
            if (!isset(self::$ignore[$tokens[$index][0]])) {
338
                return $index;
339
            }
340
341
            $index += $direction;
342
        }
343
344
        return null;
345
    }
346
347
    /**
348
     * We need a separate method to check if tokens are operators because we
349
     * occasionally add "..." to short parameter versions. If we simply check
350
     * for `$token[0]` then "..." will incorrectly match the "." operator.
351
     *
352
     * @param array|string $token The token to check
353
     *
354
     * @return bool
355
     */
356
    private static function tokenIsOperator($token)
357
    {
358
        return $token !== '...' && isset(self::$operator[$token[0]]);
359
    }
360
361
    private static function tokensToString(array $tokens)
362
    {
363
        $out = '';
364
365
        foreach ($tokens as $token) {
366
            if (is_string($token)) {
367
                $out .= $token;
368
            } elseif (is_array($token)) {
369
                $out .= $token[1];
370
            }
371
        }
372
373
        return $out;
374
    }
375
376
    private static function tokensTrim(array $tokens)
377
    {
378 View Code Duplication
        foreach ($tokens as $index => $token) {
379
            if (isset(self::$ignore[$token[0]])) {
380
                unset($tokens[$index]);
381
            } else {
382
                break;
383
            }
384
        }
385
386
        $tokens = array_reverse($tokens);
387
388 View Code Duplication
        foreach ($tokens as $index => $token) {
389
            if (isset(self::$ignore[$token[0]])) {
390
                unset($tokens[$index]);
391
            } else {
392
                break;
393
            }
394
        }
395
396
        return array_reverse($tokens);
397
    }
398
399
    private static function tokensFormatted(array $tokens)
400
    {
401
        $space = false;
402
403
        $tokens = self::tokensTrim($tokens);
404
405
        $output = array();
406
        $last = null;
407
408
        foreach ($tokens as $index => $token) {
409
            if (isset(self::$ignore[$token[0]])) {
410
                if ($space) {
411
                    continue;
412
                }
413
414
                $next = $tokens[self::realTokenIndex($tokens, $index, 1)];
415
416
                if (isset(self::$strip[$last[0]]) && !self::tokenIsOperator($next)) {
417
                    continue;
418
                } elseif (isset(self::$strip[$next[0]]) && $last && !self::tokenIsOperator($last)) {
419
                    continue;
420
                }
421
422
                $token = ' ';
423
                $space = true;
424
            } else {
425
                $space = false;
426
                $last = $token;
427
            }
428
429
            $output[] = $token;
430
        }
431
432
        return $output;
433
    }
434
}
435