class Query {
private $query;
private $varCount = 0;
private $variable = array();
private $connected;
const DECIMAL = 'DECIMAL';
const STRING = 'STING';
const NAME = 'NAME';
const ARAY = 'ARAY';
const FLOAT = 'FLOAT';
const HASH = 'HASH';
function __construct($query, $connection = NULL) {
if(!is_string($query)) {
throw new InvalidArgumentException('String expected. '. gettype($query).' given.');
}
$this->parseVariables($query);
if(is_a($connection,'mysqli')){
$this -> connected = $connection;
}
}
public function parse() {
$query = $this->query;
$counter = 0;
$in = func_get_args();
if(sizeof($in) == 0 && $this->varCount ==0) {
return $this ->query;
}
//$in = $in[0];
$vars = $this->variable;
while (sizeof($vars) > 0) {
$currentVariable = array_shift($vars);
$currentInput = array_shift($in);
if (!$currentInput) {
throw new InvalidArgumentException('Query expects "'.$this->varCount.'" variables.');
}
if (($currentVariable['type'] === Query::HASH || $currentVariable['type'] === Query::ARAY) && !is_array($currentInput)) {
throw new InvalidArgumentException('Array expected. "'.gettype($currentInput).'" is given.');
}
if (($currentVariable['type'] === Query::HASH || $currentVariable['type'] === Query::ARAY) && is_array($currentInput)) {
$paste = $this->prepareVariable($currentVariable, $currentInput);
$searchFor = '/#' . $currentVariable['id'] . '#/u';
$query = preg_replace($searchFor, $paste, $query);
$counter++;
} elseif (is_array($currentInput)) {
$c = false;
foreach ($currentInput as $input) {
if ($c) {
$currentVariable = array_shift($vars);
if (!$currentVariable) {
throw new InvalidArgumentException('Query expects '.$this->varCount.' variables.');
}
}
if (($currentVariable['type'] === Query::HASH || $currentVariable['type'] === Query::ARAY) && !is_array($input)) {
throw new InvalidArgumentException('Array expected. "'.gettype($input).'" is given.');
}
$paste = $this->prepareVariable($currentVariable, $input);
$searchFor = '/#' . $currentVariable['id'] . '#/u';
$query = preg_replace($searchFor, $paste, $query);
$counter++;
$c = true;
}
} else {
$paste = $this->prepareVariable($currentVariable, $currentInput);
$searchFor = '/#' . $currentVariable['id'] . '#/u';
$query = preg_replace($searchFor, $paste, $query);
$counter++;
}
}
if($counter!=$this->varCount) {
throw new InvalidArgumentException('Invalid number of variables is given.d');
}
return $query;
}
private function parseVariables($string) {
$pattern = '/%([DFSNHA])({([^{}]+)})?/u';
$array = preg_split($pattern, $string);
$matches = array();
preg_match_all($pattern, $string, $matches);
$result = "";
$counter = 0;
foreach ($array as $key => $value) {
if (isset($matches[1][$key])) {
switch ($matches[1][$key]) {
case 'F':
$type = Query::FLOAT;
break;
case 'D':
$type = Query::DECIMAL;
break;
case 'N':
$type = Query::NAME;
break;
case 'A':
$type = Query::ARAY;
break;
case 'H':
$type = Query::HASH;
break;
default:
$type = Query::STRING;
}
$this->addVariable($counter, $type, $matches[3][$key]);
$result .= $value . '#' . $counter . '#';
$counter++;
} else {
$result .= $value;
}
}
$this -> varCount = $counter;
$this->query = $result;
}
private function prepareVariable($field, $value) {
$result = NULL;
if ($value === NULL) {
return NULL;
}
//REGEXP MATCHING
if ($field['regexp'] != NULL) {
if (!preg_match($field['regexp'], $value)) {
return NULL; //Raise exeption
}
}
switch ($field['type']) {
case Query::DECIMAL:
$result = $this->prepareDecimal($value);
break;
case Query::STRING:
$result = $this->prepareSting($value);
break;
case Query::NAME:
$result = $this->prepareName($value);
break;
case Query::ARAY:
if(!is_array($value)) {
throw new InvalidArgumentException('Array expected. '. gettype($str).' is given.');
}
$result = '(';
while (sizeof($value) > 1) {
$val = $this->prepareUnknown(array_shift($value));
$result .= $val . ', ';
}
$val = $this->prepareUnknown(array_shift($value));
$result .= $val . ')';
break;
case Query::FLOAT:
$result = $this->prepareFloat($value);
break;
case Query::HASH:
if(!is_array($value)) {
throw new InvalidArgumentException('Array expected. '. gettype($str).' is given.');
}
$result = '';
if (sizeof($value) > 0) {
foreach ($value as $key => $valu) {
$key = $this->prepareName($key);
$valu = $this->prepareUnknown($valu);
$result .= $key . '=' . $valu . ', ';
}
$result = substr($result, 0, strlen($result) -2);
}
}
return $result;
}
private function prepareUnknown($unk) {
return $this->prepareSting($unk);
}
private function prepareSting($str) {
if(!is_string($str)) {
throw new InvalidArgumentException('String expected. '. gettype($str).' is given.');
}
if(isset($this->connected)) {
$str = mysqli_real_escape_string($this->connected,$str);
}
else {
$str = mysql_real_escape_string($str);
}
$result = '';
echo "string testing<br>";
$result = "'" . $str . "'";
return $result;
}
private function prepareFloat($flo) {
echo "float testing<br>";
if (!is_numeric($flo)) {
throw new InvalidArgumentException('Float expected. '. gettype($flo).' is given.');
}
return $flo;
}
private function prepareDecimal($dec) {
echo "decimal testing<br>";
if (!is_numeric($dec)) {
throw new InvalidArgumentException('Decimal expected. '. gettype($flo).' is given.');
}
if (is_float($dec)) {
$dec = round($dec);
}
return $dec;
}
private function prepareName($name) {
if(!is_string($str)) {
throw new InvalidArgumentException('String expected. '. gettype($name).' is given.');
}
echo "name testing<br>";
$result = preg_replace('/[\'\`]/', '', $name);
if(isset($this->connected)) {
$str = mysqli_real_escape_string($this->connected,$name);
} else {
$str = mysql_real_escape_string($name);
}
if (strlen($name) > 30) {
throw new LengthException('Length of name should be less then 30 symbols');
}
return '`' . $result . '`';
}
private function addVariable($field_name, $type, $regex = NULL) {
$this->variable[$field_name]['type'] = $type;
$this->variable[$field_name]['regexp'] = $regex;
$this->variable[$field_name]['id'] = $field_name;
}
}