getSQL($varnames, "or", "regexp", "[[:<:]]", "[[:>:]]"); # getSQL arguments: array of column names, string to join sets of column # expressions, relation for expression (like, regexp, etc.), string to put # before each word, string to put after each word (e.g. "%", "[[:<:]]") # result: ($varname regexp '[[:<:]]$wordfromquerystring[[:>:]]') or $varname ... require_once("Token.php"); class BooleanToSQL { var $query; var $ops; # valid operators other than parens, not case-sensitive var $tarray; # infix token array var $ptarray; # postfix token array # constructor sets up query and valid operators function BooleanToSQL($bquery) { $this->query = $bquery; $this->ops = array("and", "or", "not"); } function setQuery($bquery) { $this->query = $bquery; } function getQuery() { return $this->query; } function getCount() { if(!$this->getTokens()) { return 0; } $count = 0; for($i = 0; $i < count($this->tarray); $i++) { if($this->tarray[$i]->isOperator() == 0) { $count++; } } return $count; } # tokenize the query function getTokens() { $str = $this->query; $t = 0; while($str != "") { $str = trim($str); # take the first character in the remaining query $c = substr($str, 0, 1); # if a quote character, match anything up to the next # matching quote if($c == "\"" || $c == "'") { preg_match("/^$c([^$c]*)$c/", $str, $matches); $val = preg_quote($matches[1]); $str = preg_replace("/^$c$val$c/", "", $str); $token = new Token($matches[1]); } # if a parenthesis, create a token for it else if($c == "(" || $c == ")") { $str = substr($str, 1); $token = new Token($c, 1); } # otherwise match any non-special characters to find # the next word or word operator else { preg_match("/^([^\s\(\)\"\']+)/", $str, $matches); $val = preg_quote($matches[1]); $str = preg_replace("/^$val/", "", $str); $token = new Token($matches[1]); # if the token is one of the operators, set the # operator flag for that token for($j = 0; $j < count($this->ops); $j++) { if(strtolower($val) == $this->ops[$j]) { if($val == "not") { $val = "and not"; } $token->setValue(strtolower($val)); $token->setOperator(); break; } } } $this->tarray[$t] = $token; $t++; # if the query is too long or something else has gone # awry, break out of the loop if($t > 100) { return false; } } return true; } # given an array of variable names (table columns), a string to join # each variable set with, the relation operator, and the strings to # place before and after each query token in the string: # '$pre$word$post' function getSQL($varnames, $join, $rel, $pre, $post) { if(!$this->postfix()) { return 0; } if(count($varnames) < 1 || count($this->ptarray) < 1) { return 0; } $wclause = $this->createWhere($varnames[0], $this->ptarray, $rel, $pre, $post); for($i = 1; $i < count($varnames); $i++) { $wclause .= "$join " .$this->createWhere($varnames[$i], $this->ptarray, $rel, $pre, $post); } return $wclause; } # print a token array for debugging purposes function printTokens($array) { for($i = 0; $i < count($array); $i++) { print "$i: " . $array[$i]->isOperator() . " " . $array[$i]->getValue() . "
\n"; } } # create the section of the where clause for column $varname given # an array of keywords, the relation operator, and pre and post # strings which surround the word in the expression function createWhere($varname, $array, $rel, $pre, $post) { $tmpstack = array(); if(count($array) == 0) { return 0; } while(count($array) > 0) { if($array[0]->isOperator() == 0) { $val = $array[0]->getEValue($rel); $tok = new Token("( $varname $rel '$pre$val$post') "); array_push($tmpstack, $tok); } else { $word2 = array_pop($tmpstack); $word1 = array_pop($tmpstack); $op = $array[0]->getValue(); $tok = new Token(" (" . $word1->getValue() . " $op " . $word2->getValue() . ") "); array_push($tmpstack, $tok); } array_shift($array); } return $tmpstack[0]->getValue(); } function escapeVal($val, $rel) { if(preg_match("/regexp|rlike/", $rel)) { $val = preg_quote($val); } $val = preg_replace("/\*/", "%", $val); $val = addslashes($val); if(preg_match("/regexp|rlike/", $rel)) { $val = preg_replace("/\\\\\\\\%/", ".*", $val); } return $val; } # create a postfix token array from the infix token array, returning # 1 if successful and 0 if there are any problems function postfix() { $this->getTokens(); $tmpstack = array(); $prevWord = 0; # 1 if the previous token wasn't an op $tarray = $this->tarray; $this->ptarray = array(); # check for balanced parentheses in the input $openparen = 0; $closeparen = 0; for($i = 0; $i < count($tarray); $i++) { if($tarray[$i]->getValue() == "(") { $openparen++; } else if($tarray[$i]->getValue() == ")") { $closeparen++; } } if($openparen != $closeparen) { return 0; } while(count($tarray) > 0) { # if not an operator, push on the temp stack if($tarray[0]->isOperator() == 0) { array_push($tmpstack, array_shift($tarray)); if($prevWord == 1) { return 0; } else { $prevWord = 1; } } # if ), pop the temp stack to output until ( is found else if($tarray[0]->getValue() == ")") { $prevWord = 0; $tcount = count($tmpstack); while($tcount > 0 && $tmpstack[$tcount - 1]->getValue() != "(") { array_push($this->ptarray, array_pop($tmpstack)); $tcount = count($tmpstack); } array_shift($tarray); array_pop($tmpstack); } # if (, push on temp stack else if($tarray[0]->getValue() == "(") { $prevWord = 0; array_push($tmpstack, array_shift($tarray)); } # otherwise, pop the stack until another operator is # found and push the operator from the input on the # stack else { $prevWord = 0; $tcount = count($tmpstack); while($tcount > 0 && $tmpstack[$tcount - 1]->isOperator() == 0) { array_push($this->ptarray, array_pop($tmpstack)); $tcount = count($tmpstack); } array_push($tmpstack, array_shift($tarray)); } } # pop all remaining terms from temp stack to output while(count($tmpstack) > 0) { array_push($this->ptarray, array_pop($tmpstack)); } # check to make sure that there is one more word than operator $numwords = $numops = 0; for($i = 0; $i < count($this->ptarray); $i++) { if($this->ptarray[$i]->isOperator()) { $numops++; } else { $numwords++; } } if($numops != ($numwords - 1)) { return 0; } return 1; } } ?>