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 |
||
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
|
|||
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 |
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.