€%5€%6€%7€%8€%9€%:€%;€%<€%=€%>€%?€%@€%A€%B€%C€%D€%E€%F€%G€%H€%I€%J€%K€%L€%M€%N€%O€%P€%Q€%R€%S€%T€%U€%V€%W€%X€%Y€%Z€%[€%\€%]€%^€%_€%`€%a€%b€%c€%d€%e€%f€%i€%j€%k€%l€%m€%n€%o€%p€%g€%h€%q€%r€%s€%t€%u€%v€%w€%x€%~€%y€%z€%{€%Š€%|€%}€%€%€€%€%‚€%ƒ€%„€%…€%†€%‡€%ˆ€%‰€%‹€%Œ€%€%Ž€%€%€%‘€%’€%“€%”€%•€%–€%œ€%—€%˜€%™€%¥€%š€%›€%€%ž€%Ÿ€% €%¡€%¢€%£€%¤€%¦€%§€%¨€%©€%®€%ª€%«€%¬€%­€%±€%¯€%°€%³€%´€%µ€%¶€%·€%¸€%¹€%º€%»€%¼€%½€%¾€%¿€%À€%Á€%€%À%Ā%²€%ŀ%ƀ%ǀ%Ȁ%ɀ%ʀ%à€%ˀ%̀%̀%΀%π%Ѐ%р%Ҁ%Ӏ%Ԁ%Հ%ր%׀%؀%ـ%ڀ%ۀ%܀%݀%ހ%߀%á€%â€%ã€%ä€%å€%æ€%ç€%è€%é€%ê€%ë€%ì€%í€%î€%ï€%ð€%ñ€%ò€%ó€%ô€%õ€%ö€%÷€%ø€%ù€%þ€%ú€%û€%ü€%€%ý€%€%€%€%ÿ€%€%€%€%€%€% €% €% €% €% €%€%€%€%€%€%€%€%€%€%€%€%€%€%€%€%€%€%€% €%!€%#€%"€%'€%(€%)€%*€%+€%,€%-€%.€%/€%0€%1€%2€%3€%4€%5€%6€%<€%7€%8€%9€%=€%:€%;€%>€%?€%@€%A€%B€%C€%D€%E€%L€%M€%N€%O€%P€%Q€%R€%S€%T€%F€%G€%H€%U€%I€%J€%K€%W€%X€%Y€%Z€%[€%\€%]€%^€%V€%_€%`€%a€%b€%c€%d€%e€%k€%f€%g€%h€%i€%j€%l€%m€%n€%o€%p€%q€%r€%s€%t€%u€%v€%w€%x€%y€%z€%{€%|€%}€%~€%€%€€%€%‡€%‚€%ƒ€%„€%…€%†€%‰€%Š€%‹€%Œ€%€%Ž€%€%€%‘€%’€%“€%”€%ˆ€%•€%–€%—€%˜€%™€%š€%›€%œ€%€%ž€%Ÿ€% €%¡€%¢€%£€%¤€%¹€%¥€%¦€%§€%¨€%©€%ª€%«€%¬€%­€%®€%¯€%°€%±€%²€%³€%´€%µ€%¶€%·€%¸€%¼€%½€%¾€%¿€%À€%Á€%º€%»€%€%À%Ā%ŀ%ƀ%ǀ%Ȁ%ɀ%ʀ%ˀ%̀%̀%΀%π%Ѐ%р%Ҁ%Ӏ%Ԁ%Հ%ր%׀%؀%ـ%ڀ%ۀ%܀%æ€%݀%ހ%߀%è€%à€%á€%â€%ã€%ä€%å€%ç€%é€%ê€%ë€%ì€%ð€%í€%î€%ï€%ó€%ñ€%ô€%õ€%ö€%÷€%ò€%ø€%ù€%ú€%û€%ü€%ý€%þ€%ÿ€%€%€%€%€%€%€%€%€%€% €% €%€% €% €% €%€%€%€%€%€%€%€%€%€%€%€%€%€%€%€%€%"€%€% €%!€%&€%'€%(€%)€%#€%$€%%€%*€%+€%,€%-€%.€%/€%0€%1€%2€%3€%4€%5€%6€%7xError $e) { } } } return false; } private $subject; /** * @var int */ private $flags; /** @var wfWAFSQLiLexer */ protected $lexer; private $portableCommentVersions = array(); private $intervalUnits = array( 'SECOND', 'MINUTE', 'HOUR', 'DAY_SYM', 'WEEK', 'MONTH', 'QUARTER', 'YEAR', 'SECOND_MICROSECOND', 'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'HOUR_MICROSECOND', 'HOUR_SECOND', 'HOUR_MINUTE', 'DAY_MICROSECOND', 'DAY_SECOND', 'DAY_MINUTE', 'DAY_HOUR', 'YEAR_MONTH', ); private $keywords = array( 'ID', 'TIME', 'DATE', 'SQLTIME', 'ACCESSIBLE', 'ADD', 'ALL', 'ALTER', 'ANALYZE', 'AND', 'AS', 'ASC', 'ASENSITIVE', 'BEFORE', 'BETWEEN', 'BIGINT', 'BINARY', 'BLOB', 'BOTH', 'BY', 'CALL', 'CASCADE', 'CASE', 'CHANGE', 'CHAR', 'CHARACTER', 'CHECK', 'COLLATE', 'COLUMN', 'CONDITION', 'CONSTRAINT', 'CONTINUE', 'CONVERT', 'CREATE', 'CROSS', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'CURRENT_USER', 'CURSOR', 'DATABASE', 'DATABASES', 'DAY_HOUR', 'DAY_MICROSECOND', 'DAY_MINUTE', 'DAY_SECOND', 'DEC', 'DECIMAL', 'DECLARE', 'DEFAULT', 'DELAYED', 'DELETE', 'DESC', 'DESCRIBE', 'DETERMINISTIC', 'DISTINCT', 'DISTINCTROW', 'DIV', 'DOUBLE', 'DROP', 'DUAL', 'EACH', 'ELSE', 'ELSEIF', 'ENCLOSED', 'ESCAPED', 'EXISTS', 'EXIT', 'EXPLAIN', 'FALSE', 'FETCH', 'FLOAT', 'FLOAT4', 'FLOAT8', 'FOR', 'FORCE', 'FOREIGN', 'FROM', 'FULLTEXT', 'GRANT', 'GROUP', 'HAVING', 'HIGH_PRIORITY', 'HOUR_MICROSECOND', 'HOUR_MINUTE', 'HOUR_SECOND', 'IF', 'IGNORE', 'IN', 'INDEX', 'INFILE', 'INNER', 'INOUT', 'INSENSITIVE', 'INSERT', 'INT', 'INT1', 'INT2', 'INT3', 'INT4', 'INT8', 'INTEGER', 'INTERVAL', 'INTO', 'IS', 'ITERATE', 'JOIN', 'KEY', 'KEYS', 'KILL', 'LEADING', 'LEAVE', 'LEFT', 'LIKE', 'LIMIT', 'LINEAR', 'LINES', 'LOAD', 'LOCALTIME', 'LOCALTIMESTAMP', 'LOCK', 'LONG', 'LONGBLOB', 'LONGTEXT', 'LOOP', 'LOW_PRIORITY', 'MASTER_SSL_VERIFY_SERVER_CERT', 'MATCH', 'MEDIUMBLOB', 'MEDIUMINT', 'MEDIUMTEXT', 'MIDDLEINT', 'MINUTE_MICROSECOND', 'MINUTE_SECOND', 'MOD', 'MODIFIES', 'NATURAL', 'NOT', 'NO_WRITE_TO_BINLOG', 'NULL', 'NUMERIC', 'ON', 'OPTIMIZE', 'OPTION', 'OPTIONALLY', 'OR', 'ORDER', 'OUT', 'OUTER', 'OUTFILE', 'PRECISION', 'PRIMARY', 'PROCEDURE', 'PURGE', 'RANGE', 'READ', 'READS', 'READ_WRITE', 'REAL', 'REFERENCES', 'REGEXP', 'RELEASE', 'RENAME', 'REPEAT', 'REPLACE', 'REQUIRE', 'RESTRICT', 'RETURN', 'REVOKE', 'RIGHT', 'RLIKE', 'SCHEMA', 'SCHEMAS', 'SECOND_MICROSECOND', 'SELECT', 'SENSITIVE', 'SEPARATOR', 'SET', 'SHOW', 'SMALLINT', 'SPATIAL', 'SPECIFIC', 'SQL', 'SQLEXCEPTION', 'SQLSTATE', 'SQLWARNING', 'SQL_BIG_RESULT', 'SQL_CALC_FOUND_ROWS', 'SQL_SMALL_RESULT', 'SSL', 'STARTING', 'STRAIGHT_JOIN', 'TABLE', 'TERMINATED', 'THEN', 'TINYBLOB', 'TINYINT', 'TINYTEXT', 'TO', 'TRAILING', 'TRIGGER', 'TRUE', 'UNDO', 'UNION', 'UNIQUE', 'UNLOCK', 'UNSIGNED', 'UPDATE', 'USAGE', 'USE', 'USING', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'VALUES', 'VARBINARY', 'VARCHAR', 'VARCHARACTER', 'VARYING', 'WHEN', 'WHERE', 'WHILE', 'WITH', 'WRITE', 'XOR', 'YEAR_MONTH', 'ZEROFILL', 'ACCESSIBLE', 'LINEAR', 'MASTER_SSL_VERIFY_SERVER_CERT', 'RANGE', 'READ_ONLY', 'READ_WRITE', ); private $numberFunctions = array( 'ABS', 'ACOS', 'ASIN', 'ATAN2', 'ATAN', 'CEIL', 'CEILING', 'CONV', 'COS', 'COT', 'CRC32', 'DEGREES', 'EXP', 'FLOOR', 'LN', 'LOG10', 'LOG2', 'LOG', 'MOD', 'PI', 'POW', 'POWER', 'RADIANS', 'RAND', 'ROUND', 'SIGN', 'SIN', 'SQRT', 'TAN', 'TRUNCATE', ); private $charFunctions = array( 'ASCII_SYM', 'BIN', 'BIT_LENGTH', 'CHAR_LENGTH', 'CHAR', 'CONCAT_WS', 'CONCAT', 'ELT', 'EXPORT_SET', 'FIELD', 'FIND_IN_SET', 'FORMAT', 'FROM_BASE64', 'HEX', 'INSERT', 'INSTR', 'LEFT', 'LENGTH', 'LOAD_FILE', 'LOCATE', 'LOWER', 'LPAD', 'LTRIM', 'MAKE_SET', 'MID', 'OCT', 'ORD', 'QUOTE', 'REPEAT', 'REPLACE', 'REVERSE', 'RIGHT', 'RPAD', 'RTRIM', 'SOUNDEX', 'SPACE', 'STRCMP', 'SUBSTRING_INDEX', 'SUBSTRING', 'TO_BASE64', 'TRIM', 'UNHEX', 'UPPER', 'WEIGHT_STRING', ); private $timeFunctions = array( 'ADDDATE', 'ADDTIME', 'CONVERT_TZ', 'CURDATE', 'CURTIME', 'DATE_ADD', 'DATE_FORMAT', 'DATE_SUB', 'DATE_SYM', 'DATEDIFF', 'DAYNAME', 'DAYOFMONTH', 'DAYOFWEEK', 'DAYOFYEAR', 'EXTRACT', 'FROM_DAYS', 'FROM_UNIXTIME', 'GET_FORMAT', 'HOUR', 'LAST_DAY ', 'MAKEDATE', 'MAKETIME ', 'MICROSECOND', 'MINUTE', 'MONTH', 'MONTHNAME', 'NOW', 'PERIOD_ADD', 'PERIOD_DIFF', 'QUARTER', 'SEC_TO_TIME', 'SECOND', 'STR_TO_DATE', 'SUBTIME', 'SYSDATE', 'TIME_FORMAT', 'TIME_TO_SEC', 'TIME_SYM', 'TIMEDIFF', 'TIMESTAMP', 'TIMESTAMPADD', 'TIMESTAMPDIFF', 'TO_DAYS', 'TO_SECONDS', 'UNIX_TIMESTAMP', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'WEEK', 'WEEKDAY', 'WEEKOFYEAR', 'YEAR', 'YEARWEEK', ); private $otherFunctions = array( 'MAKE_SET', 'LOAD_FILE', 'IF', 'IFNULL', 'AES_ENCRYPT', 'AES_DECRYPT', 'DECODE', 'ENCODE', 'DES_DECRYPT', 'DES_ENCRYPT', 'ENCRYPT', 'MD5', 'OLD_PASSWORD', 'PASSWORD', 'BENCHMARK', 'CHARSET', 'COERCIBILITY', 'COLLATION', 'CONNECTION_ID', 'CURRENT_USER', 'DATABASE', 'SCHEMA', 'USER', 'SESSION_USER', 'SYSTEM_USER', 'VERSION_SYM', 'FOUND_ROWS', 'LAST_INSERT_ID', 'DEFAULT', 'GET_LOCK', 'RELEASE_LOCK', 'IS_FREE_LOCK', 'IS_USED_LOCK', 'MASTER_POS_WAIT', 'INET_ATON', 'INET_NTOA', 'NAME_CONST', 'SLEEP', 'UUID', 'VALUES', ); private $groupFunctions = array( 'AVG', 'COUNT', 'MAX_SYM', 'MIN_SYM', 'SUM', 'BIT_AND', 'BIT_OR', 'BIT_XOR', 'GROUP_CONCAT', 'STD', 'STDDEV', 'STDDEV_POP', 'STDDEV_SAMP', 'VAR_POP', 'VAR_SAMP', 'VARIANCE', ); /** * @param wfWAFSQLiLexer $lexer * @param string $subject * @param int $flags */ public function __construct($lexer, $subject = null, $flags = 0) { parent::__construct($lexer); $this->setSubject($subject); $this->setFlags($flags); } protected function _init() { $this->portableCommentVersions = array(); $this->index = -1; } /** * @param int $num * @return bool */ public function hasMoreThanNumTokens($num) { $this->_init(); $savePoint = $this->index; for ($i = 0; $i <= $num; $i++) { if (!$this->nextToken()) { $this->index = $savePoint; return false; } } $this->index = $savePoint; return true; } /** * @return bool */ public function evaluate() { try { $this->parse(); return true; } catch (wfWAFParserSyntaxError $e) { return false; } } public function parse() { $this->_init(); if ( $this->parseSelectStatement() || $this->parseInsertStatement() || $this->parseUpdateStatement() // || $this->parseDeleteStatement() // || $this->parseReplaceStatement() ) { $token = $this->nextToken(); if ($token && !$this->isTokenOfType($token, wfWAFSQLiLexer::SEMICOLON)) { $this->triggerSyntaxError($this->currentToken()); } } else { $this->triggerSyntaxError($this->expectNextToken()); } } /** * @param int $index * @return bool */ protected function getToken($index) { if (array_key_exists($index, $this->tokens)) { return $this->tokens[$index]; } while ($token = $this->getLexer()->nextToken()) { if (!$this->isCommentToken($token)) { $this->tokens[$index] = $token; return $this->tokens[$index]; } } return false; } /** * @param wfWAFLexerToken $token * @return bool */ public function isCommentToken($token) { if ($this->isTokenOfType($token, wfWAFSQLiLexer::MYSQL_PORTABLE_COMMENT_START)) { $this->portableCommentVersions[(int) preg_replace('/[^\d]/', '', $token->getValue())] = 1; } return $this->isTokenOfType($token, array( wfWAFSQLiLexer::SINGLE_LINE_COMMENT, wfWAFSQLiLexer::MULTI_LINE_COMMENT, wfWAFSQLiLexer::MYSQL_PORTABLE_COMMENT_START, wfWAFSQLiLexer::MYSQL_PORTABLE_COMMENT_END, )); } public function hasMultiplePortableCommentVersions() { return count($this->portableCommentVersions) > 1; } /** * Expects the next token to be an identifier with the supplied case-insensitive value * * @param $keyword * @return wfWAFLexerToken * @throws wfWAFParserSyntaxError */ protected function expectNextIdentifierEquals($keyword) { $nextToken = $this->expectNextToken(); $this->expectTokenTypeEquals($nextToken, wfWAFSQLiLexer::UNQUOTED_IDENTIFIER); if ($nextToken->getLowerCaseValue() !== wfWAFUtils::strtolower($keyword)) { $this->triggerSyntaxError($nextToken); } return $nextToken; } private function parseSelectStatement() { $startIndex = $this->index; $hasSelect = false; while ($this->parseSelectExpression()) { $hasSelect = true; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'union')) { $hasSelect = false; if (!$this->isIdentifierWithValue($this->nextToken(), 'all')) { $this->index--; } continue; } $this->index = $savePoint; break; } if ($hasSelect) { return true; } $this->index = $startIndex; return false; } private function parseSelectExpression() { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parseSelectExpression() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; if ($this->parseSelect()) { if ($this->parseFrom()) { $this->parseWhere(); $this->parseProcedure(); $this->parseGroupBy(); $this->parseHaving(); } $this->parseOrderBy(); $this->parseLimit(); return true; } return false; } /** * @throws wfWAFParserSyntaxError */ private function parseSelect() { $startPoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'select')) { $optionalSelectParamsRegex = '/ALL|DISTINCT(?:ROW)?|HIGH_PRIORITY|MAX_STATEMENT_TIME|STRAIGHT_JOIN|SQL_SMALL_RESULT|SQL_BIG_RESULT|SQL_BUFFER_RESULT|SQL_CACHE|SQL_NO_CACHE|SQL_CALC_FOUND_ROWS/i'; while (true) { $savePoint = $this->index; $token = $this->nextToken(); if ($token) { $value = $token->getLowerCaseValue(); if (preg_match($optionalSelectParamsRegex, $value)) { if ($value == 'max_statement_time') { $this->expectTokenTypeEquals($this->expectNextToken(), wfWAFSQLiLexer::EQUALS_SYMBOL); $this->expectTokenTypeInArray($this->expectNextToken(), array( wfWAFSQLiLexer::INTEGER_LITERAL, wfWAFSQLiLexer::BINARY_NUMBER_LITERAL, wfWAFSQLiLexer::HEX_NUMBER_LITERAL, wfWAFSQLiLexer::BINARY_NUMBER_LITERAL, )); } continue; } } $this->index = $savePoint; break; } return $this->parseSelectList(); } $this->index = $startPoint; return false; } /** * @throws wfWAFParserSyntaxError */ private function parseSelectList() { $startPoint = $this->index; $hasSelects = false; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::ASTERISK)) { $hasSelects = true; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { // Just SELECT * [FROM ...] $this->index--; return true; } } else { $this->index = $startPoint; } while ($this->parseDisplayedColumn()) { $hasSelects = true; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index--; break; } if ($hasSelects) { return true; } $this->index = $startPoint; return false; } private function parseDisplayedColumn() { /* ( table_spec DOT ASTERISK ) | ( column_spec (alias)? ) | ( bit_expr (alias)? ) */ $savePoint = $this->index; if ($this->parseTableSpec() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::DOT) && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::ASTERISK) ) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->parseExpression()) { $this->parseAlias(); return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->parseColumnSpec()) { $this->parseAlias(); return true; } $this->index = $savePoint; return false; } /** * @return bool */ private function parseExpressionList() { $startIndex = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS)) { $hasExpressions = false; while ($this->parseExpression()) { $hasExpressions = true; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index--; break; } if ($hasExpressions && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $startIndex; return false; } private function parseExpression() { // Combines these: // exp_factor3 ( AND_SYM exp_factor3 )* ; // expression: exp_factor1 ( OR_SYM exp_factor1 )* ; // exp_factor1: exp_factor2 ( XOR exp_factor2 )* ; // exp_factor2: exp_factor3 ( AND_SYM exp_factor3 )* ; $savePoint = $this->index; $hasExpression = false; while ($this->parseExpressionFactor3()) { $hasExpression = true; $savePoint2 = $this->index; $token = $this->nextToken(); if ($this->isOrToken($token) || $this->isAndToken($token) || $this->isIdentifierWithValue($token, 'xor')) { continue; } $this->index = $savePoint2; break; } if ($hasExpression) { return true; } $this->index = $savePoint; return false; } private function parseExpressionFactor3() { // (NOT_SYM)? exp_factor4 ; $savePoint = $this->index; if (!$this->isNotSymbolToken($this->nextToken())) { $this->index--; } if ($this->parseExpressionFactor4()) { return true; } $this->index = $savePoint; return false; } private function parseExpressionFactor4() { // bool_primary ( IS_SYM (NOT_SYM)? (boolean_literal|NULL_SYM) )? ; $savePoint = $this->index; if ($this->parseBoolPrimary()) { $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'is')) { if (!$this->isNotSymbolToken($this->nextToken())) { $this->index--; } if ($this->isIdentifierWithValue($this->nextToken(), array( 'true', 'false', 'null', )) ) { return true; } } $this->index = $savePoint; return true; } $this->index = $savePoint; return false; } /** * @return bool */ private function parseBoolPrimary() { $startIndex = $this->index; $token = $this->nextToken(); if ($token) { $hasNot = false; if ($this->isNotSymbolToken($token)) { $hasNot = true; $token = $this->nextToken(); } $val = $token->getLowerCaseValue(); if ($token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER) { if ($val === 'exists' && $this->parseSubquery()) { return true; } else if ($hasNot) { $this->index = $startIndex; return false; } } if (!$hasNot) { $this->index = $startIndex; } } if ($this->parsePredicate()) { $savePoint = $this->index; $opToken = $this->nextToken(); if ($opToken) { switch ($opToken->getType()) { case wfWAFSQLiLexer::EQUALS_SYMBOL: case wfWAFSQLiLexer::LESS_THAN: case wfWAFSQLiLexer::GREATER_THAN: case wfWAFSQLiLexer::LESS_THAN_EQUAL_TO: case wfWAFSQLiLexer::GREATER_THAN_EQUAL_TO: case wfWAFSQLiLexer::NOT_EQUALS: case wfWAFSQLiLexer::SET_VAR: $savePoint2 = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), array( 'any', 'all' )) && $this->parseSubquery() ) { return true; } $this->index = $savePoint2; $savePoint2 = $this->index; if ($this->testForSubquery() && $this->parseSubquery()) { return true; } $this->index = $savePoint2; if ($this->parsePredicate()) { return true; } $this->index = $startIndex; return false; } } $this->index = $savePoint; return true; } $this->index = $startIndex; return false; } private function parsePredicate() { $startIndex = $this->index; if ($this->parseBitExpression()) { $savePoint = $this->index; $token = $this->nextToken(); if ($token) { if ($hasNot = $this->isNotSymbolToken($token)) { $token = $this->nextToken(); if (!$token) { $this->index = $startIndex; return false; } } $val = $token->getLowerCaseValue(); if ($token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER) { switch ($val) { case 'in': if ($this->parseSubquery() || $this->parseExpressionList()) { return true; } break; case 'between': if ($this->parseBitExpression() && $this->isIdentifierWithValue($this->nextToken(), 'and') && $this->parsePredicate() ) { return true; } break; case 'sounds': if ($this->isIdentifierWithValue($this->nextToken(), 'like') && $this->parseBitExpression() ) { return true; } break; case 'like': case 'rlike': if ($this->parseSimpleExpression()) { // We've got a LIKE statement at this point $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'escape') && $this->parseSimpleExpression() ) { return true; } $this->index = $savePoint; return true; } break; case 'regexp': if ($this->parseBitExpression()) { return true; } break; default: if ($hasNot) { $this->index = $startIndex; return false; } break; } } } $this->index = $savePoint; return true; } $this->index = $startIndex; return false; } /** * @return bool */ private function parseBitExpression() { // factor1 ( VERTBAR factor1 )? ; $savePoint = $this->index; if ($this->parseBitExprFactor5()) { $savePoint = $this->index; $token = $this->nextToken(); if (($this->isTokenOfType($token, array( wfWAFSQLiLexer::BIT_OR, wfWAFSQLiLexer::BIT_AND, wfWAFSQLiLexer::BIT_XOR, wfWAFSQLiLexer::BIT_LEFT_SHIFT, wfWAFSQLiLexer::BIT_RIGHT_SHIFT, wfWAFSQLiLexer::BIT_INVERSION, wfWAFSQLiLexer::PLUS, wfWAFSQLiLexer::MINUS, wfWAFSQLiLexer::ASTERISK, wfWAFSQLiLexer::DIVISION, wfWAFSQLiLexer::MOD, )) || $this->isIdentifierWithValue($token, array( 'div', 'mod' ))) && $this->parseBitExpression() ) { return true; } $this->index = $savePoint; return true; } $this->index = $savePoint; return false; } private function parseBitExprFactor5() { // factor6 ( (PLUS|MINUS) interval_expr )? ; $savePoint = $this->index; if ($this->parseBitExprFactor6()) { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), array( wfWAFSQLiLexer::PLUS, wfWAFSQLiLexer::MINUS, )) && $this->parseIntervalExpression() ) { return true; } $this->index = $savePoint; return true; } $this->index = $savePoint; return false; } private function parseBitExprFactor6() { // (PLUS | MINUS | NEGATION | BINARY) simple_expr // | simple_expr ; $startPoint = $this->index; $savePoint = $this->index; while ( ($token = $this->nextToken()) && ( $this->isTokenOfType($token, array( wfWAFSQLiLexer::PLUS, wfWAFSQLiLexer::MINUS, )) || ($this->isTokenOfType($token, wfWAFSQLiLexer::BIT_INVERSION)) || ($this->isIdentifierWithValue($token, 'BINARY')) ) ) { $savePoint = $this->index; } $this->index = $savePoint; if ($this->parseSimpleExpression()) { return true; } $this->index = $startPoint; return false; } /** * literal_value * | column_spec * | function_call * | USER_VAR * | expression_list * | (ROW_SYM expression_list) * | subquery * | EXISTS subquery * | {identifier expr} * | match_against_statement * | case_when_statement * | interval_expr * * @return bool */ private function parseSimpleExpression() { $startPoint = $this->index; $simple = ($parseLiteral = $this->parseLiteral()) || ($parseMatchAgainst = $this->parseMatchAgainst()) || ($parseFunctionCall = $this->parseFunctionCall()) || ($parseVariable = $this->parseVariable()) || ($parseExpressionList = $this->parseExpressionList()) || ($parseSubquery = $this->parseSubquery()) || ($parseExistsSubquery = $this->parseExistsSubquery()) || ($parseCaseWhen = $this->parseCaseWhen()) || ($parseODBCExpression = $this->parseODBCExpression()) || ($parseIntervalExpression = $this->parseIntervalExpression()) || ($parseColumnSpec = $this->parseColumnSpec()); if ($simple) { $token = $this->nextToken(); if ($token && $token->getLowerCaseValue() == 'collate') { $savePoint = $this->index; if ($this->parseCollationName()) { return true; } $this->index = $savePoint; } else { $this->index--; } return true; } $this->index = $startPoint; return false; } /** * @return bool */ private function parseLiteral() { $startIndex = $this->index; $savePoint = $this->index; while ($this->isTokenOfType($this->nextToken(), array( wfWAFSQLiLexer::PLUS, wfWAFSQLiLexer::MINUS, ))) { $savePoint = $this->index; } $this->index = $savePoint; $nextToken = $this->nextToken(); if ($nextToken) { switch ($nextToken->getType()) { case wfWAFSQLiLexer::INTEGER_LITERAL: case wfWAFSQLiLexer::BINARY_NUMBER_LITERAL: case wfWAFSQLiLexer::HEX_NUMBER_LITERAL: case wfWAFSQLiLexer::REAL_NUMBER_LITERAL: return true; // Allow concatenation: 'test' 'test' is valid case wfWAFSQLiLexer::DOUBLE_STRING_LITERAL: case wfWAFSQLiLexer::SINGLE_STRING_LITERAL: $savePoint = $this->index; while ($this->isTokenOfType($this->nextToken(), array( wfWAFSQLiLexer::DOUBLE_STRING_LITERAL, wfWAFSQLiLexer::SINGLE_STRING_LITERAL ))) { $savePoint = $this->index; } $this->index = $savePoint; return true; case wfWAFSQLiLexer::UNQUOTED_IDENTIFIER: if ($nextToken->getLowerCaseValue() === 'null') { return true; } break; } } $this->index = $startIndex; return false; } /** * @return bool */ private function parseColumnSpec() { $savePoint = $this->index; if ($this->parseTableSpec()) { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::DOT)) { $nextToken = $this->nextToken(); if ($nextToken && ($nextToken->getType() == wfWAFSQLiLexer::UNQUOTED_IDENTIFIER || $nextToken->getType() == wfWAFSQLiLexer::QUOTED_IDENTIFIER) ) { return true; } $this->index = $savePoint; return false; } $this->index = $savePoint; return true; } $this->index = $savePoint; return false; } /** * CAST_SYM LPAREN expression AS_SYM cast_data_type RPAREN ) * | ( CONVERT_SYM LPAREN expression COMMA cast_data_type RPAREN ) * | ( CONVERT_SYM LPAREN expression USING_SYM transcoding_name RPAREN ) * | ( group_functions LPAREN ( ASTERISK | ALL | DISTINCT )? bit_expr RPAREN ) * * @return bool */ private function parseFunctionCall() { $startPoint = $this->index; $functionToken = $this->nextToken(); if ($functionToken && $functionToken->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER) { if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS)) { switch ($functionToken->getLowerCaseValue()) { case 'cast': if ($this->parseExpression() && $this->isIdentifierWithValue($this->nextToken(), 'as') && $this->parseCastDataType() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } break; case 'convert': if ($this->parseExpression()) { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA) && $this->parseCastDataType() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'using') && $this->parseTranscodingName() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; } break; default: $savePoint = $this->index; if (in_array($functionToken->getUpperCaseValue(), $this->groupFunctions)) { $token = $this->nextToken(); if (!$this->isIdentifierWithValue($token, array( 'all', 'distinct', )) && !$this->isTokenOfType($token, wfWAFSQLiLexer::ASTERISK) ) { $this->index--; } $this->parseBitExpression(); if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $savePoint; while ($this->parseExpression()) { if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index--; break; } if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } break; } } } $this->index = $startPoint; return false; } /** * BINARY (INTEGER_NUM)? * | CHAR (INTEGER_NUM)? * | DATE_SYM * | DATETIME * | DECIMAL_SYM ( INTEGER_NUM (COMMA INTEGER_NUM)? )? * | SIGNED_SYM (INTEGER_SYM)? * | TIME_SYM * | UNSIGNED_SYM (INTEGER_SYM)? * * @return bool */ private function parseCastDataType() { $startPoint = $this->index; $token = $this->nextToken(); if ($this->isKeywordToken($token)) { switch ($token->getLowerCaseValue()) { case 'binary': case 'char': $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::INTEGER_LITERAL)) { return true; } $this->index = $savePoint; return true; case 'date': case 'datetime': case 'time': return true; case 'signed': case 'unsigned': if (!$this->isIdentifierWithValue($this->nextToken(), 'integer')) { $this->index--; } return true; case 'decimal': $savePoint = $this->index; while ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::INTEGER_LITERAL)) { if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index--; return true; } $this->index = $savePoint; return true; } } $this->index = $startPoint; return false; } private function parseTranscodingName() { $savePoint = $this->index; $token = $this->nextToken(); if ($token && $token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER) { return false; } $this->index = $savePoint; return false; } private function parseVariable() { $nextToken = $this->nextToken(); if ($nextToken && $nextToken->getType() === wfWAFSQLiLexer::VARIABLE) { return true; } $this->index--; return false; } /** * @return bool */ private function parseSubquery() { $startIndex = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parseSelectStatement() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $startIndex; return false; } private function testForSubquery() { $startIndex = $this->index; $nextToken = $this->nextToken(); if ($nextToken && $nextToken->getType() === wfWAFSQLiLexer::OPEN_PARENTHESIS) { $selectToken = $this->nextToken(); if ($this->isIdentifierWithValue($selectToken, 'select')) { $this->index = $startIndex; return true; } } $this->index = $startIndex; return false; } /** * * * @return bool */ private function parseExistsSubquery() { $startIndex = $this->index; $existsToken = $this->nextToken(); if ($this->isIdentifierWithValue($existsToken, 'exists')) { if ($this->parseSubquery()) { return true; } } $this->index = $startIndex; return false; } /** * MATCH (column_spec (COMMA column_spec)* ) AGAINST (expression (search_modifier)? ) * * @return bool */ private function parseMatchAgainst() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'match')) { $savePoint = $this->index; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS)) { $this->index = $savePoint; } $hasColumns = false; while ($this->parseColumnSpec()) { $hasColumns = true; $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index = $savePoint; break; } $savePoint = $this->index; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { $this->index = $savePoint; } if ($hasColumns && $this->isIdentifierWithValue($this->nextToken(), 'against') && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parseExpression() && ($this->parseSearchModifier() || true) && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } } $this->index = $startIndex; return false; } /** * Used in match/against * * @link https://dev.mysql.com/doc/refman/5.6/en/fulltext-search.html * @return bool */ private function parseSearchModifier() { $startIndex = $this->index; $startToken = $this->nextToken(); if ($this->isIdentifierWithValue($startToken, 'in')) { $next = $this->nextToken(); if ($this->isIdentifierWithValue($next, 'natural') && $this->isIdentifierWithValue($this->nextToken(), 'language') && $this->isIdentifierWithValue($this->nextToken(), 'mode') ) { $saveIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'with') && $this->isIdentifierWithValue($this->nextToken(), 'query') && $this->isIdentifierWithValue($this->nextToken(), 'expansion') ) { return true; } $this->index = $saveIndex; return true; } else if ($this->isIdentifierWithValue($next, 'boolean') && $this->isIdentifierWithValue($this->nextToken(), 'mode') ) { return true; } } else if ($this->isIdentifierWithValue($startToken, 'with')) { if ($this->isIdentifierWithValue($this->nextToken(), 'query') && $this->isIdentifierWithValue($this->nextToken(), 'expansion') ) { return true; } } $this->index = $startIndex; return false; } /** * @return bool */ private function parseCaseWhen() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'case')) { $hasWhen = false; while (true) { if (!$this->isIdentifierWithValue($this->nextToken(), 'when')) { $this->index--; break; } if ($this->parseExpression()) { if ($this->isIdentifierWithValue($this->nextToken(), 'then') && $this->parseBitExpression()) { $hasWhen = true; continue; } $this->index--; } $this->index--; break; } if ($hasWhen) { $endToken = $this->nextToken(); if ($this->isIdentifierWithValue($endToken, 'else')) { if (!$this->parseBitExpression()) { $this->index = $startIndex; return false; } $endToken = $this->nextToken(); } if ($this->isIdentifierWithValue($endToken, 'end')) { return true; } } } $this->index = $startIndex; return false; } /** * @return bool */ private function parseODBCExpression() { $startIndex = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_BRACKET) && $this->isIdentifier($this->nextToken()) && $this->parseExpression() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_BRACKET)) { return true; } $this->index = $startIndex; return false; } /** * @return bool */ private function parseIntervalExpression() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'interval') && $this->parseExpression()) { $intervalUnitToken = $this->nextToken(); if ($intervalUnitToken && in_array($intervalUnitToken->getType(), $this->intervalUnits)) { return true; } } $this->index = $startIndex; return false; } /** * @return bool */ public function parseCollationName() { $startIndex = $this->index; $token = $this->nextToken(); if ($token && $token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER) { return true; } $this->index = $startIndex; return false; } /** * @return bool */ private function parseFrom() { $startIndex = $this->index; $token = $this->nextToken(); if ($this->isIdentifierWithValue($token, 'from')) { return $this->parseTableReferences(); } $this->index = $startIndex; return false; } /** * @link http://dev.mysql.com/doc/refman/5.6/en/join.html * @return bool */ private function parseTableReferences() { $startPoint = $this->index; $hasReferences = false; while ($this->parseEscapedTableReference()) { $hasReferences = true; $savePoint = $this->index; $token = $this->nextToken(); if ($this->isTokenOfType($token, wfWAFSQLiLexer::COMMA)) { continue; } $this->index = $savePoint; break; } if ($hasReferences) { return true; } $this->index = $startPoint; return false; } /** * @return bool */ private function parseEscapedTableReference() { $startPoint = $this->index; if ($this->parseTableReference() || ( $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_BRACKET) && $this->isIdentifierWithValue($this->nextToken(), 'oj') && $this->parseTableReference() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_BRACKET) ) ) { return true; } $this->index = $startPoint; return false; } /** * @return bool */ private function parseTableReference() { $savePoint = $this->index; $hasTables = false; if ($this->parseTableFactor()) { $hasTables = true; while ($this->parseJoinTable()) { } } if ($hasTables) { return true; } $this->index = $savePoint; return false; } /** * table_factor: * tbl_name [PARTITION (partition_names)] [[AS] alias] [index_hint_list] * | table_subquery [AS] alias * | ( table_references ) */ private function parseTableFactor() { $savePoint = $this->index; if ($this->parseTableSpec()) { $savePoint2 = $this->index; if (!$this->parsePartitionClause()) { $this->index = $savePoint2; } $this->parseAlias(); $this->parseIndexHintList(); return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->parseSubquery() && $this->parseAlias()) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parseTableReferences() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; return false; } /** * PARTITION (partition_names) * * @return bool */ private function parsePartitionClause() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'partition') && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parsePartitionNames() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $startIndex; return false; } /** * @return bool */ private function parsePartitionNames() { $startPoint = $this->index; $hasPartition = false; while ($this->parsePartitionName()) { $hasPartition = true; $savePoint = $this->index; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $this->index = $savePoint; break; } } if ($hasPartition) { return true; } $this->index = $startPoint; return false; } /** * @return bool */ private function parsePartitionName() { $startPoint = $this->index; $token = $this->nextToken(); if ($this->isTokenOfType($token, wfWAFSQLiLexer::QUOTED_IDENTIFIER) || $this->isValidNonKeywordIdentifier($token) ) { return true; } $this->index = $startPoint; return false; } /** * join_table: * table_reference [INNER | CROSS] JOIN table_factor [join_condition] * | table_reference STRAIGHT_JOIN table_factor * | table_reference STRAIGHT_JOIN table_factor ON conditional_expr * | table_reference {LEFT|RIGHT} [OUTER] JOIN table_reference join_condition * | table_reference NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factor * * @return bool */ private function parseJoinTable() { $savePoint = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), array( 'inner', 'cross', )) ) { $this->index = $savePoint; } if ($this->isIdentifierWithValue($this->nextToken(), 'join') && $this->parseTableFactor()) { $this->parseJoinCondition(); return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'straight_join') && $this->parseTableFactor() ) { $savePoint = $this->index; if (!($this->isIdentifierWithValue($this->nextToken(), 'on') && $this->parseExpression())) { $this->index = $savePoint; } return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), array( 'left', 'right', )) ) { $savePoint2 = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), array( 'outer', )) ) { $this->index = $savePoint2; } } else { $this->index = $savePoint; } if ($this->isIdentifierWithValue($this->nextToken(), 'join') && $this->parseTableReference() && $this->parseJoinCondition() ) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), array( 'natural', )) ) { if ($this->isIdentifierWithValue($this->nextToken(), array( 'left', 'right', )) ) { $savePoint2 = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), array( 'outer', )) ) { $this->index = $savePoint2; } } else { $this->index = $savePoint; } if ($this->isIdentifierWithValue($this->nextToken(), 'join') && $this->parseTableFactor() ) { return true; } } $this->index = $savePoint; return false; } /** * (ON expression) | (USING_SYM column_list) * * @return bool */ private function parseJoinCondition() { $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'on') && $this->parseExpression()) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'using') && $this->parseColumnList()) { return true; } $this->index = $savePoint; return false; } /** * @return bool */ private function parseTableSpec() { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), array( wfWAFSQLiLexer::UNQUOTED_IDENTIFIER, wfWAFSQLiLexer::QUOTED_IDENTIFIER, )) ) { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::DOT) && $this->isTokenOfType($this->nextToken(), array( wfWAFSQLiLexer::UNQUOTED_IDENTIFIER, wfWAFSQLiLexer::QUOTED_IDENTIFIER, )) ) { return true; } $this->index = $savePoint; return true; } $this->index = $savePoint; return false; } /** * @return bool */ private function parseAlias() { $savePoint = $this->index; $token = $this->nextToken(); if ($this->isIdentifierWithValue($token, 'as')) { $token = $this->nextToken(); } if ($this->isValidNonKeywordIdentifier($token)) { return true; } $this->index = $savePoint; return false; } /** * @return bool */ private function parseIndexHintList() { $startPoint = $this->index; $hasHints = false; while ($this->parseIndexHint()) { $hasHints = true; $savePoint = $this->index; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $this->index = $savePoint; break; } } if ($hasHints) { return true; } $this->index = $startPoint; return false; } /** * @return bool */ private function parseIndexHint() { // USE_SYM index_options LPAREN (index_list)? RPAREN $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'use') && $this->parseIndexOptions() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) ) { $this->parseIndexList(); if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $savePoint; // IGNORE_SYM index_options LPAREN index_list RPAREN $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'ignore') && $this->parseIndexOptions() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parseIndexList() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; // FORCE_SYM index_options LPAREN index_list RPAREN $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'force') && $this->parseIndexOptions() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) && $this->parseIndexList() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; return false; } /** * (INDEX_SYM | KEY_SYM) ( FOR_SYM ((JOIN_SYM) | (ORDER_SYM BY_SYM) | (GROUP_SYM BY_SYM)) )? * * @return bool */ private function parseIndexOptions() { $savePoint = $this->index; $token = $this->nextToken(); if ($this->isIdentifierWithValue($token, 'index') || $this->isIdentifierWithValue($token, 'key') ) { $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'for')) { $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'join')) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'order') && $this->isIdentifierWithValue($this->nextToken(), 'by') ) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'group') && $this->isIdentifierWithValue($this->nextToken(), 'by') ) { return true; } $this->index = $savePoint; return true; } $this->index = $savePoint; return true; } $this->index = $savePoint; return false; } private function parseIndexList() { $startPoint = $this->index; $hasIndex = false; while ($this->parseIndexName()) { $hasIndex = true; $savePoint = $this->index; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $this->index = $savePoint; break; } } if ($hasIndex) { return true; } $this->index = $startPoint; return false; } private function parseIndexName() { $startPoint = $this->index; $token = $this->nextToken(); if ($this->isValidNonKeywordIdentifier($token)) { return true; } $this->index = $startPoint; return false; } /** * LPAREN column_spec (COMMA column_spec)* RPAREN * * @return bool */ private function parseColumnList() { $startPoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS)) { $hasColumn = false; while ($this->parseColumnSpec()) { $hasColumn = true; $savePoint = $this->index; if (!$this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $this->index = $savePoint; break; } } if ($hasColumn && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $startPoint; return false; } private function parseWhere() { $startIndex = $this->index; $token = $this->nextToken(); if ($this->isIdentifierWithValue($token, 'where')) { if ($this->parseExpression()) { return true; } } $this->index = $startIndex; return false; } private function parseProcedure() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'PROCEDURE') && $this->isIdentifierWithValue($this->nextToken(), 'ANALYSE') && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS) ) { $savePoint = $this->index; if ($this->parseExpression()) { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA) && $this->parseExpression() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS) ) { return true; } $this->index = $savePoint; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $savePoint; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $startIndex; return false; } /** * GROUP_SYM BY_SYM groupby_item (COMMA groupby_item)* (WITH ROLLUP_SYM)? * * @return bool */ private function parseGroupBy() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'group') && $this->isIdentifierWithValue($this->nextToken(), 'by') ) { $hasItems = false; while ($this->parseGroupByItem()) { $hasItems = true; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index--; break; } if ($hasItems) { $savePoint = $this->index; if (!($this->isIdentifierWithValue($this->nextToken(), 'with') && $this->isIdentifierWithValue($this->nextToken(), 'rollup')) ) { $this->index = $savePoint; } return true; } } $this->index = $startIndex; return false; } /** * column_spec | INTEGER_NUM | bit_expr ; * * @return bool */ private function parseGroupByItem() { $startIndex = $this->index; if ($this->parseBitExpression()) { return true; } $this->index = $startIndex; return false; } /** * HAVING expression * * @return bool */ private function parseHaving() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'having') && $this->parseExpression() ) { return true; } $this->index = $startIndex; return false; } /** * ORDER_SYM BY_SYM orderby_item (COMMA orderby_item)* * * @return bool */ private function parseOrderBy() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'order') && $this->isIdentifierWithValue($this->nextToken(), 'by') ) { $hasItems = false; while ($this->parseOrderByItem()) { $hasItems = true; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { continue; } $this->index--; break; } if ($hasItems) { return true; } } $this->index = $startIndex; return false; } /** * groupby_item (ASC | DESC)? ; * * @return bool */ private function parseOrderByItem() { $startIndex = $this->index; if ($this->parseGroupByItem()) { $savePoint = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), array( 'asc', 'desc', )) ) { $this->index = $savePoint; } return true; } $this->index = $startIndex; return false; } private function parseLimit() { // LIMIT ((offset COMMA)? row_count) | (row_count OFFSET_SYM offset) $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'limit') && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::INTEGER_LITERAL) ) { $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA) && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::INTEGER_LITERAL) ) { return true; } $this->index = $savePoint; $savePoint = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'offset') && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::INTEGER_LITERAL) ) { return true; } $this->index = $savePoint; return true; } $this->index = $startIndex; return false; } /** * @link http://dev.mysql.com/doc/refman/5.6/en/insert.html * @return bool */ private function parseInsertStatement() { $startIndex = $this->index; if ($this->parseInsertStatement1() || $this->parseInsertStatement2() || $this->parseInsertStatement3() ) { return true; } $this->index = $startIndex; return false; } /** * insert_header * (column_list)? * value_list_clause * ( insert_subfix )? * * @return bool */ private function parseInsertStatement1() { $startIndex = $this->index; if ($this->parseInsertHeader()) { $this->parseColumnList(); if ($this->parseValueListClause()) { $this->parseInsertSubfix(); return true; } } $this->index = $startIndex; return false; } /** * insert_header * set_columns_cluase * ( insert_subfix )? * * @return bool */ private function parseInsertStatement2() { $startIndex = $this->index; if ($this->parseInsertHeader() && $this->parseSetColumnsClause()) { $this->parseInsertSubfix(); return true; } $this->index = $startIndex; return false; } /** * insert_header * (column_list)? * select_expression * ( insert_subfix )? * * @return bool */ private function parseInsertStatement3() { $startIndex = $this->index; if ($this->parseInsertHeader()) { $this->parseColumnList(); if ($this->parseSelectStatement()) { $this->parseInsertSubfix(); return true; } } $this->index = $startIndex; return false; } /** * INSERT (LOW_PRIORITY | HIGH_PRIORITY)? (IGNORE_SYM)? * (INTO)? table_spec * (partition_clause)? * * @return bool */ private function parseInsertHeader() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'insert')) { $savePoint = $this->index; // (LOW_PRIORITY | HIGH_PRIORITY)? if (!$this->isIdentifierWithValue($this->nextToken(), array( 'LOW_PRIORITY', 'HIGH_PRIORITY' )) ) { $this->index = $savePoint; } // (IGNORE_SYM)? $savePoint = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), array( 'IGNORE' )) ) { $this->index = $savePoint; } // (INTO)? $savePoint = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), array( 'into' )) ) { $this->index = $savePoint; } // table_spec if ($this->parseTableSpec()) { $savePoint = $this->index; // (partition_clause)? if (!$this->parsePartitionClause()) { $this->index = $savePoint; } return true; } } $this->index = $startIndex; return false; } /** * (VALUES | VALUE_SYM) column_value_list (COMMA column_value_list)*; * * @return bool */ private function parseValueListClause() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), array( 'value', 'values', )) ) { $hasValues = false; while ($this->parseColumnValueList()) { $hasValues = true; $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $hasValues = false; continue; } $this->index = $savePoint; break; } if ($hasValues) { return true; } } $this->index = $startIndex; return false; } /** * LPAREN (bit_expr|DEFAULT) (COMMA (bit_expr|DEFAULT) )* RPAREN ; * * @return bool */ private function parseColumnValueList() { $startIndex = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::OPEN_PARENTHESIS)) { $hasValues = false; while (true) { $savePoint = $this->index; if (!$this->parseBitExpression() && !$this->isIdentifierWithValue($this->nextToken(), 'DEFAULT')) { $this->index = $savePoint; break; } $hasValues = true; $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $hasValues = false; continue; } $this->index = $savePoint; break; } if ($hasValues && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::CLOSE_PARENTHESIS)) { return true; } } $this->index = $startIndex; return false; } private function parseInsertSubfix() { // ON DUPLICATE_SYM KEY_SYM UPDATE column_spec EQ_SYM expression (COMMA column_spec EQ_SYM expression)* $startIndex = $this->index; if ( $this->isIdentifierWithValue($this->nextToken(), 'on') && $this->isIdentifierWithValue($this->nextToken(), 'duplicate') && $this->isIdentifierWithValue($this->nextToken(), 'key') && $this->isIdentifierWithValue($this->nextToken(), 'update') ) { $hasValues = false; while (true) { $savePoint = $this->index; if ($this->parseColumnSpec() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::EQUALS_SYMBOL) && $this->parseExpression() ) { $hasValues = true; $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $hasValues = false; continue; } $this->index = $savePoint; break; } $this->index = $savePoint; break; } if ($hasValues) { return true; } } $this->index = $startIndex; return false; } /** * SET_SYM set_column_cluase ( COMMA set_column_cluase )*; * * @return bool */ private function parseSetColumnsClause() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'set')) { $hasValues = true; while ($this->parseSetColumnClause()) { $hasValues = true; $savePoint = $this->index; if ($this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::COMMA)) { $hasValues = false; continue; } $this->index = $savePoint; break; } if ($hasValues) { return true; } } $this->index = $startIndex; return false; } /** * column_spec EQ_SYM (expression|DEFAULT) ; * * @return bool */ private function parseSetColumnClause() { $startIndex = $this->index; if ($this->parseColumnSpec() && $this->isTokenOfType($this->nextToken(), wfWAFSQLiLexer::EQUALS_SYMBOL) && ($this->parseExpression() || $this->isIdentifierWithValue($this->nextToken(), 'default')) ) { return true; } $this->index = $startIndex; return false; } /** * UPDATE (LOW_PRIORITY)? (IGNORE_SYM)? table_reference * set_columns_cluase * (where_clause)? * (orderby_clause)? * (limit_clause)? * | * UPDATE (LOW_PRIORITY)? (IGNORE_SYM)? table_references * set_columns_cluase * (where_clause)? * * @return bool */ private function parseUpdateStatement() { $startIndex = $this->index; if ($this->isIdentifierWithValue($this->nextToken(), 'update')) { $savePoint = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), 'LOW_PRIORITY')) { $this->index = $savePoint; } $savePoint = $this->index; if (!$this->isIdentifierWithValue($this->nextToken(), 'ignore')) { $this->index = $savePoint; } if ($this->parseTableReferences() && $this->parseSetColumnsClause()) { $this->parseWhere(); $this->parseOrderBy(); $this->parseLimit(); return true; } } $this->index = $startIndex; return false; } /** * @param wfWAFLexerToken $token * @return bool */ private function isIdentifier($token) { return $token && ($token->getType() === wfWAFSQLiLexer::QUOTED_IDENTIFIER || $token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER); } /** * @param wfWAFLexerToken $token * @param string|array $value * @return bool */ private function isIdentifierWithValue($token, $value) { return $token && $token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER && (is_array($value) ? in_array($token->getLowerCaseValue(), array_map('wfWAFUtils::strtolower', $value)) : $token->getLowerCaseValue() === wfWAFUtils::strtolower($value)); } /** * @param wfWAFLexerToken $token * @param mixed $type * @return bool */ protected function isTokenOfType($token, $type) { if (is_array($type)) { return $token && in_array($token->getType(), $type); } return $token && $token->getType() === $type; } /** * @param wfWAFLexerToken $token * @return bool */ private function isNotSymbolToken($token) { return $token && ( ($token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER && $token->getLowerCaseValue() === 'not') || ($token->getType() === wfWAFSQLiLexer::EXPR_NOT) ); } /** * @param wfWAFLexerToken $token * @return bool */ private function isKeywordToken($token) { return $token && $token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER && in_array($token->getUpperCaseValue(), $this->keywords); } /** * @param wfWAFLexerToken $token * @return bool */ private function isValidNonKeywordIdentifier($token) { return $token && ( $token->getType() === wfWAFSQLiLexer::QUOTED_IDENTIFIER || ($token->getType() === wfWAFSQLiLexer::UNQUOTED_IDENTIFIER && !$this->isKeywordToken($token)) ); } /** * @param wfWAFLexerToken $token * @return bool */ private function isOrToken($token) { return $token && ($this->isIdentifierWithValue($token, 'or') || $this->isTokenOfType($token, wfWAFSQLiLexer::EXPR_OR)); } /** * @param wfWAFLexerToken $token * @return bool */ private function isAndToken($token) { return $token && ($this->isIdentifierWithValue($token, 'and') || $this->isTokenOfType($token, wfWAFSQLiLexer::EXPR_AND)); } /** * @return string */ public function getSubject() { return $this->subject; } /** * @param string $subject */ public function setSubject($subject) { $this->subject = $subject; $this->setTokens(array()); $this->lexer->setSQL($this->subject); } /** * @return int */ public function getFlags() { return $this->flags; } /** * @param int $flags */ public function setFlags($flags) { $this->flags = $flags; $this->lexer->setFlags($this->flags); } } class wfWAFSQLiLexer implements wfWAFLexerInterface { const FLAG_TOKENIZE_MYSQL_PORTABLE_COMMENTS = 0x1; const UNQUOTED_IDENTIFIER = 'UNQUOTED_IDENTIFIER'; const VARIABLE = 'VARIABLE'; const QUOTED_IDENTIFIER = 'QUOTED_IDENTIFIER'; const DOUBLE_STRING_LITERAL = 'DOUBLE_STRING_LITERAL'; const SINGLE_STRING_LITERAL = 'SINGLE_STRING_LITERAL'; const INTEGER_LITERAL = 'INTEGER_LITERAL'; const REAL_NUMBER_LITERAL = 'REAL_NUMBER_LITERAL'; const BINARY_NUMBER_LITERAL = 'BINARY_NUMBER_LITERAL'; const HEX_NUMBER_LITERAL = 'HEX_NUMBER_LITERAL'; const DOT = 'DOT'; const OPEN_PARENTHESIS = 'OPEN_PARENTHESIS'; const CLOSE_PARENTHESIS = 'CLOSE_PARENTHESIS'; const OPEN_BRACKET = 'OPEN_BRACKET'; const CLOSE_BRACKET = 'CLOSE_BRACKET'; const COMMA = 'COMMA'; const EXPR_OR = 'EXPR_OR'; const EXPR_AND = 'EXPR_AND'; const EXPR_NOT = 'EXPR_NOT'; const BIT_AND = 'BIT_AND'; const BIT_LEFT_SHIFT = 'BIT_LEFT_SHIFT'; const BIT_RIGHT_SHIFT = 'BIT_RIGHT_SHIFT'; const BIT_XOR = 'BIT_XOR'; const BIT_INVERSION = 'BIT_INVERSION'; const BIT_OR = 'BIT_OR'; const PLUS = 'PLUS'; const MINUS = 'MINUS'; const ASTERISK = 'ASTERISK'; const DIVISION = 'DIVISION'; const MOD = 'MOD'; const ARROW = 'ARROW'; const EQUALS_SYMBOL = 'EQUALS_SYMBOL'; const NOT_EQUALS = 'NOT_EQUALS'; const LESS_THAN = 'LESS_THAN'; const GREATER_THAN = 'GREATER_THAN'; const LESS_THAN_EQUAL_TO = 'LESS_THAN_EQUAL_TO'; const GREATER_THAN_EQUAL_TO = 'GREATER_THAN_EQUAL_TO'; const SET_VAR = 'SET_VAR'; const RIGHT_BRACKET = 'RIGHT_BRACKET'; const LEFT_BRACKET = 'LEFT_BRACKET'; const SEMICOLON = 'SEMICOLON'; const COLON = 'COLON'; const MYSQL_PORTABLE_COMMENT_START = 'MYSQL_PORTABLE_COMMENT_START'; const MYSQL_PORTABLE_COMMENT_END = 'MYSQL_PORTABLE_COMMENT_END'; const SINGLE_LINE_COMMENT = 'SINGLE_LINE_COMMENT'; const MULTI_LINE_COMMENT = 'MULTI_LINE_COMMENT'; /** * @var int */ private $flags; private $tokenMatchers; private $hasPortableCommentStart = false; public static function getLexerTokenMatchers() { static $tokenMatchers; if ($tokenMatchers === null) { $tokenMatchers = array( new wfWAFLexerTokenMatcher(self::REAL_NUMBER_LITERAL, '/^(?:[0-9]+\\.[0-9]+|[0-9]+\\.|\\.[0-9]+|[Ee][\\+\\-][0-9]+)/'), new wfWAFLexerTokenMatcher(self::BINARY_NUMBER_LITERAL, '/^(?:0b[01]+|[bB]\'[01]+\')/', true), new wfWAFLexerTokenMatcher(self::HEX_NUMBER_LITERAL, '/^(?:0x[0-9a-fA-F]+|[xX]\'[0-9a-fA-F]+\')/', true), new wfWAFLexerTokenMatcher(self::INTEGER_LITERAL, '/^[0-9]+/', true), new wfWAFLexerTokenMatcher(self::VARIABLE, '/^(?:@(?:`(?:[^`]*(?:``[^`]*)*)`| "([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"| \'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'| [a-zA-Z_\\$\\.]+| @[a-zA-Z_\\$][a-zA-Z_\\$0-9]{0,256}){0,1}) /Asx'), new wfWAFLexerTokenMatcher(self::QUOTED_IDENTIFIER, '/^`(?:[^`]*(?:``[^`]*)*)`/As'), new wfWAFLexerTokenMatcher(self::DOUBLE_STRING_LITERAL, '/^(?:[nN]|_[0-9a-zA-Z\\$_]{0,256})?"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"/As'), new wfWAFLexerTokenMatcher(self::SINGLE_STRING_LITERAL, '/^(?:[nN]|_[0-9a-zA-Z\\$_]{0,256})?\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'), // U+0080 .. U+FFFF new wfWAFLexerTokenMatcher(self::UNQUOTED_IDENTIFIER, '/^[0-9a-zA-Z\\$_\\x{0080}-\\x{FFFF}]{1,256}/u'), new wfWAFLexerTokenMatcher(self::MYSQL_PORTABLE_COMMENT_START, '/^\\/\\*\\![0-9]{0,5}/s'), new wfWAFLexerTokenMatcher(self::MYSQL_PORTABLE_COMMENT_END, '/^\\*\\//s'), new wfWAFLexerTokenMatcher(self::SINGLE_LINE_COMMENT, '/^(?:#[^\n]*|--(?:[ \t\r][^\n]*|[\n]))/'), new wfWAFLexerTokenMatcher(self::MULTI_LINE_COMMENT, '/^\\/\\*.*?\\*\\//s'), new wfWAFLexerTokenMatcher(self::DOT, '/^\\./'), new wfWAFLexerTokenMatcher(self::OPEN_PARENTHESIS, '/^\\(/'), new wfWAFLexerTokenMatcher(self::CLOSE_PARENTHESIS, '/^\\)/'), new wfWAFLexerTokenMatcher(self::OPEN_BRACKET, '/^\\{/'), new wfWAFLexerTokenMatcher(self::CLOSE_BRACKET, '/^\\}/'), new wfWAFLexerTokenMatcher(self::COMMA, '/^,/'), new wfWAFLexerTokenMatcher(self::EXPR_OR, '/^\\|\\|/'), new wfWAFLexerTokenMatcher(self::EXPR_AND, '/^&&/'), new wfWAFLexerTokenMatcher(self::BIT_LEFT_SHIFT, '/^\\<\\\\>/'), new wfWAFLexerTokenMatcher(self::EQUALS_SYMBOL, '/^(?:\\=|\\<\\=\\>)/'), new wfWAFLexerTokenMatcher(self::ARROW, '/^\\=\\>/'), new wfWAFLexerTokenMatcher(self::LESS_THAN_EQUAL_TO, '/^\\<\\=/'), new wfWAFLexerTokenMatcher(self::GREATER_THAN_EQUAL_TO, '/^\\>\\=/'), new wfWAFLexerTokenMatcher(self::NOT_EQUALS, '/^(?:\\<\\>|(?:\\!|\\~|\\^)\\=)/'), new wfWAFLexerTokenMatcher(self::LESS_THAN, '/^\\/'), new wfWAFLexerTokenMatcher(self::SET_VAR, '/^:\\=/'), new wfWAFLexerTokenMatcher(self::BIT_XOR, '/^\\^/'), new wfWAFLexerTokenMatcher(self::BIT_INVERSION, '/^\\~/'), new wfWAFLexerTokenMatcher(self::BIT_OR, '/^\\|/'), new wfWAFLexerTokenMatcher(self::PLUS, '/^\\+/'), new wfWAFLexerTokenMatcher(self::MINUS, '/^\\-/'), new wfWAFLexerTokenMatcher(self::ASTERISK, '/^\\*/'), new wfWAFLexerTokenMatcher(self::DIVISION, '/^\\//'), new wfWAFLexerTokenMatcher(self::MOD, '/^%/'), new wfWAFLexerTokenMatcher(self::EXPR_NOT, '/^\\!/'), new wfWAFLexerTokenMatcher(self::BIT_AND, '/^&/'), new wfWAFLexerTokenMatcher(self::RIGHT_BRACKET, '/^\\]/'), new wfWAFLexerTokenMatcher(self::LEFT_BRACKET, '/^\\[/'), new wfWAFLexerTokenMatcher(self::SEMICOLON, '/^;/'), new wfWAFLexerTokenMatcher(self::COLON, '/^:/'), ); } return $tokenMatchers; } /** * @var string */ private $sql; /** * @var wfWAFStringScanner */ private $scanner; /** * wfWAFRuleLexer constructor. * @param $sql * @param int $flags */ public function __construct($sql = null, $flags = 0) { $this->scanner = new wfWAFStringScanner(); $this->tokenMatchers = self::getLexerTokenMatchers(); $this->setSQL($sql); $this->setFlags($flags); } /** * @return array * @throws wfWAFParserSyntaxError */ public function tokenize() { $tokens = array(); while ($token = $this->nextToken()) { $tokens[] = $token; } return $tokens; } /** * @return bool|wfWAFLexerToken * @throws wfWAFParserSyntaxError */ public function nextToken() { if (!$this->scanner->eos()) { /** @var wfWAFLexerTokenMatcher $tokenMatcher */ foreach ($this->tokenMatchers as $tokenMatcher) { $this->scanner->skip('/^\s+/s'); if ($this->scanner->eos()) { return false; } if (($this->flags & self::FLAG_TOKENIZE_MYSQL_PORTABLE_COMMENTS) === 0 && ($tokenMatcher->getTokenID() === self::MYSQL_PORTABLE_COMMENT_START || $tokenMatcher->getTokenID() === self::MYSQL_PORTABLE_COMMENT_END) ) { continue; } if (!$this->hasPortableCommentStart && $tokenMatcher->getTokenID() === self::MYSQL_PORTABLE_COMMENT_END) { continue; } if ($tokenMatcher->useMaximalMunch() && ($match = $this->scanner->check($tokenMatcher->getMatch())) !== null) { $biggestToken = $this->createToken($tokenMatcher->getTokenID(), $match); /** @var wfWAFLexerTokenMatcher $tokenMatcher2 */ foreach ($this->tokenMatchers as $tokenMatcher2) { if ($tokenMatcher === $tokenMatcher2) { continue; } if (($match2 = $this->scanner->check($tokenMatcher2->getMatch())) !== null) { $biggestToken2 = $this->createToken($tokenMatcher2->getTokenID(), $match2); if (wfWAFUtils::strlen($biggestToken2->getValue()) > wfWAFUtils::strlen($biggestToken->getValue())) { $biggestToken = $biggestToken2; } } } $this->scanner->advancePointer(wfWAFUtils::strlen($biggestToken->getValue())); return $biggestToken; } else if (($match = $this->scanner->scan($tokenMatcher->getMatch())) !== null) { $token = $this->createToken($tokenMatcher->getTokenID(), $match); if ($tokenMatcher->getTokenID() === self::MYSQL_PORTABLE_COMMENT_START) { $this->hasPortableCommentStart = true; } else if ($tokenMatcher->getTokenID() === self::MYSQL_PORTABLE_COMMENT_END) { $this->hasPortableCommentStart = false; } return $token; } } $char = $this->scanner->scanChar(); $e = new wfWAFParserSyntaxError(sprintf('Invalid character "%s" (\x%02x) found on line %d, column %d', $char, ord($char), $this->scanner->getLine(), $this->scanner->getColumn())); $e->setParseLine($this->scanner->getLine()); $e->setParseColumn($this->scanner->getColumn()); throw $e; } return false; } public function hasMoreTokens() { } /** * @param $type * @param $value * @return wfWAFLexerToken */ protected function createToken($type, $value) { return new wfWAFLexerToken($type, $value, $this->scanner->getLine(), $this->scanner->getColumn()); } /** * @return string */ public function getSQL() { return $this->sql; } /** * @param string $sql */ public function setSQL($sql) { if (is_string($sql)) { $this->scanner->setString($sql); } $this->sql = $sql; } /** * @return int */ public function getFlags() { return $this->flags; } /** * @param int $flags */ public function setFlags($flags) { $this->flags = $flags; } } class wfWAFLexerTokenMatcher { /** * @var mixed */ private $tokenID; /** * @var string */ private $match; /** * @var bool */ private $useMaximalMunch; /** * @param mixed $tokenID * @param string $match * @param bool $useMaximalMunch */ public function __construct($tokenID, $match, $useMaximalMunch = false) { $this->tokenID = $tokenID; $this->match = $match; $this->useMaximalMunch = $useMaximalMunch; } /** * @return bool */ public function useMaximalMunch() { return $this->useMaximalMunch; } /** * @return mixed */ public function getTokenID() { return $this->tokenID; } /** * @param mixed $tokenID */ public function setTokenID($tokenID) { $this->tokenID = $tokenID; } /** * @return string */ public function getMatch() { return $this->match; } /** * @param string $match */ public function setMatch($match) { $this->match = $match; } } }
Warning: Cannot modify header information - headers already sent by (output started at /home/hvhospitalveteri/public_html/wp-content/plugins/wordfence/vendor/wordfence/wf-waf/src/lib/parser/sqli.php:2904) in /home/hvhospitalveteri/public_html/wp-content/plugins/wp-math-captcha/includes/class-cookie-session.php on line 46

Warning: Cannot modify header information - headers already sent by (output started at /home/hvhospitalveteri/public_html/wp-content/plugins/wordfence/vendor/wordfence/wf-waf/src/lib/parser/sqli.php:2904) in /home/hvhospitalveteri/public_html/wp-content/plugins/wp-math-captcha/includes/class-cookie-session.php on line 49

Warning: Cannot modify header information - headers already sent by (output started at /home/hvhospitalveteri/public_html/wp-content/plugins/wordfence/vendor/wordfence/wf-waf/src/lib/parser/sqli.php:2904) in /home/hvhospitalveteri/public_html/wp-content/plugins/wp-math-captcha/includes/class-cookie-session.php on line 49

Warning: Cannot modify header information - headers already sent by (output started at /home/hvhospitalveteri/public_html/wp-content/plugins/wordfence/vendor/wordfence/wf-waf/src/lib/parser/sqli.php:2904) in /home/hvhospitalveteri/public_html/wp-content/plugins/wp-math-captcha/includes/class-cookie-session.php on line 49

Warning: Cannot modify header information - headers already sent by (output started at /home/hvhospitalveteri/public_html/wp-content/plugins/wordfence/vendor/wordfence/wf-waf/src/lib/parser/sqli.php:2904) in /home/hvhospitalveteri/public_html/wp-content/plugins/wp-math-captcha/includes/class-cookie-session.php on line 49

Warning: Cannot modify header information - headers already sent by (output started at /home/hvhospitalveteri/public_html/wp-content/plugins/wordfence/vendor/wordfence/wf-waf/src/lib/parser/sqli.php:2904) in /home/hvhospitalveteri/public_html/wp-content/plugins/wp-math-captcha/includes/class-cookie-session.php on line 49
Therapy Found Effective for Carpal Tunnel Syndrome – HV Hospital Veterinario

Therapy Found Effective for Carpal Tunnel Syndrome

Customized physical therapy may be a useful way to ease low back pain, which affects an estimated 31 million Americans a new study says. Researchers from La Trobe University observed that ‘many patients with low-back disorders persisting beyond 6 weeks do not recover.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Huic mori optimum esse propter desperationem sapientiae, illi propter spem vivere. Dic in quovis conventu te omnia facere, ne doleas. Duo Reges: constructio interrete. Hosne igitur laudas et hanc eorum, inquam, sententiam sequi nos censes oportere? Potius inflammat, ut coercendi magis quam dedocendi esse videantur. Quid enim est a Chrysippo praetermissum in Stoicis? Sed quanta sit alias, nunc tantum possitne esse tanta. Ne amores quidem sanctos a sapiente alienos esse arbitrantur. Prodest, inquit, mihi eo esse animo.

Tibi hoc incredibile, quod beatissimum. An dolor longissimus quisque miserrimus, voluptatem non optabiliorem diuturnitas facit? Quia nec honesto quic quam honestius nec turpi turpius. Quod idem cum vestri faciant, non satis magnam tribuunt inventoribus gratiam. De ingenio eius in his disputationibus, non de moribus quaeritur. Et ille ridens: Video, inquit, quid agas; Tria genera bonorum; Non laboro, inquit, de nomine.

Non igitur de improbo, sed de callido improbo quaerimus, qualis Q. Haeret in salebra. Aliter homines, aliter philosophos loqui putas oportere? Quod ea non occurrentia fingunt, vincunt Aristonem;

Nihil opus est exemplis hoc facere longius. Sed ad haec, nisi molestum est, habeo quae velim. Ita ceterorum sententiis semotis relinquitur non mihi cum Torquato, sed virtuti cum voluptate certatio. Quae tamen a te agetur non melior, quam illae sunt, quas interdum optines.

Nam, ut sint illa vendibiliora, haec uberiora certe sunt. Nemo nostrum istius generis asotos iucunde putat vivere. Ex rebus enim timiditas, non ex vocabulis nascitur. Atqui haec patefactio quasi rerum opertarum, cum quid quidque sit aperitur, definitio est. Videsne quam sit magna dissensio? Numquam facies.