Issues (4069)

Security Analysis    not enabled

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.

include/php-sql-parser.php (3 issues)

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
/**
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) {
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
Performance Best Practice introduced by
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
}
Loading history...
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') {
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;
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;
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;
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;
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':
495
496
					case ';':
497
						continue 2;
498
						break;
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':
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;
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
Performance Best Practice introduced by
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
}
Loading history...
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;
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':
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;
883
884
885
886
					case 'FOR':
887
						$token_count++;
888
						$skip_next = true;
889
						continue;
890
					break;
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 ',':
902
						$modifier = 'CROSS';
903
904
					case 'JOIN':
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));
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));
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) {
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) {
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
Performance Best Practice introduced by
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
}
Loading history...
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