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 | /** |
||
4 | * SQL Parser from: http://code.google.com/p/php-sql-parser/ |
||
5 | * License: New BSD |
||
6 | */ |
||
7 | class PHPSQLParser |
||
8 | { |
||
9 | var $reserved = array(); |
||
10 | var $functions = array(); |
||
11 | function __construct($sql = false) { |
||
12 | #LOAD THE LIST OF RESERVED WORDS |
||
13 | $this->load_reserved_words(); |
||
14 | if($sql) $this->parse($sql); |
||
15 | } |
||
16 | |||
17 | function parse($sql) { |
||
18 | $sql = trim($sql); |
||
19 | |||
20 | #lex the SQL statement |
||
21 | $in = $this->split_sql($sql); |
||
22 | |||
23 | #sometimes the parser needs to skip ahead until a particular |
||
24 | #token is found |
||
25 | $skip_until = false; |
||
26 | |||
27 | #this is the output tree which is being parsed |
||
28 | $out = array(); |
||
29 | |||
30 | #This is the last type of union used (UNION or UNION ALL) |
||
31 | #indicates a) presence of at least one union in this query |
||
32 | # b) the type of union if this is the first or last query |
||
33 | $union = false; |
||
34 | |||
35 | #Sometimes a "query" consists of more than one query (like a UNION query) |
||
36 | #this array holds all the queries |
||
37 | $queries=array(); |
||
38 | |||
39 | #This is the highest level lexical analysis. This is the part of the |
||
40 | #code which finds UNION and UNION ALL query parts |
||
41 | foreach($in as $key => $token) { |
||
0 ignored issues
–
show
|
|||
42 | $token=trim($token); |
||
43 | |||
44 | if($skip_until) { |
||
45 | if($token) { |
||
46 | if(strtoupper($token) == $skip_until) { |
||
47 | $skip_until = false; |
||
48 | continue; |
||
49 | } |
||
50 | } else { |
||
51 | continue; |
||
52 | } |
||
53 | } |
||
54 | |||
55 | if(strtoupper($token) == "UNION") { |
||
56 | $union = 'UNION'; |
||
57 | for($i=$key+1;$i<count($in);++$i) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
58 | if(trim($in[$i]) == '') continue; |
||
59 | if(strtoupper($in[$i]) == 'ALL') { |
||
60 | $skip_until = 'ALL'; |
||
61 | $union = 'UNION ALL'; |
||
62 | continue ; |
||
63 | } else { |
||
64 | break; |
||
65 | } |
||
66 | } |
||
67 | |||
68 | $queries[$union][] = $out; |
||
69 | $out = array(); |
||
70 | |||
71 | } else { |
||
72 | $out[]=$token; |
||
73 | } |
||
74 | |||
75 | } |
||
76 | |||
77 | if(!empty($out)) { |
||
78 | if ($union) { |
||
79 | $queries[$union][] = $out; |
||
80 | } else { |
||
81 | $queries[] = $out; |
||
82 | } |
||
83 | } |
||
84 | |||
85 | |||
86 | /*MySQL supports a special form of UNION: |
||
87 | (select ...) |
||
88 | union |
||
89 | (select ...) |
||
90 | |||
91 | This block handles this query syntax. Only one such subquery |
||
92 | is supported in each UNION block. (select)(select)union(select) is not legal. |
||
93 | The extra queries will be silently ignored. |
||
94 | */ |
||
95 | $union_types = array('UNION','UNION ALL'); |
||
96 | foreach($union_types as $union_type) { |
||
97 | if(!empty($queries[$union_type])) { |
||
98 | foreach($queries[$union_type] as $i => $tok_list) { |
||
99 | foreach($tok_list as $z => $tok) { |
||
100 | $tok = trim($tok); |
||
101 | if(!$tok) continue; |
||
102 | if(preg_match('/^\\(\\s*select\\s*/i', $tok)) { |
||
103 | $queries[$union_type][$i] = $this->parse(substr($tok,1,-1)); |
||
104 | break; |
||
105 | } else { |
||
106 | $queries[$union_type][$i] = $this->process_sql($queries[$union_type][$i]); |
||
107 | break; |
||
108 | } |
||
109 | } |
||
110 | } |
||
111 | } |
||
112 | } |
||
113 | |||
114 | |||
115 | /* If there was no UNION or UNION ALL in the query, then the query is |
||
116 | stored at $queries[0]. |
||
117 | */ |
||
118 | if(!empty($queries[0])) { |
||
119 | $queries[0] = $this->process_sql($queries[0]); |
||
120 | |||
121 | } |
||
122 | |||
123 | if(count($queries) == 1 && !$union) { |
||
124 | $queries = $queries[0]; |
||
125 | } |
||
126 | |||
127 | $this->parsed = $queries; |
||
128 | return $this->parsed; |
||
129 | } |
||
130 | |||
131 | #This function counts open and close parenthesis and |
||
132 | #returns their location. This might be faster as a regex |
||
133 | private function count_paren($token,$chars=array('(',')')) { |
||
134 | $len = strlen($token); |
||
135 | $open=array(); |
||
136 | $close=array(); |
||
137 | for($i=0;$i<$len;++$i){ |
||
138 | if($token[$i] == $chars[0]) { |
||
139 | $open[] = $i; |
||
140 | } elseif($token[$i] == $chars[1]) { |
||
141 | $close[] = $i; |
||
142 | } |
||
143 | |||
144 | } |
||
145 | return array('open' => $open, 'close' => $close, 'balanced' =>( count($close) - count($open))); |
||
146 | } |
||
147 | |||
148 | #This function counts open and close parenthesis and |
||
149 | #returns their location. This might be faster as a regex |
||
150 | private function count_backtick($token) { |
||
151 | $len = strlen($token); |
||
152 | $cnt=0; |
||
153 | for($i=0;$i<$len;++$i){ |
||
154 | if($token[$i] == '`') ++$cnt; |
||
155 | } |
||
156 | return $cnt; |
||
157 | } |
||
158 | |||
159 | #This is the lexer |
||
160 | #this function splits up a SQL statement into easy to "parse" |
||
161 | #tokens for the SQL processor |
||
162 | private function split_sql($sql) { |
||
163 | |||
164 | if(!is_string($sql)) { |
||
165 | return false; |
||
166 | } |
||
167 | |||
168 | $sql = str_replace(array('\\\'','\\"',"\r\n","\n","()"),array("''",'""'," "," "," "), $sql); |
||
169 | $regex=<<<EOREGEX |
||
170 | /(`(?:[^`]|``)`|[@A-Za-z0-9_.`-]+(?:\(\s*\)){0,1}) |
||
171 | |(\+|-|\*|\/|!=|>=|<=|<>|>|<|&&|\|\||=|\^) |
||
172 | |(\(.*?\)) # Match FUNCTION(...) OR BAREWORDS |
||
173 | |('(?:[^']|'')*'+) |
||
174 | |("(?:[^"]|"")*"+) |
||
175 | |([^ ,]+) |
||
176 | /ix |
||
177 | EOREGEX |
||
178 | ; |
||
179 | |||
180 | $tokens = preg_split($regex, $sql,-1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); |
||
181 | $token_count = count($tokens); |
||
182 | |||
183 | /* The above regex has one problem, because the parenthetical match is not greedy. |
||
184 | Thus, when matching grouped expressions such as ( (a and b) or c) the |
||
185 | tokenizer will produce "( (a and b)", " ", "or", " " , "c,")" |
||
186 | |||
187 | This block detects the number of open/close parentheses in the given token. If the parentheses are balanced |
||
188 | (balanced == 0) then we don't need to do anything. |
||
189 | |||
190 | otherwise, we need to balance the expression. |
||
191 | */ |
||
192 | $reset = false; |
||
193 | for($i=0;$i<$token_count;++$i) { |
||
194 | |||
195 | if(empty($tokens[$i])) continue; |
||
196 | |||
197 | $token = $tokens[$i]; |
||
198 | $trim = trim($token); |
||
199 | if($trim) { |
||
200 | if($trim[0] != '(' |
||
201 | && substr($trim,-1) == ')') { |
||
202 | $trim=trim(substr($trim,0, |
||
203 | strpos($trim,'('))); |
||
204 | } |
||
205 | $tokens[$i]=$trim; |
||
206 | $token=$trim; |
||
207 | } |
||
208 | |||
209 | if($token && $token[0] == '(') { |
||
210 | $info = $this->count_paren($token); |
||
211 | if($info['balanced'] == 0) { |
||
212 | continue; |
||
213 | } |
||
214 | |||
215 | // We need to find this many closing parentheses. |
||
216 | $needed = abs($info['balanced']); |
||
217 | $n = $i; |
||
218 | while($needed > 0 && $n <$token_count-1) { |
||
219 | ++$n; |
||
220 | #echo "LOOKING FORWARD TO $n [ " . $tokens[$n] . "]\n"; |
||
221 | $token2 = $tokens[$n]; |
||
222 | $info2 = $this->count_paren($token2); |
||
223 | $closes = count($info2['close']); |
||
224 | if($closes != $needed) { |
||
225 | $tokens[$i] .= $tokens[$n]; |
||
226 | unset($tokens[$n]); |
||
227 | $reset = true; |
||
228 | $info2 = $this->count_paren($tokens[$i]); |
||
229 | $needed = abs($info2['balanced']); |
||
230 | # echo "CLOSES LESS THAN NEEDED (still need $needed)\n"; |
||
231 | } else { |
||
232 | /*get the string pos of the last close parenthesis we need*/ |
||
233 | $pos = $info2['close'][count($info2['close'])-1]; |
||
234 | $str1 = $str2 = ""; |
||
235 | if($pos == 0) { |
||
236 | $str1 = ')'; |
||
237 | } else { |
||
238 | $str1 = substr($tokens[$n],0,$pos) . ')'; |
||
239 | $str2 = substr($tokens[$n],$pos+1); |
||
240 | } |
||
241 | #echo "CLOSES FOUND AT $n, offset:$pos [$str1] [$str2]\n"; |
||
242 | if(strlen($str2) > 0) { |
||
243 | $tokens[$n] = $str2; |
||
244 | } else { |
||
245 | unset($tokens[$n]); |
||
246 | $reset = true; |
||
247 | } |
||
248 | $tokens[$i] .= $str1; |
||
249 | $info2 = $this->count_paren($tokens[$i]); |
||
250 | $needed = abs($info2['balanced']); |
||
251 | |||
252 | } |
||
253 | } |
||
254 | } |
||
255 | } |
||
256 | |||
257 | #the same problem appears with backticks :( |
||
258 | |||
259 | /* reset the array if we deleted any tokens above */ |
||
260 | if ($reset) $tokens = array_values($tokens); |
||
261 | |||
262 | $token_count=count($tokens); |
||
263 | for($i=0;$i<$token_count;++$i) { |
||
264 | if(empty($tokens[$i])) continue; |
||
265 | $token=$tokens[$i]; |
||
266 | $needed=true; |
||
267 | $reset=false; |
||
268 | if($needed && $token && strpos($token,'`') !== false) { |
||
269 | $info = $this->count_backtick($token); |
||
270 | if($info %2 == 0) { #even number of backticks means we are balanced |
||
271 | continue; |
||
272 | } |
||
273 | $needed=1; |
||
274 | |||
275 | $n = $i; |
||
276 | while($needed && $n <$token_count-1) { |
||
277 | $reset=true; |
||
278 | #echo "BACKTICK COUNT[$i]: $info old: {$tokens[$i]}, new: ($token)\n"; |
||
279 | ++$n; |
||
280 | $token .= $tokens[$n]; |
||
281 | unset($tokens[$n]); |
||
282 | $needed = $this->count_backtick($token) % 2; |
||
283 | } |
||
284 | } |
||
285 | if($reset) $tokens[$i] = $token; |
||
286 | |||
287 | } |
||
288 | /* reset the array if we deleted any tokens above */ |
||
289 | $tokens = array_values($tokens); |
||
290 | |||
291 | return $tokens; |
||
292 | |||
293 | } |
||
294 | |||
295 | /* This function breaks up the SQL statement into logical sections. |
||
296 | Some sections are then further handled by specialized functions. |
||
297 | */ |
||
298 | private function process_sql(&$tokens,$start_at = 0, $stop_at = false) { |
||
299 | $prev_category = ""; |
||
300 | $start = microtime(true); |
||
301 | $token_category = ""; |
||
302 | |||
303 | $skip_next=false; |
||
304 | $token_count = count($tokens); |
||
305 | |||
306 | if(!$stop_at) { |
||
307 | $stop_at = $token_count; |
||
308 | } |
||
309 | |||
310 | $out = false; |
||
311 | |||
312 | for($token_number = $start_at;$token_number<$stop_at;++$token_number) { |
||
313 | $token = trim($tokens[$token_number]); |
||
314 | if($token && $token[0] == '(' && $token_category == "") { |
||
315 | $token_category = 'SELECT'; |
||
316 | } |
||
317 | |||
318 | /* If it isn't obvious, when $skip_next is set, then we ignore the next real |
||
319 | token, that is we ignore whitespace. |
||
320 | */ |
||
321 | if($skip_next) { |
||
322 | #whitespace does not count as a next token |
||
323 | if($token == "") { |
||
324 | continue; |
||
325 | } |
||
326 | |||
327 | #to skip the token we replace it with whitespace |
||
328 | $new_token = ""; |
||
329 | $skip_next = false; |
||
330 | } |
||
331 | |||
332 | $upper = strtoupper($token); |
||
333 | switch($upper) { |
||
334 | |||
335 | /* Tokens that get their own sections. These keywords have subclauses. */ |
||
336 | case 'SELECT': |
||
337 | case 'ORDER': |
||
338 | case 'LIMIT': |
||
339 | case 'SET': |
||
340 | case 'DUPLICATE': |
||
341 | case 'VALUES': |
||
342 | case 'GROUP': |
||
343 | case 'ORDER': |
||
344 | case 'HAVING': |
||
345 | case 'INTO': |
||
346 | case 'WHERE': |
||
347 | case 'RENAME': |
||
348 | case 'CALL': |
||
349 | case 'PROCEDURE': |
||
350 | case 'FUNCTION': |
||
351 | case 'DATABASE': |
||
352 | case 'SERVER': |
||
353 | case 'LOGFILE': |
||
354 | case 'DEFINER': |
||
355 | case 'RETURNS': |
||
356 | case 'EVENT': |
||
357 | case 'TABLESPACE': |
||
358 | case 'VIEW': |
||
359 | case 'TRIGGER': |
||
360 | case 'DATA': |
||
361 | case 'DO': |
||
362 | case 'PASSWORD': |
||
363 | case 'USER': |
||
364 | case 'PLUGIN': |
||
365 | case 'FROM': |
||
366 | case 'FLUSH': |
||
367 | case 'KILL': |
||
368 | case 'RESET': |
||
369 | case 'START': |
||
370 | case 'STOP': |
||
371 | case 'PURGE': |
||
372 | case 'EXECUTE': |
||
373 | case 'PREPARE': |
||
374 | case 'DEALLOCATE': |
||
375 | if($token == 'DEALLOCATE') { |
||
376 | $skip_next = true; |
||
377 | } |
||
378 | /* this FROM is different from FROM in other DML (not join related) */ |
||
379 | if($token_category == 'PREPARE' && $upper == 'FROM') { |
||
380 | continue 2; |
||
381 | } |
||
382 | |||
383 | $token_category = $upper; |
||
384 | #$join_type = 'JOIN'; |
||
385 | if($upper == 'FROM' && $token_category == 'FROM') { |
||
0 ignored issues
–
show
This
if statement is empty and can be removed.
This check looks for the bodies of These if (rand(1, 6) > 3) {
//print "Check failed";
} else {
print "Check succeeded";
}
could be turned into if (rand(1, 6) <= 3) {
print "Check succeeded";
}
This is much more concise to read. ![]() |
|||
386 | /* DO NOTHING*/ |
||
387 | } else { |
||
388 | continue 2; |
||
389 | |||
390 | } |
||
391 | break; |
||
392 | |||
393 | /* These tokens get their own section, but have no subclauses. |
||
394 | These tokens identify the statement but have no specific subclauses of their own. */ |
||
395 | case 'DELETE': |
||
396 | case 'ALTER': |
||
397 | case 'INSERT': |
||
398 | case 'REPLACE': |
||
399 | case 'TRUNCATE': |
||
400 | case 'CREATE': |
||
401 | case 'TRUNCATE': |
||
402 | case 'OPTIMIZE': |
||
403 | case 'GRANT': |
||
404 | case 'REVOKE': |
||
405 | case 'SHOW': |
||
406 | case 'HANDLER': |
||
407 | case 'LOAD': |
||
408 | case 'ROLLBACK': |
||
409 | case 'SAVEPOINT': |
||
410 | case 'UNLOCK': |
||
411 | case 'INSTALL': |
||
412 | case 'UNINSTALL': |
||
413 | case 'ANALZYE': |
||
414 | case 'BACKUP': |
||
415 | case 'CHECK': |
||
416 | case 'CHECKSUM': |
||
417 | case 'REPAIR': |
||
418 | case 'RESTORE': |
||
419 | case 'CACHE': |
||
420 | case 'DESCRIBE': |
||
421 | case 'EXPLAIN': |
||
422 | case 'USE': |
||
423 | case 'HELP': |
||
424 | $token_category = $upper; /* set the category in case these get subclauses |
||
425 | in a future version of MySQL */ |
||
426 | $out[$upper][0] = $upper; |
||
427 | continue 2; |
||
428 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
429 | |||
430 | /* This is either LOCK TABLES or SELECT ... LOCK IN SHARE MODE*/ |
||
431 | case 'LOCK': |
||
432 | if($token_category == "") { |
||
433 | $token_category = $upper; |
||
434 | $out[$upper][0] = $upper; |
||
435 | } else { |
||
436 | $token = 'LOCK IN SHARE MODE'; |
||
437 | $skip_next=true; |
||
438 | $out['OPTIONS'][] = $token; |
||
439 | } |
||
440 | continue 2; |
||
441 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
442 | |||
443 | case 'USING': |
||
444 | /* USING in FROM clause is different from USING w/ prepared statement*/ |
||
445 | if($token_category == 'EXECUTE') { |
||
446 | $token_category=$upper; |
||
447 | continue 2; |
||
448 | } |
||
449 | if($token_category == 'FROM' && !empty($out['DELETE'])) { |
||
450 | $token_category=$upper; |
||
451 | continue 2; |
||
452 | } |
||
453 | break; |
||
454 | |||
455 | /* DROP TABLE is different from ALTER TABLE DROP ... */ |
||
456 | case 'DROP': |
||
457 | if($token_category != 'ALTER') { |
||
458 | $token_category = $upper; |
||
459 | $out[$upper][0] = $upper; |
||
460 | continue 2; |
||
461 | } |
||
462 | break; |
||
463 | |||
464 | case 'FOR': |
||
465 | $skip_next=true; |
||
466 | $out['OPTIONS'][] = 'FOR UPDATE'; |
||
467 | continue 2; |
||
468 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
469 | |||
470 | |||
471 | case 'UPDATE': |
||
472 | if($token_category == "" ) { |
||
473 | $token_category = $upper; |
||
474 | continue 2; |
||
475 | |||
476 | } |
||
477 | if($token_category == 'DUPLICATE') { |
||
478 | continue 2; |
||
479 | } |
||
480 | break; |
||
481 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
482 | |||
483 | case 'START': |
||
484 | $token = "BEGIN"; |
||
485 | $out[$upper][0] = $upper; |
||
486 | $skip_next = true; |
||
487 | break; |
||
488 | |||
489 | /* These tokens are ignored. */ |
||
490 | case 'BY': |
||
491 | case 'ALL': |
||
492 | case 'SHARE': |
||
493 | case 'MODE': |
||
494 | case 'TO': |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
495 | |||
496 | case ';': |
||
497 | continue 2; |
||
498 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
499 | |||
500 | case 'KEY': |
||
501 | if($token_category == 'DUPLICATE') { |
||
502 | continue 2; |
||
503 | } |
||
504 | break; |
||
505 | |||
506 | /* These tokens set particular options for the statement. They never stand alone.*/ |
||
507 | case 'DISTINCTROW': |
||
0 ignored issues
–
show
|
|||
508 | $token='DISTINCT'; |
||
509 | case 'DISTINCT': |
||
510 | case 'HIGH_PRIORITY': |
||
511 | case 'LOW_PRIORITY': |
||
512 | case 'DELAYED': |
||
513 | case 'IGNORE': |
||
514 | case 'FORCE': |
||
515 | case 'STRAIGHT_JOIN': |
||
516 | case 'SQL_SMALL_RESULT': |
||
517 | case 'SQL_BIG_RESULT': |
||
518 | case 'QUICK': |
||
519 | case 'SQL_BUFFER_RESULT': |
||
520 | case 'SQL_CACHE': |
||
521 | case 'SQL_NO_CACHE': |
||
522 | case 'SQL_CALC_FOUND_ROWS': |
||
523 | $out['OPTIONS'][] = $upper; |
||
524 | continue 2; |
||
525 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
526 | |||
527 | case 'WITH': |
||
528 | if($token_category == 'GROUP') { |
||
529 | $skip_next=true; |
||
530 | $out['OPTIONS'][] = 'WITH ROLLUP'; |
||
531 | continue 2; |
||
532 | } |
||
533 | break; |
||
534 | |||
535 | |||
536 | case 'AS': |
||
537 | break; |
||
538 | |||
539 | case '': |
||
540 | case ',': |
||
541 | case ';': |
||
542 | break; |
||
543 | |||
544 | default: |
||
545 | break; |
||
546 | } |
||
547 | |||
548 | if($prev_category == $token_category) { |
||
549 | $out[$token_category][] = $token; |
||
550 | } |
||
551 | |||
552 | $prev_category = $token_category; |
||
553 | } |
||
554 | |||
555 | if(!$out) return false; |
||
556 | |||
557 | |||
558 | #process the SELECT clause |
||
559 | if(!empty($out['SELECT'])) $out['SELECT'] = $this->process_select($out['SELECT']); |
||
560 | |||
561 | if(!empty($out['FROM'])) $out['FROM'] = $this->process_from($out['FROM']); |
||
562 | if(!empty($out['USING'])) $out['USING'] = $this->process_from($out['USING']); |
||
563 | if(!empty($out['UPDATE'])) $out['UPDATE'] = $this->process_from($out['UPDATE']); |
||
564 | |||
565 | if(!empty($out['GROUP'])) $out['GROUP'] = $this->process_group($out['GROUP'], $out['SELECT']); |
||
566 | if(!empty($out['ORDER'])) $out['ORDER'] = $this->process_group($out['ORDER'], $out['SELECT']); |
||
567 | |||
568 | if(!empty($out['LIMIT'])) $out['LIMIT'] = $this->process_limit($out['LIMIT']); |
||
569 | |||
570 | if(!empty($out['WHERE'])) $out['WHERE'] = $this->process_expr_list($out['WHERE']); |
||
571 | if(!empty($out['HAVING'])) $out['HAVING'] = $this->process_expr_list($out['HAVING']); |
||
572 | if(!empty($out['SET'])) $out['SET'] = $this->process_set_list($out['SET']); |
||
573 | if(!empty($out['DUPLICATE'])) { |
||
574 | $out['ON DUPLICATE KEY UPDATE'] = $this->process_set_list($out['DUPLICATE']); |
||
575 | unset($out['DUPLICATE']); |
||
576 | } |
||
577 | if(!empty($out['INSERT'])) $out = $this->process_insert($out); |
||
578 | if(!empty($out['REPLACE'])) $out = $this->process_insert($out,'REPLACE'); |
||
579 | if(!empty($out['DELETE'])) $out = $this->process_delete($out); |
||
580 | |||
581 | return $out; |
||
582 | |||
583 | } |
||
584 | |||
585 | /* A SET list is simply a list of key = value expressions separated by comma (,). |
||
586 | This function produces a list of the key/value expressions. |
||
587 | */ |
||
588 | private function process_set_list($tokens) { |
||
589 | $column=""; |
||
590 | $expression=""; |
||
591 | foreach($tokens as $token) { |
||
592 | $token=trim($token); |
||
593 | if(!$column) { |
||
594 | if($token === false || empty($token)) continue; |
||
595 | $column .= $token; |
||
596 | continue; |
||
597 | } |
||
598 | |||
599 | if($token == '=') continue; |
||
600 | |||
601 | if($token == ',') { |
||
602 | $expr[] = array('column' => trim($column), 'expr' => trim($expression)); |
||
603 | $expression = $column = ""; |
||
604 | continue; |
||
605 | } |
||
606 | |||
607 | $expression .= $token; |
||
608 | } |
||
609 | if($expression) { |
||
610 | $expr[] = array('column' => trim($column), 'expr' => trim($expression)); |
||
611 | } |
||
612 | |||
613 | return $expr; |
||
614 | } |
||
615 | |||
616 | /* This function processes the LIMIT section. |
||
617 | start,end are set. If only end is provided in the query |
||
618 | then start is set to 0. |
||
619 | */ |
||
620 | private function process_limit($tokens) { |
||
621 | $start = 0; |
||
622 | $end = 0; |
||
623 | |||
624 | if($pos = array_search(',',$tokens)) { |
||
625 | for($i=0;$i<$pos;++$i) { |
||
626 | if($tokens[$i] != '') { |
||
627 | $start = $tokens[$i]; |
||
628 | break; |
||
629 | } |
||
630 | } |
||
631 | $pos = $pos + 1; |
||
632 | |||
633 | } else { |
||
634 | $pos = 0; |
||
635 | } |
||
636 | |||
637 | for($i=$pos;$i<count($tokens);++$i) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
638 | if($tokens[$i] != '') { |
||
639 | $end = $tokens[$i]; |
||
640 | break; |
||
641 | } |
||
642 | } |
||
643 | |||
644 | return array('start' => $start, 'end' => $end); |
||
645 | } |
||
646 | |||
647 | /* This function processes the SELECT section. It splits the clauses at the commas. |
||
648 | Each clause is then processed by process_select_expr() and the results are added to |
||
649 | the expression list. |
||
650 | |||
651 | Finally, at the end, the expression list is returned. |
||
652 | */ |
||
653 | private function process_select(&$tokens) { |
||
654 | $expression = ""; |
||
655 | $expr = array(); |
||
656 | foreach($tokens as $token) { |
||
657 | if($token == ',') { |
||
658 | $expr[] = $this->process_select_expr(trim($expression)); |
||
659 | $expression = ""; |
||
660 | } else { |
||
661 | if($token === "" || $token===false) $token=" "; |
||
662 | $expression .= $token ; |
||
663 | } |
||
664 | } |
||
665 | $expression = trim($expression); |
||
666 | if($expression) $expr[] = $this->process_select_expr($expression); |
||
667 | return $expr; |
||
668 | } |
||
669 | |||
670 | /* This function processes each SELECT clause. We determine what (if any) alias |
||
671 | is provided, and we set the type of expression. |
||
672 | */ |
||
673 | private function process_select_expr($expression) { |
||
674 | |||
675 | if (empty($expression)){ |
||
676 | return ''; |
||
677 | } |
||
678 | |||
679 | $capture = false; |
||
680 | $alias = ""; |
||
681 | $base_expression = $expression; |
||
682 | $upper = trim(strtoupper($expression)); |
||
683 | #if necessary, unpack the expression |
||
684 | if($upper[0] == '(') { |
||
685 | #$expression = substr($expression,1,-1); |
||
686 | $base_expression = $expression; |
||
687 | } |
||
688 | |||
689 | $tokens = $this->split_sql($expression); |
||
690 | $token_count = count($tokens); |
||
691 | |||
692 | /* Determine if there is an explicit alias after the AS clause. |
||
693 | If AS is found, then the next non-whitespace token is captured as the alias. |
||
694 | The tokens after (and including) the AS are removed. |
||
695 | */ |
||
696 | $base_expr = ""; |
||
697 | $stripped=array(); |
||
698 | $capture=false; |
||
699 | $alias = ""; |
||
700 | $processed=false; |
||
701 | for($i=0;$i<$token_count;++$i) { |
||
702 | $token = strtoupper($tokens[$i]); |
||
703 | if(trim($token)) { |
||
704 | $stripped[] = $tokens[$i]; |
||
705 | } |
||
706 | |||
707 | if($token == 'AS') { |
||
708 | unset($tokens[$i]); |
||
709 | $capture = true; |
||
710 | continue; |
||
711 | } |
||
712 | |||
713 | if($capture) { |
||
714 | if(trim($token)) { |
||
715 | $alias .= $tokens[$i]; |
||
716 | } |
||
717 | unset($tokens[$i]); |
||
718 | continue; |
||
719 | } |
||
720 | $base_expr .= $tokens[$i]; |
||
721 | } |
||
722 | |||
723 | $stripped = $this->process_expr_list($stripped); |
||
724 | $last = array_pop($stripped); |
||
725 | if(!$alias && $last['expr_type'] == 'colref') { |
||
726 | $prev = array_pop($stripped); |
||
727 | if($prev['expr_type'] == 'operator' || |
||
728 | $prev['expr_type'] == 'const' || |
||
729 | $prev['expr_type'] == 'function' || |
||
730 | $prev['expr_type'] == 'expression' || |
||
731 | #$prev['expr_type'] == 'aggregate_function' || |
||
732 | $prev['expr_type'] == 'subquery' || |
||
733 | $prev['expr_type'] == 'colref') { |
||
734 | $alias = $last['base_expr']; |
||
735 | |||
736 | #remove the last token |
||
737 | array_pop($tokens); |
||
738 | |||
739 | $base_expr = join("", $tokens); |
||
740 | |||
741 | |||
742 | } |
||
743 | } |
||
744 | |||
745 | if(!$alias) { |
||
746 | $base_expr=join("", $tokens); |
||
747 | $alias = $base_expr; |
||
748 | } |
||
749 | |||
750 | /* Properly escape the alias if it is not escaped */ |
||
751 | if ($alias[0] != '`') { |
||
752 | $alias = '`' . str_replace('`','``',$alias) . '`'; |
||
753 | } |
||
754 | $processed = false; |
||
755 | $type='expression'; |
||
756 | |||
757 | if(substr(trim($base_expr),0,1) == '(') { |
||
758 | $base_expr = substr($expression,1,-1); |
||
759 | if(preg_match('/^sel/i', $base_expr)) { |
||
760 | $type='subquery'; |
||
761 | $processed = $this->parse($base_expr); |
||
762 | } |
||
763 | } |
||
764 | if(!$processed) { |
||
765 | $processed = $this->process_expr_list($tokens); |
||
766 | } |
||
767 | |||
768 | if(count($processed) == 1) { |
||
769 | $type = $processed[0]['expr_type']; |
||
770 | $processed = false; |
||
771 | } |
||
772 | |||
773 | return array('expr_type'=>$type,'alias' => $alias, 'base_expr' => $base_expr, 'sub_tree' => $processed); |
||
774 | |||
775 | } |
||
776 | |||
777 | private function trimSubquery($sq) |
||
778 | { |
||
779 | $sq = trim($sq); |
||
780 | if(empty($sq)) return ''; |
||
781 | while($sq[0] == '(' && substr($sq, -1) == ')') { |
||
782 | $sq = substr($sq, 1, -1); |
||
783 | } |
||
784 | return $sq; |
||
785 | } |
||
786 | |||
787 | private function process_from(&$tokens) { |
||
788 | |||
789 | $expression = ""; |
||
790 | $expr = array(); |
||
791 | $token_count=0; |
||
792 | $table = ""; |
||
793 | $alias = ""; |
||
794 | |||
795 | $skip_next=false; |
||
796 | $i=0; |
||
797 | $join_type = ''; |
||
798 | $ref_type=""; |
||
799 | $ref_expr=""; |
||
800 | $base_expr=""; |
||
801 | $sub_tree = false; |
||
802 | $subquery = ""; |
||
803 | |||
804 | $first_join=true; |
||
805 | $modifier=""; |
||
806 | $saved_join_type=""; |
||
807 | |||
808 | foreach($tokens as $token) { |
||
809 | $base_expr = false; |
||
810 | $upper = strtoupper(trim($token)); |
||
811 | |||
812 | if($skip_next && $token) { |
||
813 | $token_count++; |
||
814 | $skip_next = false; |
||
815 | continue; |
||
816 | } else { |
||
817 | if($skip_next) { |
||
818 | continue; |
||
819 | } |
||
820 | } |
||
821 | |||
822 | if(preg_match("/^\\s*\\(\\s*select/i",$token)) { |
||
823 | $type = 'subquery'; |
||
824 | $table = "DEPENDENT-SUBQUERY"; |
||
825 | $sub_tree = $this->parse($this->trimSubquery($token)); |
||
826 | $subquery = $token; |
||
827 | } |
||
828 | |||
829 | switch($upper) { |
||
830 | case 'OUTER': |
||
831 | case 'LEFT': |
||
832 | case 'RIGHT': |
||
833 | case 'NATURAL': |
||
834 | case 'CROSS': |
||
835 | case ',': |
||
836 | case 'JOIN': |
||
837 | break; |
||
838 | |||
839 | default: |
||
840 | $expression .= $token == '' ? " " : $token; |
||
841 | if($ref_type) { |
||
842 | $ref_expr .= $token == '' ? " " : $token; |
||
843 | } |
||
844 | break; |
||
845 | } |
||
846 | |||
847 | switch($upper) { |
||
848 | case 'AS': |
||
849 | $token_count++; |
||
850 | $n=1; |
||
851 | $alias = ""; |
||
852 | while($alias == "") { |
||
853 | $alias = trim($tokens[$i+$n]); |
||
854 | ++$n; |
||
855 | } |
||
856 | |||
857 | continue; |
||
858 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
859 | |||
860 | case 'INDEX': |
||
861 | if($token_category == 'CREATE') { |
||
862 | $token_category = $upper; |
||
863 | continue 2; |
||
864 | } |
||
865 | |||
866 | break; |
||
867 | |||
868 | case 'USING': |
||
869 | case 'ON': |
||
0 ignored issues
–
show
|
|||
870 | $ref_type = $upper; |
||
871 | $ref_expr = ""; |
||
872 | |||
873 | case 'CROSS': |
||
874 | case 'USE': |
||
875 | case 'FORCE': |
||
876 | case 'IGNORE': |
||
877 | case 'INNER': |
||
878 | case 'OUTER': |
||
879 | # $expression .= $token; |
||
880 | $token_count++; |
||
881 | continue; |
||
882 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
883 | |||
884 | |||
885 | |||
886 | case 'FOR': |
||
887 | $token_count++; |
||
888 | $skip_next = true; |
||
889 | continue; |
||
890 | break; |
||
0 ignored issues
–
show
break; does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
891 | |||
892 | case 'LEFT': |
||
893 | case 'RIGHT': |
||
894 | case 'STRAIGHT_JOIN': |
||
895 | $join_type=$saved_join_type; |
||
896 | |||
897 | $modifier = $upper . " "; |
||
898 | break; |
||
899 | |||
900 | |||
901 | case ',': |
||
0 ignored issues
–
show
|
|||
902 | $modifier = 'CROSS'; |
||
903 | |||
904 | case 'JOIN': |
||
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. ![]() |
|||
905 | |||
906 | if($first_join) { |
||
907 | $join_type = 'JOIN'; |
||
908 | $saved_join_type = ($modifier ? $modifier : 'JOIN'); |
||
909 | } else { |
||
910 | $new_join_type = ($modifier ? $modifier : 'JOIN'); |
||
911 | $join_type = $saved_join_type; |
||
912 | $saved_join_type = $new_join_type; |
||
913 | unset($new_join_type); |
||
914 | } |
||
915 | |||
916 | $first_join = false; |
||
917 | |||
918 | if(!trim($alias)) $alias = $table; |
||
919 | |||
920 | if($subquery) { |
||
921 | $sub_tree = $this->parse(trim($subquery,'()')); |
||
922 | $base_expr=$subquery; |
||
923 | } |
||
924 | |||
925 | if(substr(trim($table),0,1) == '(') { |
||
926 | $base_expr=$this->trimSubquery($table); |
||
927 | $join_type = 'JOIN'; |
||
928 | $sub_tree = $this->process_from($this->split_sql($base_expr)); |
||
0 ignored issues
–
show
|
|||
929 | $alias=""; |
||
930 | } |
||
931 | |||
932 | |||
933 | if($join_type == "") $join_type='JOIN'; |
||
934 | $expr[] = array('table'=>$table, 'alias'=>$alias,'join_type'=>$join_type,'ref_type'=> $ref_type,'ref_clause'=>$this->trimSubquery($ref_expr), 'base_expr' => $base_expr, 'sub_tree' => $sub_tree); |
||
935 | $modifier = ""; |
||
936 | #$join_type=$saved_join_type; |
||
937 | |||
938 | |||
939 | $token_count = 0; |
||
940 | $table = $alias = $expression = $base_expr = $ref_type = $ref_expr = ""; |
||
941 | $sub_tree=false; |
||
942 | $subquery = ""; |
||
943 | |||
944 | break; |
||
945 | |||
946 | |||
947 | default: |
||
948 | if($token === false || empty($token) || $token === "") continue; |
||
949 | |||
950 | if($token_count == 0 ) { |
||
951 | if(!$table) { |
||
952 | $table = $token ; |
||
953 | } |
||
954 | } else if($token_count == 1) { |
||
955 | $alias = $token; |
||
956 | } |
||
957 | $token_count++; |
||
958 | break; |
||
959 | } |
||
960 | ++$i; |
||
961 | } |
||
962 | if(substr(trim($table),0,1) == '(') { |
||
963 | $base_expr=$this->trimSubquery($table); |
||
964 | $join_type = 'JOIN'; |
||
965 | $sub_tree = $this->process_from($this->split_sql($base_expr)); |
||
0 ignored issues
–
show
|
|||
966 | $alias = ""; |
||
967 | } else { |
||
968 | if(!trim($alias)) $alias = $table; |
||
969 | } |
||
970 | if($join_type == "") $saved_join_type='JOIN'; |
||
971 | |||
972 | $expr[] = array('table'=>$table, 'alias'=>$alias,'join_type'=>$saved_join_type,'ref_type'=> $ref_type,'ref_clause'=> $this->trimSubquery($ref_expr), 'base_expr' => $base_expr, 'sub_tree' => $sub_tree); |
||
973 | |||
974 | |||
975 | return $expr; |
||
976 | } |
||
977 | |||
978 | private function process_group(&$tokens, &$select) { |
||
979 | |||
980 | $out=array(); |
||
981 | $expression = ""; |
||
982 | $direction="ASC"; |
||
983 | $type = "expression"; |
||
984 | if(!$tokens) return false; |
||
985 | |||
986 | foreach($tokens as $token) { |
||
987 | switch(strtoupper($token)) { |
||
988 | case ',': |
||
989 | $expression = trim($expression); |
||
990 | if($expression[0] != '`' || substr($expression,-1) != '`') { |
||
991 | $escaped = str_replace('`','``',$expression); |
||
992 | } else { |
||
993 | $escaped = $expression; |
||
994 | } |
||
995 | $escaped = '`' . $escaped . '`'; |
||
996 | |||
997 | if(is_numeric(trim($expression))) { |
||
998 | $type = 'pos'; |
||
999 | } else { |
||
1000 | |||
1001 | #search to see if the expression matches an alias |
||
1002 | foreach($select as $clause) { |
||
1003 | if($clause['alias'] == $escaped) { |
||
1004 | $type = 'alias'; |
||
1005 | } |
||
1006 | } |
||
1007 | |||
1008 | if(!$type) $type = "expression"; |
||
1009 | } |
||
1010 | |||
1011 | $out[]=array('type'=>$type,'base_expr'=>$expression,'direction'=>$direction); |
||
1012 | $escaped = ""; |
||
1013 | $expression = ""; |
||
1014 | $direction = "ASC"; |
||
1015 | $type = ""; |
||
1016 | break; |
||
1017 | |||
1018 | case 'ASC': |
||
1019 | $direction = "ASC"; |
||
1020 | break; |
||
1021 | case 'DESC': |
||
1022 | $direction = "DESC"; |
||
1023 | break; |
||
1024 | |||
1025 | default: |
||
1026 | $expression .= $token == '' ? ' ' : $token; |
||
1027 | |||
1028 | |||
1029 | } |
||
1030 | } |
||
1031 | if($expression) { |
||
1032 | $expression = trim($expression); |
||
1033 | if($expression[0] != '`' || substr($expression,-1) != '`') { |
||
1034 | $escaped = str_replace('`','``',$expression); |
||
1035 | } else { |
||
1036 | $escaped = $expression; |
||
1037 | } |
||
1038 | $escaped = '`' . $escaped . '`'; |
||
1039 | |||
1040 | if(is_numeric(trim($expression))) { |
||
1041 | $type = 'pos'; |
||
1042 | } else { |
||
1043 | |||
1044 | #search to see if the expression matches an alias |
||
1045 | if(!$type && $select) { |
||
1046 | foreach($select as $clause) { |
||
1047 | if(!is_array($clause)) continue; |
||
1048 | if($clause['alias'] == $escaped) { |
||
1049 | $type = 'alias'; |
||
1050 | } |
||
1051 | } |
||
1052 | } else { |
||
1053 | $type="expression"; |
||
1054 | } |
||
1055 | |||
1056 | if(!$type) $type = "expression"; |
||
1057 | } |
||
1058 | |||
1059 | $out[]=array('type'=>$type,'base_expr'=>$expression,'direction'=>$direction); |
||
1060 | } |
||
1061 | foreach($out as &$term) { |
||
1062 | if(!empty($term['base_expr'])) { |
||
1063 | $term['sub_tree'] = array($this->process_select_expr($term['base_expr'])); |
||
1064 | } |
||
1065 | } |
||
1066 | |||
1067 | return $out; |
||
1068 | } |
||
1069 | |||
1070 | /* Some sections are just lists of expressions, like the WHERE and HAVING clauses. This function |
||
1071 | processes these sections. Recursive. |
||
1072 | */ |
||
1073 | private function process_expr_list($tokens) { |
||
1074 | $expr = ""; |
||
1075 | $type = ""; |
||
1076 | $prev_token = ""; |
||
1077 | $skip_next = false; |
||
1078 | $sub_expr = ""; |
||
1079 | |||
1080 | $in_lists = array(); |
||
1081 | foreach($tokens as $key => $token) { |
||
1082 | |||
1083 | if(strlen(trim($token))==0) continue; |
||
1084 | if($skip_next) { |
||
1085 | $skip_next = false; |
||
1086 | continue; |
||
1087 | } |
||
1088 | |||
1089 | $processed = false; |
||
1090 | $upper = strtoupper(trim($token)); |
||
1091 | if(trim($token)) $token=trim($token); |
||
1092 | |||
1093 | /* is it a subquery?*/ |
||
1094 | if(preg_match("/^\\s*\\(\\s*SELECT/i", $token)) { |
||
1095 | $type = 'subquery'; |
||
1096 | #tokenize and parse the subquery. |
||
1097 | #we remove the enclosing parenthesis for the tokenizer |
||
1098 | $processed = $this->parse($this->trimSubquery($token)); |
||
1099 | |||
1100 | |||
1101 | /* is it an inlist */ |
||
1102 | } elseif( $upper[0] == '(' && substr($upper,-1) == ')' ) { |
||
1103 | if($prev_token == 'IN') { |
||
1104 | $type = "in-list"; |
||
1105 | $processed = $this->split_sql(substr($token,1,-1)); |
||
1106 | $list = array(); |
||
1107 | foreach($processed as $v) { |
||
0 ignored issues
–
show
The expression
$processed of type false|array<integer,?> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
1108 | if($v == ',') continue; |
||
1109 | $list[]=$v; |
||
1110 | } |
||
1111 | $processed = $list; |
||
1112 | unset($list); |
||
1113 | $prev_token = ""; |
||
1114 | |||
1115 | } |
||
1116 | elseif($prev_token == 'AGAINST') { |
||
1117 | $type = "match-arguments"; |
||
1118 | $list = $this->split_sql(substr($token,1,-1)); |
||
1119 | if(count($list) > 1){ |
||
1120 | $match_mode = implode('',array_slice($list,1)); |
||
1121 | $processed = array($list[0], $match_mode); |
||
1122 | } |
||
1123 | else |
||
1124 | $processed = $list[0]; |
||
1125 | $prev_token = ""; |
||
1126 | } |
||
1127 | |||
1128 | /* it is either an operator, a colref or a constant */ |
||
1129 | } else { |
||
1130 | switch($upper) { |
||
1131 | case 'AND': |
||
1132 | case '&&': |
||
1133 | case 'BETWEEN': |
||
1134 | case 'AND': |
||
1135 | case 'BINARY': |
||
1136 | case '&': |
||
1137 | case '~': |
||
1138 | case '|': |
||
1139 | case '^': |
||
1140 | case 'CASE': |
||
1141 | case 'WHEN': |
||
1142 | case 'END': |
||
1143 | case 'DIV': |
||
1144 | case '/': |
||
1145 | case '<=>': |
||
1146 | case '=': |
||
1147 | case '>=': |
||
1148 | case '>': |
||
1149 | case 'IS': |
||
1150 | case 'NOT': |
||
1151 | case 'NULL': |
||
1152 | case '<<': |
||
1153 | case '<=': |
||
1154 | case '<': |
||
1155 | case 'LIKE': |
||
1156 | case '-': |
||
1157 | case '%': |
||
1158 | case '!=': |
||
1159 | case '<>': |
||
1160 | case 'REGEXP': |
||
1161 | case '!': |
||
1162 | case '||': |
||
1163 | case 'OR': |
||
1164 | case '+': |
||
1165 | case '>>': |
||
1166 | case 'RLIKE': |
||
1167 | case 'SOUNDS': |
||
1168 | case '*': |
||
1169 | case '-': |
||
1170 | case 'XOR': |
||
1171 | case 'IN': |
||
1172 | $processed = false; |
||
1173 | $type = "operator"; |
||
1174 | break; |
||
1175 | default: |
||
1176 | switch($token[0]) { |
||
1177 | case "'": |
||
1178 | case '"': |
||
1179 | $type = 'const'; |
||
1180 | break; |
||
1181 | case '`': |
||
1182 | $type = 'colref'; |
||
1183 | break; |
||
1184 | |||
1185 | default: |
||
1186 | if(is_numeric($token)) { |
||
1187 | $type = 'const'; |
||
1188 | } else { |
||
1189 | $type = 'colref'; |
||
1190 | } |
||
1191 | break; |
||
1192 | |||
1193 | } |
||
1194 | #$processed = $token; |
||
1195 | $processed = false; |
||
1196 | } |
||
1197 | } |
||
1198 | /* is a reserved word? */ |
||
1199 | if(($type != 'operator' && $type != 'in-list' && $type != 'sub_expr') && in_array($upper, $this->reserved)) { |
||
1200 | $token = $upper; |
||
1201 | if(!in_array($upper,$this->functions)) { |
||
1202 | $type = 'reserved'; |
||
1203 | } else { |
||
1204 | switch($token) { |
||
1205 | case 'AVG': |
||
1206 | case 'SUM': |
||
1207 | case 'COUNT': |
||
1208 | case 'MIN': |
||
1209 | case 'MAX': |
||
1210 | case 'STDDEV': |
||
1211 | case 'STDDEV_SAMP': |
||
1212 | case 'STDDEV_POP': |
||
1213 | case 'VARIANCE': |
||
1214 | case 'VAR_SAMP': |
||
1215 | case 'VAR_POP': |
||
1216 | case 'GROUP_CONCAT': |
||
1217 | case 'BIT_AND': |
||
1218 | case 'BIT_OR': |
||
1219 | case 'BIT_XOR': |
||
1220 | $type = 'aggregate_function'; |
||
1221 | if(!empty($tokens[$key+1])) $sub_expr = $tokens[$key+1]; |
||
1222 | #$skip_next=true; |
||
1223 | break; |
||
1224 | |||
1225 | default: |
||
1226 | $type = 'function'; |
||
1227 | if(!empty($tokens[$key+1])) $sub_expr = $tokens[$key+1]; else $sub_expr="()"; |
||
1228 | #$skip_next=true; |
||
1229 | |||
1230 | |||
1231 | break; |
||
1232 | } |
||
1233 | } |
||
1234 | } |
||
1235 | |||
1236 | if(!$type) { |
||
1237 | if($upper[0] == '(') { |
||
1238 | $local_expr = substr(trim($token),1,-1); |
||
1239 | } else { |
||
1240 | $local_expr = $token; |
||
1241 | } |
||
1242 | $processed = $this->process_expr_list($this->split_sql($local_expr)); |
||
1243 | $type = 'expression'; |
||
1244 | |||
1245 | // if(count($processed) == 1) { |
||
1246 | // $type = $processed[0]['expr_type']; |
||
1247 | // $base_expr = $processed[0]['base_expr']; |
||
1248 | // $processed = $processed[0]['sub_tree']; |
||
1249 | // } |
||
1250 | |||
1251 | } |
||
1252 | |||
1253 | $sub_expr=trim($sub_expr); |
||
1254 | $sub_expr = ""; |
||
1255 | |||
1256 | $expr[] = array( 'expr_type' => $type, 'base_expr' => $token, 'sub_tree' => $processed); |
||
1257 | $prev_token = $upper; |
||
1258 | $expr_type = ""; |
||
1259 | $type = ""; |
||
1260 | } |
||
1261 | if($sub_expr) { |
||
1262 | $processed['sub_tree'] = $this->process_expr_list($this->split_sql(substr($sub_expr,1,-1))); |
||
1263 | } |
||
1264 | |||
1265 | if(!is_array($processed)) { |
||
1266 | $processed = false; |
||
1267 | } |
||
1268 | |||
1269 | if($expr_type) { |
||
1270 | $expr[] = array( 'expr_type' => $type, 'base_expr' => $token, 'sub_tree' => $processed); |
||
1271 | } |
||
1272 | $mod = false; |
||
1273 | |||
1274 | /* |
||
1275 | |||
1276 | for($i=0;$i<count($expr);++$i){ |
||
1277 | if($expr[$i]['expr_type'] == 'function' || |
||
1278 | $expr[$i]['expr_type'] == 'aggregate_function') { |
||
1279 | if(!empty($expr[$i+1])) { |
||
1280 | $expr[$i]['sub_tree']=$expr[$i+1]['sub_tree']; |
||
1281 | unset($expr[$i+1]); |
||
1282 | $mod = 1; |
||
1283 | ++$i; // BAD FORM TO MODIFY THE LOOP COUNTER |
||
1284 | } |
||
1285 | } |
||
1286 | |||
1287 | } |
||
1288 | |||
1289 | */ |
||
1290 | |||
1291 | if($mod) $expr=array_values($expr); |
||
1292 | |||
1293 | |||
1294 | return $expr; |
||
1295 | } |
||
1296 | |||
1297 | private function process_update($tokens) { |
||
0 ignored issues
–
show
|
|||
1298 | |||
1299 | } |
||
1300 | |||
1301 | private function process_delete($tokens) { |
||
1302 | $tables = array(); |
||
1303 | $del = $tokens['DELETE']; |
||
1304 | |||
1305 | foreach($tokens['DELETE'] as $expression) { |
||
1306 | if ($expression != 'DELETE' && trim($expression,' .*') != "" && $expression != ',') { |
||
1307 | $tables[] = trim($expression,'.* '); |
||
1308 | } |
||
1309 | } |
||
1310 | |||
1311 | if(empty($tables)) { |
||
1312 | foreach($tokens['FROM'] as $table) { |
||
1313 | $tables[] = $table['table']; |
||
1314 | } |
||
1315 | } |
||
1316 | |||
1317 | $tokens['DELETE'] = array('TABLES' => $tables); |
||
1318 | |||
1319 | return $tokens; |
||
1320 | } |
||
1321 | |||
1322 | private function process_insert($tokens, $token_category = 'INSERT') { |
||
1323 | $table = ""; |
||
1324 | $cols = ""; |
||
1325 | |||
1326 | $into = $tokens['INTO']; |
||
1327 | foreach($into as $token) { |
||
1328 | if(!trim($token)) continue; |
||
1329 | if(!$table) { |
||
1330 | $table = $token; |
||
1331 | }elseif(!$cols) { |
||
1332 | $cols = $token; |
||
1333 | } |
||
1334 | } |
||
1335 | |||
1336 | if(!$cols) { |
||
1337 | $cols = 'ALL'; |
||
1338 | } else { |
||
1339 | $cols = explode(",", $this->trimSubquery($cols)); |
||
1340 | } |
||
1341 | unset($tokens['INTO']); |
||
1342 | $tokens[$token_category] = array('table'=>$table, 'cols'=>$cols); |
||
1343 | return $tokens; |
||
1344 | |||
1345 | } |
||
1346 | |||
1347 | |||
1348 | private function load_reserved_words() { |
||
1349 | |||
1350 | $this->functions = array( |
||
1351 | 'abs', |
||
1352 | 'acos', |
||
1353 | 'adddate', |
||
1354 | 'addtime', |
||
1355 | 'aes_encrypt', |
||
1356 | 'aes_decrypt', |
||
1357 | 'against', |
||
1358 | 'ascii', |
||
1359 | 'asin', |
||
1360 | 'atan', |
||
1361 | 'avg', |
||
1362 | 'benchmark', |
||
1363 | 'bin', |
||
1364 | 'bit_and', |
||
1365 | 'bit_or', |
||
1366 | 'bitcount', |
||
1367 | 'bitlength', |
||
1368 | 'cast', |
||
1369 | 'ceiling', |
||
1370 | 'char', |
||
1371 | 'char_length', |
||
1372 | 'character_length', |
||
1373 | 'charset', |
||
1374 | 'coalesce', |
||
1375 | 'coercibility', |
||
1376 | 'collation', |
||
1377 | 'compress', |
||
1378 | 'concat', |
||
1379 | 'concat_ws', |
||
1380 | 'conection_id', |
||
1381 | 'conv', |
||
1382 | 'convert', |
||
1383 | 'convert_tz', |
||
1384 | 'cos', |
||
1385 | 'cot', |
||
1386 | 'count', |
||
1387 | 'crc32', |
||
1388 | 'curdate', |
||
1389 | 'current_user', |
||
1390 | 'currval', |
||
1391 | 'curtime', |
||
1392 | 'database', |
||
1393 | 'date_add', |
||
1394 | 'date_diff', |
||
1395 | 'date_format', |
||
1396 | 'date_sub', |
||
1397 | 'day', |
||
1398 | 'dayname', |
||
1399 | 'dayofmonth', |
||
1400 | 'dayofweek', |
||
1401 | 'dayofyear', |
||
1402 | 'decode', |
||
1403 | 'default', |
||
1404 | 'degrees', |
||
1405 | 'des_decrypt', |
||
1406 | 'des_encrypt', |
||
1407 | 'elt', |
||
1408 | 'encode', |
||
1409 | 'encrypt', |
||
1410 | 'exp', |
||
1411 | 'export_set', |
||
1412 | 'extract', |
||
1413 | 'field', |
||
1414 | 'find_in_set', |
||
1415 | 'floor', |
||
1416 | 'format', |
||
1417 | 'found_rows', |
||
1418 | 'from_days', |
||
1419 | 'from_unixtime', |
||
1420 | 'get_format', |
||
1421 | 'get_lock', |
||
1422 | 'group_concat', |
||
1423 | 'greatest', |
||
1424 | 'hex', |
||
1425 | 'hour', |
||
1426 | 'if', |
||
1427 | 'ifnull', |
||
1428 | 'in', |
||
1429 | 'inet_aton', |
||
1430 | 'inet_ntoa', |
||
1431 | 'insert', |
||
1432 | 'instr', |
||
1433 | 'interval', |
||
1434 | 'is_free_lock', |
||
1435 | 'is_used_lock', |
||
1436 | 'last_day', |
||
1437 | 'last_insert_id', |
||
1438 | 'lcase', |
||
1439 | 'least', |
||
1440 | 'left', |
||
1441 | 'length', |
||
1442 | 'ln', |
||
1443 | 'load_file', |
||
1444 | 'localtime', |
||
1445 | 'localtimestamp', |
||
1446 | 'locate', |
||
1447 | 'log', |
||
1448 | 'log2', |
||
1449 | 'log10', |
||
1450 | 'lower', |
||
1451 | 'lpad', |
||
1452 | 'ltrim', |
||
1453 | 'make_set', |
||
1454 | 'makedate', |
||
1455 | 'maketime', |
||
1456 | 'master_pos_wait', |
||
1457 | 'match', |
||
1458 | 'max', |
||
1459 | 'md5', |
||
1460 | 'microsecond', |
||
1461 | 'mid', |
||
1462 | 'min', |
||
1463 | 'minute', |
||
1464 | 'mod', |
||
1465 | 'month', |
||
1466 | 'monthname', |
||
1467 | 'nextval', |
||
1468 | 'now', |
||
1469 | 'nullif', |
||
1470 | 'oct', |
||
1471 | 'octet_length', |
||
1472 | 'old_password', |
||
1473 | 'ord', |
||
1474 | 'password', |
||
1475 | 'period_add', |
||
1476 | 'period_diff', |
||
1477 | 'pi', |
||
1478 | 'position', |
||
1479 | 'pow', |
||
1480 | 'power', |
||
1481 | 'quarter', |
||
1482 | 'quote', |
||
1483 | 'radians', |
||
1484 | 'rand', |
||
1485 | 'release_lock', |
||
1486 | 'repeat', |
||
1487 | 'replace', |
||
1488 | 'reverse', |
||
1489 | 'right', |
||
1490 | 'round', |
||
1491 | 'row_count', |
||
1492 | 'rpad', |
||
1493 | 'rtrim', |
||
1494 | 'sec_to_time', |
||
1495 | 'second', |
||
1496 | 'session_user', |
||
1497 | 'sha', |
||
1498 | 'sha1', |
||
1499 | 'sign', |
||
1500 | 'soundex', |
||
1501 | 'space', |
||
1502 | 'sqrt', |
||
1503 | 'std', |
||
1504 | 'stddev', |
||
1505 | 'stddev_pop', |
||
1506 | 'stddev_samp', |
||
1507 | 'strcmp', |
||
1508 | 'str_to_date', |
||
1509 | 'subdate', |
||
1510 | 'substr', |
||
1511 | 'substring', |
||
1512 | 'substring_index', |
||
1513 | 'subtime', |
||
1514 | 'sum', |
||
1515 | 'sysdate', |
||
1516 | 'system_user', |
||
1517 | 'tan', |
||
1518 | 'time', |
||
1519 | 'timediff', |
||
1520 | 'timestamp', |
||
1521 | 'timestampadd', |
||
1522 | 'timestampdiff', |
||
1523 | 'time_format', |
||
1524 | 'time_to_sec', |
||
1525 | 'to_days', |
||
1526 | 'trim', |
||
1527 | 'truncate', |
||
1528 | 'ucase', |
||
1529 | 'uncompress', |
||
1530 | 'uncompressed_length', |
||
1531 | 'unhex', |
||
1532 | 'unix_timestamp', |
||
1533 | 'upper', |
||
1534 | 'user', |
||
1535 | 'utc_date', |
||
1536 | 'utc_time', |
||
1537 | 'utc_timestamp', |
||
1538 | 'uuid', |
||
1539 | 'var_pop', |
||
1540 | 'var_samp', |
||
1541 | 'variance', |
||
1542 | 'version', |
||
1543 | 'week', |
||
1544 | 'weekday', |
||
1545 | 'weekofyear', |
||
1546 | 'year', |
||
1547 | 'yearweek'); |
||
1548 | |||
1549 | /* includes functions */ |
||
1550 | $this->reserved = array( |
||
1551 | 'abs', |
||
1552 | 'acos', |
||
1553 | 'adddate', |
||
1554 | 'addtime', |
||
1555 | 'aes_encrypt', |
||
1556 | 'aes_decrypt', |
||
1557 | 'against', |
||
1558 | 'ascii', |
||
1559 | 'asin', |
||
1560 | 'atan', |
||
1561 | 'avg', |
||
1562 | 'benchmark', |
||
1563 | 'bin', |
||
1564 | 'bit_and', |
||
1565 | 'bit_or', |
||
1566 | 'bitcount', |
||
1567 | 'bitlength', |
||
1568 | 'cast', |
||
1569 | 'ceiling', |
||
1570 | 'char', |
||
1571 | 'char_length', |
||
1572 | 'character_length', |
||
1573 | 'charset', |
||
1574 | 'coalesce', |
||
1575 | 'coercibility', |
||
1576 | 'collation', |
||
1577 | 'compress', |
||
1578 | 'concat', |
||
1579 | 'concat_ws', |
||
1580 | 'conection_id', |
||
1581 | 'conv', |
||
1582 | 'convert', |
||
1583 | 'convert_tz', |
||
1584 | 'cos', |
||
1585 | 'cot', |
||
1586 | 'count', |
||
1587 | 'crc32', |
||
1588 | 'curdate', |
||
1589 | 'current_user', |
||
1590 | 'currval', |
||
1591 | 'curtime', |
||
1592 | 'database', |
||
1593 | 'date_add', |
||
1594 | 'date_diff', |
||
1595 | 'date_format', |
||
1596 | 'date_sub', |
||
1597 | 'day', |
||
1598 | 'dayname', |
||
1599 | 'dayofmonth', |
||
1600 | 'dayofweek', |
||
1601 | 'dayofyear', |
||
1602 | 'decode', |
||
1603 | 'default', |
||
1604 | 'degrees', |
||
1605 | 'des_decrypt', |
||
1606 | 'des_encrypt', |
||
1607 | 'elt', |
||
1608 | 'encode', |
||
1609 | 'encrypt', |
||
1610 | 'exp', |
||
1611 | 'export_set', |
||
1612 | 'extract', |
||
1613 | 'field', |
||
1614 | 'find_in_set', |
||
1615 | 'floor', |
||
1616 | 'format', |
||
1617 | 'found_rows', |
||
1618 | 'from_days', |
||
1619 | 'from_unixtime', |
||
1620 | 'get_format', |
||
1621 | 'get_lock', |
||
1622 | 'group_concat', |
||
1623 | 'greatest', |
||
1624 | 'hex', |
||
1625 | 'hour', |
||
1626 | 'if', |
||
1627 | 'ifnull', |
||
1628 | 'in', |
||
1629 | 'inet_aton', |
||
1630 | 'inet_ntoa', |
||
1631 | 'insert', |
||
1632 | 'instr', |
||
1633 | 'interval', |
||
1634 | 'is_free_lock', |
||
1635 | 'is_used_lock', |
||
1636 | 'last_day', |
||
1637 | 'last_insert_id', |
||
1638 | 'lcase', |
||
1639 | 'least', |
||
1640 | 'left', |
||
1641 | 'length', |
||
1642 | 'ln', |
||
1643 | 'load_file', |
||
1644 | 'localtime', |
||
1645 | 'localtimestamp', |
||
1646 | 'locate', |
||
1647 | 'log', |
||
1648 | 'log2', |
||
1649 | 'log10', |
||
1650 | 'lower', |
||
1651 | 'lpad', |
||
1652 | 'ltrim', |
||
1653 | 'make_set', |
||
1654 | 'makedate', |
||
1655 | 'maketime', |
||
1656 | 'master_pos_wait', |
||
1657 | 'match', |
||
1658 | 'max', |
||
1659 | 'md5', |
||
1660 | 'microsecond', |
||
1661 | 'mid', |
||
1662 | 'min', |
||
1663 | 'minute', |
||
1664 | 'mod', |
||
1665 | 'month', |
||
1666 | 'monthname', |
||
1667 | 'nextval', |
||
1668 | 'now', |
||
1669 | 'nullif', |
||
1670 | 'oct', |
||
1671 | 'octet_length', |
||
1672 | 'old_password', |
||
1673 | 'ord', |
||
1674 | 'password', |
||
1675 | 'period_add', |
||
1676 | 'period_diff', |
||
1677 | 'pi', |
||
1678 | 'position', |
||
1679 | 'pow', |
||
1680 | 'power', |
||
1681 | 'quarter', |
||
1682 | 'quote', |
||
1683 | 'radians', |
||
1684 | 'rand', |
||
1685 | 'release_lock', |
||
1686 | 'repeat', |
||
1687 | 'replace', |
||
1688 | 'reverse', |
||
1689 | 'right', |
||
1690 | 'round', |
||
1691 | 'row_count', |
||
1692 | 'rpad', |
||
1693 | 'rtrim', |
||
1694 | 'sec_to_time', |
||
1695 | 'second', |
||
1696 | 'session_user', |
||
1697 | 'sha', |
||
1698 | 'sha1', |
||
1699 | 'sign', |
||
1700 | 'soundex', |
||
1701 | 'space', |
||
1702 | 'sqrt', |
||
1703 | 'std', |
||
1704 | 'stddev', |
||
1705 | 'stddev_pop', |
||
1706 | 'stddev_samp', |
||
1707 | 'strcmp', |
||
1708 | 'str_to_date', |
||
1709 | 'subdate', |
||
1710 | 'substring', |
||
1711 | 'substring_index', |
||
1712 | 'subtime', |
||
1713 | 'sum', |
||
1714 | 'sysdate', |
||
1715 | 'system_user', |
||
1716 | 'tan', |
||
1717 | 'time', |
||
1718 | 'timediff', |
||
1719 | 'timestamp', |
||
1720 | 'timestampadd', |
||
1721 | 'timestampdiff', |
||
1722 | 'time_format', |
||
1723 | 'time_to_sec', |
||
1724 | 'to_days', |
||
1725 | 'trim', |
||
1726 | 'truncate', |
||
1727 | 'ucase', |
||
1728 | 'uncompress', |
||
1729 | 'uncompressed_length', |
||
1730 | 'unhex', |
||
1731 | 'unix_timestamp', |
||
1732 | 'upper', |
||
1733 | 'user', |
||
1734 | 'utc_date', |
||
1735 | 'utc_time', |
||
1736 | 'utc_timestamp', |
||
1737 | 'uuid', |
||
1738 | 'var_pop', |
||
1739 | 'var_samp', |
||
1740 | 'variance', |
||
1741 | 'version', |
||
1742 | 'week', |
||
1743 | 'weekday', |
||
1744 | 'weekofyear', |
||
1745 | 'year', |
||
1746 | 'yearweek', |
||
1747 | 'add', |
||
1748 | 'all', |
||
1749 | 'alter', |
||
1750 | 'analyze', |
||
1751 | 'and', |
||
1752 | 'as', |
||
1753 | 'asc', |
||
1754 | 'asensitive', |
||
1755 | 'auto_increment', |
||
1756 | 'bdb', |
||
1757 | 'before', |
||
1758 | 'berkeleydb', |
||
1759 | 'between', |
||
1760 | 'bigint', |
||
1761 | 'binary', |
||
1762 | 'blob', |
||
1763 | 'both', |
||
1764 | 'by', |
||
1765 | 'call', |
||
1766 | 'cascade', |
||
1767 | 'case', |
||
1768 | 'change', |
||
1769 | 'char', |
||
1770 | 'character', |
||
1771 | 'check', |
||
1772 | 'collate', |
||
1773 | 'column', |
||
1774 | 'columns', |
||
1775 | 'condition', |
||
1776 | 'connection', |
||
1777 | 'constraint', |
||
1778 | 'continue', |
||
1779 | 'create', |
||
1780 | 'cross', |
||
1781 | 'current_date', |
||
1782 | 'current_time', |
||
1783 | 'current_timestamp', |
||
1784 | 'cursor', |
||
1785 | 'database', |
||
1786 | 'databases', |
||
1787 | 'day_hour', |
||
1788 | 'day_microsecond', |
||
1789 | 'day_minute', |
||
1790 | 'day_second', |
||
1791 | 'dec', |
||
1792 | 'decimal', |
||
1793 | 'declare', |
||
1794 | 'default', |
||
1795 | 'delayed', |
||
1796 | 'delete', |
||
1797 | 'desc', |
||
1798 | 'describe', |
||
1799 | 'deterministic', |
||
1800 | 'distinct', |
||
1801 | 'distinctrow', |
||
1802 | 'div', |
||
1803 | 'double', |
||
1804 | 'drop', |
||
1805 | 'else', |
||
1806 | 'elseif', |
||
1807 | 'enclosed', |
||
1808 | 'escaped', |
||
1809 | 'exists', |
||
1810 | 'exit', |
||
1811 | 'explain', |
||
1812 | 'false', |
||
1813 | 'fetch', |
||
1814 | 'fields', |
||
1815 | 'float', |
||
1816 | 'for', |
||
1817 | 'force', |
||
1818 | 'foreign', |
||
1819 | 'found', |
||
1820 | 'frac_second', |
||
1821 | 'from', |
||
1822 | 'fulltext', |
||
1823 | 'grant', |
||
1824 | 'group', |
||
1825 | 'having', |
||
1826 | 'high_priority', |
||
1827 | 'hour_microsecond', |
||
1828 | 'hour_minute', |
||
1829 | 'hour_second', |
||
1830 | 'if', |
||
1831 | 'ignore', |
||
1832 | 'in', |
||
1833 | 'index', |
||
1834 | 'infile', |
||
1835 | 'inner', |
||
1836 | 'innodb', |
||
1837 | 'inout', |
||
1838 | 'insensitive', |
||
1839 | 'insert', |
||
1840 | 'int', |
||
1841 | 'integer', |
||
1842 | 'interval', |
||
1843 | 'into', |
||
1844 | 'io_thread', |
||
1845 | 'is', |
||
1846 | 'iterate', |
||
1847 | 'join', |
||
1848 | 'key', |
||
1849 | 'keys', |
||
1850 | 'kill', |
||
1851 | 'leading', |
||
1852 | 'leave', |
||
1853 | 'left', |
||
1854 | 'like', |
||
1855 | 'limit', |
||
1856 | 'lines', |
||
1857 | 'load', |
||
1858 | 'localtime', |
||
1859 | 'localtimestamp', |
||
1860 | 'lock', |
||
1861 | 'long', |
||
1862 | 'longblob', |
||
1863 | 'longtext', |
||
1864 | 'loop', |
||
1865 | 'low_priority', |
||
1866 | 'master_server_id', |
||
1867 | 'match', |
||
1868 | 'mediumblob', |
||
1869 | 'mediumint', |
||
1870 | 'mediumtext', |
||
1871 | 'middleint', |
||
1872 | 'minute_microsecond', |
||
1873 | 'minute_second', |
||
1874 | 'mod', |
||
1875 | 'natural', |
||
1876 | 'not', |
||
1877 | 'no_write_to_binlog', |
||
1878 | 'null', |
||
1879 | 'numeric', |
||
1880 | 'on', |
||
1881 | 'optimize', |
||
1882 | 'option', |
||
1883 | 'optionally', |
||
1884 | 'or', |
||
1885 | 'order', |
||
1886 | 'out', |
||
1887 | 'outer', |
||
1888 | 'outfile', |
||
1889 | 'precision', |
||
1890 | 'primary', |
||
1891 | 'privileges', |
||
1892 | 'procedure', |
||
1893 | 'purge', |
||
1894 | 'read', |
||
1895 | 'real', |
||
1896 | 'references', |
||
1897 | 'regexp', |
||
1898 | 'rename', |
||
1899 | 'repeat', |
||
1900 | 'replace', |
||
1901 | 'require', |
||
1902 | 'restrict', |
||
1903 | 'return', |
||
1904 | 'revoke', |
||
1905 | 'right', |
||
1906 | 'rlike', |
||
1907 | 'second_microsecond', |
||
1908 | 'select', |
||
1909 | 'sensitive', |
||
1910 | 'separator', |
||
1911 | 'set', |
||
1912 | 'show', |
||
1913 | 'smallint', |
||
1914 | 'some', |
||
1915 | 'soname', |
||
1916 | 'spatial', |
||
1917 | 'specific', |
||
1918 | 'sql', |
||
1919 | 'sqlexception', |
||
1920 | 'sqlstate', |
||
1921 | 'sqlwarning', |
||
1922 | 'sql_big_result', |
||
1923 | 'sql_calc_found_rows', |
||
1924 | 'sql_small_result', |
||
1925 | 'sql_tsi_day', |
||
1926 | 'sql_tsi_frac_second', |
||
1927 | 'sql_tsi_hour', |
||
1928 | 'sql_tsi_minute', |
||
1929 | 'sql_tsi_month', |
||
1930 | 'sql_tsi_quarter', |
||
1931 | 'sql_tsi_second', |
||
1932 | 'sql_tsi_week', |
||
1933 | 'sql_tsi_year', |
||
1934 | 'ssl', |
||
1935 | 'starting', |
||
1936 | 'straight_join', |
||
1937 | 'striped', |
||
1938 | 'table', |
||
1939 | 'tables', |
||
1940 | 'terminated', |
||
1941 | 'then', |
||
1942 | 'timestampadd', |
||
1943 | 'timestampdiff', |
||
1944 | 'tinyblob', |
||
1945 | 'tinyint', |
||
1946 | 'tinytext', |
||
1947 | 'to', |
||
1948 | 'trailing', |
||
1949 | 'true', |
||
1950 | 'undo', |
||
1951 | 'union', |
||
1952 | 'unique', |
||
1953 | 'unlock', |
||
1954 | 'unsigned', |
||
1955 | 'update', |
||
1956 | 'usage', |
||
1957 | 'use', |
||
1958 | 'user_resources', |
||
1959 | 'using', |
||
1960 | 'utc_date', |
||
1961 | 'utc_time', |
||
1962 | 'utc_timestamp', |
||
1963 | 'values', |
||
1964 | 'varbinary', |
||
1965 | 'varchar', |
||
1966 | 'varcharacter', |
||
1967 | 'varying', |
||
1968 | 'when', |
||
1969 | 'where', |
||
1970 | 'while', |
||
1971 | 'with', |
||
1972 | 'write', |
||
1973 | 'xor', |
||
1974 | 'year_month', |
||
1975 | 'zerofill' |
||
1976 | ); |
||
1977 | |||
1978 | for($i=0;$i<count($this->reserved);++$i) { |
||
0 ignored issues
–
show
It seems like you are calling the size function
count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}
// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
![]() |
|||
1979 | $this->reserved[$i]=strtoupper($this->reserved[$i]); |
||
1980 | if(!empty($this->functions[$i])) $this->functions[$i] = strtoupper($this->functions[$i]); |
||
1981 | } |
||
1982 | } |
||
1983 | |||
1984 | } // END CLASS |
||
1985 | |||
1986 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.