diff --git a/classes/xml/XmlQueryParser.150.class.php b/classes/xml/XmlQueryParser.150.class.php index e484f1900..1683988d0 100644 --- a/classes/xml/XmlQueryParser.150.class.php +++ b/classes/xml/XmlQueryParser.150.class.php @@ -43,7 +43,7 @@ if(!defined('__XE_LOADED_XML_CLASS__')){ * Parses XE XML query files * * @author Corina Udrescu (corina.udrescu@arnia.ro) - * @package dbclasses + * @package /classes/xml */ class XmlQueryParser extends XmlParser { @@ -83,7 +83,7 @@ class XmlQueryParser extends XmlParser { if(!$action) return; // Write query cache file - $parser = new QueryParser($xml_obj->query); + $parser = new QueryParser($xml_obj->query); FileHandler::writeFile($cache_file, $parser->toString()); return $parser; diff --git a/classes/xml/xmlquery/DBParser.class.php b/classes/xml/xmlquery/DBParser.class.php index a8f961371..6e12cfdcd 100644 --- a/classes/xml/xmlquery/DBParser.class.php +++ b/classes/xml/xmlquery/DBParser.class.php @@ -1,193 +1,262 @@ "member"."member_srl" + * - expressions: SUM(member.member_srl) => SUM("member"."member_srl") + * + * @author Corina Udrescu (corina.udrescu@arnia.ro) + * @package /classes/xml/xmlquery + */ +class DBParser +{ /** - * DBParser class - * @author NHN (developers@xpressengine.com) - * @package /classes/xml/xmlquery - * @version 0.1 + * Character for escape target value on the left + * + * For example, in CUBRID left and right escape + * chars are the same, the double quote - " + * But for SQL Server, the escape is made with + * [double brackets], so the left and right char differ + * + * + * @var string */ - class DBParser { - /** - * Character for escape target value on the left - * @var string - */ - var $escape_char_left; - /** - * Character for escape target value on the right - * @var string - */ - var $escape_char_right; - /** - * Table prefix string - * @var string - */ - var $table_prefix; - - /** - * constructor - * @param string $escape_char_left - * @param string $escape_char_right - * @param string $table_prefix - * @return void - */ - function DBParser($escape_char_left, $escape_char_right = "", $table_prefix = "xe_"){ - $this->escape_char_left = $escape_char_left; - if ($escape_char_right !== "")$this->escape_char_right = $escape_char_right; - else $this->escape_char_right = $escape_char_left; - $this->table_prefix = $table_prefix; - } - - /** - * Get escape character - * @param string $leftOrRight left or right - * @return string - */ - function getEscapeChar($leftOrRight){ - if ($leftOrRight === 'left')return $this->escape_char_left; - else return $this->escape_char_right; - } - - /** - * escape the value - * @param mixed $name - * @return string - */ - function escape($name){ - return $this->escape_char_left . $name . $this->escape_char_right; - } - - /** - * escape the string value - * @param string $name - * @return string - */ - function escapeString($name){ - return "'".$this->escapeStringValue($name)."'"; - } - - /** - * escape the string value - * @param string $value - * @return string - */ - function escapeStringValue($value){ - if($value == "*") return $value; - if (is_string($value)) return $value = str_replace("'","''",$value); - return $value; - } - - /** - * Return table full name - * @param string $name table name without table prefix - * @return string table full name with table prefix - */ - function parseTableName($name){ - return $this->table_prefix . $name; - } - - /** - * Return colmun name after escape - * @param string $name column name before escape - * @return string column name after escape - */ - function parseColumnName($name){ - return $this->escapeColumn($name); - } - - /** - * Escape column - * @param string $column_name - * @return string column name with db name - */ - function escapeColumn($column_name){ - if($this->isUnqualifiedColumnName($column_name)) - return $this->escape($column_name); - if($this->isQualifiedColumnName($column_name)){ - list($table, $column) = explode('.', $column_name); - // $table can also be an alias, so the prefix should not be added - return $this->escape($table).'.'.$this->escape($column); - //return $this->escape($this->parseTableName($table)).'.'.$this->escape($column); - } - } + var $escape_char_left; - /** - * Column name is suitable for use in checking - * @param string $column_name - * @return bool - */ - function isUnqualifiedColumnName($column_name){ - if(strpos($column_name,'.')===false && strpos($column_name,'(')===false) return true; - return false; - } - - /** - * Column name is suitable for use in checking - * @param string $column_name - * @return bool - */ - function isQualifiedColumnName($column_name){ - if(strpos($column_name,'.')!==false && strpos($column_name,'(')===false) return true; - return false; - } + /** + * Character for escape target value on the right + * + * For example, in CUBRID left and right escape + * chars are the same, the double quote - " + * But for SQL Server, the escape is made with + * [double brackets], so the left and right char differ + * + * @var string + */ + var $escape_char_right; - function parseExpression($column_name){ - $functions = preg_split('/([\+\-\*\/\ ])/', $column_name, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); - foreach($functions as $k => $v){ - $function = &$functions[$k]; - if(strlen($function)==1) continue; // skip delimiters - $pos = strrpos("(", $function); - $matches = preg_split('/([a-zA-Z0-9_*]+)/', $function, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); - $total_brackets = substr_count($function, "("); - $brackets = 0; - foreach($matches as $i => $j){ - $match = &$matches[$i]; - if($match == '(') {$brackets++; continue;} - if(strpos($match,')') !== false) continue; - if(in_array($match, array(',', '.'))) continue; - if($brackets == $total_brackets){ - if(!is_numeric($match) && !in_array(strtoupper($match), array('UNSIGNED', 'INTEGER', 'AS'))) { - $match = $this->escapeColumnExpression($match); - } + /** + * Table prefix string + * + * Default is "xe_" + * + * @var string + */ + var $table_prefix; + + /** + * Constructor + * + * @param string $escape_char_left + * @param string $escape_char_right + * @param string $table_prefix + * + * @return void + */ + function DBParser($escape_char_left, $escape_char_right = "", $table_prefix = "xe_") + { + $this->escape_char_left = $escape_char_left; + if ($escape_char_right !== "")$this->escape_char_right = $escape_char_right; + else $this->escape_char_right = $escape_char_left; + $this->table_prefix = $table_prefix; + } + + /** + * Get escape character + * @param string $leftOrRight left or right + * @return string + */ + function getEscapeChar($leftOrRight) + { + if ($leftOrRight === 'left')return $this->escape_char_left; + else return $this->escape_char_right; + } + + /** + * Escape the value + * @param mixed $name + * @return string + */ + function escape($name) + { + return $this->escape_char_left . $name . $this->escape_char_right; + } + + /** + * Escape the string value + * @param string $name + * @return string + */ + function escapeString($name) + { + return "'".$this->escapeStringValue($name)."'"; + } + + /** + * Escape the string value + * @param string $value + * @return string + */ + function escapeStringValue($value) + { + if($value == "*") return $value; + if (is_string($value)) return $value = str_replace("'","''",$value); + return $value; + } + + /** + * Return table full name + * + * @param string $name table name without table prefix + * + * @return string table full name with table prefix + */ + function parseTableName($name) + { + return $this->table_prefix . $name; + } + + /** + * Return column name after escape + * + * @param string $name column name before escape + * + * @return string column name after escape + */ + function parseColumnName($name) + { + return $this->escapeColumn($name); + } + + /** + * Escape column name + * + * @param string $column_name + * @return string column name with db name + */ + function escapeColumn($column_name) + { + if($this->isUnqualifiedColumnName($column_name)) + return $this->escape($column_name); + if($this->isQualifiedColumnName($column_name)){ + list($table, $column) = explode('.', $column_name); + // $table can also be an alias, so the prefix should not be added + return $this->escape($table).'.'.$this->escape($column); + //return $this->escape($this->parseTableName($table)).'.'.$this->escape($column); + } + } + + /** + * Checks to see if a given column name is unqualified + * + * Ex: "member_srl" -> unqualified + * "member"."member_srl" -> qualified + * + * @param string $column_name + * @return bool + */ + function isUnqualifiedColumnName($column_name) + { + if(strpos($column_name,'.')===FALSE && strpos($column_name,'(')===FALSE) return TRUE; + return FALSE; + } + + /** + * Checks to see if a given column name is qualified + * + * Ex: "member_srl" -> unqualified + * "member"."member_srl" -> qualified + * + * @param string $column_name + * @return bool + */ + function isQualifiedColumnName($column_name) + { + if(strpos($column_name,'.')!==FALSE && strpos($column_name,'(')===FALSE) return TRUE; + return FALSE; + } + + /** + * Escapes a query expression + * + * This can be: + * - a column name: "member_srl" or "xe_member"."member_srl" + * - an expression: + * - LEFT(UPPER("content")) + * - readed_count + voted_count + * - CAST(regdate as DATE) + * + * @param $column_name + * @return string + */ + function parseExpression($column_name) + { + $functions = preg_split('/([\+\-\*\/\ ])/', $column_name, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); + foreach($functions as $k => $v){ + $function = &$functions[$k]; + if(strlen($function)==1) continue; // skip delimiters + $pos = strrpos("(", $function); + $matches = preg_split('/([a-zA-Z0-9_*]+)/', $function, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY); + $total_brackets = substr_count($function, "("); + $brackets = 0; + foreach($matches as $i => $j){ + $match = &$matches[$i]; + if($match == '(') {$brackets++; continue;} + if(strpos($match,')') !== FALSE) continue; + if(in_array($match, array(',', '.'))) continue; + if($brackets == $total_brackets){ + if(!is_numeric($match) && !in_array(strtoupper($match), array('UNSIGNED', 'INTEGER', 'AS'))) { + $match = $this->escapeColumnExpression($match); } } - $function = implode('', $matches); - } - return implode('', $functions); - } - - /* - * Checks argument is asterisk - * @param string $column_name - * @return bool - */ - function isStar($column_name){ - if(substr($column_name,-1) == '*') return true; - return false; - } - - /* - * Checks to see if expression is an aggregate star function - * like count(*) - * @param string $column_name - * @return bool - */ - function isStarFunction($column_name){ - if(strpos($column_name, "(*)")!==false) return true; - return false; - } - - /* - * Return column name after escape - * @param string $column_name - * @return string - */ - function escapeColumnExpression($column_name){ - if($this->isStar($column_name)) return $column_name; - if($this->isStarFunction($column_name)){ - return $column_name; } - if(strpos(strtolower($column_name), 'distinct') !== false) return $column_name; - return $this->escapeColumn($column_name); - } + $function = implode('', $matches); + } + return implode('', $functions); } - + + /** + * Checks if a given argument is an asterisk + * + * @param string $column_name + * @return bool + */ + function isStar($column_name) + { + if(substr($column_name,-1) == '*') return TRUE; + return FALSE; + } + + /** + * Checks to see if expression is an aggregate star function + * like count(*) + * + * @param string $column_name + * @return bool + */ + function isStarFunction($column_name) + { + if(strpos($column_name, "(*)")!==FALSE) return TRUE; + return FALSE; + } + + /** + * Return column name after escape + * @param string $column_name + * @return string + */ + function escapeColumnExpression($column_name) + { + if($this->isStar($column_name)) return $column_name; + if($this->isStarFunction($column_name)) + { + return $column_name; + } + if(strpos(strtolower($column_name), 'distinct') !== FALSE) return $column_name; + return $this->escapeColumn($column_name); + } +} + diff --git a/classes/xml/xmlquery/QueryParser.class.php b/classes/xml/xmlquery/QueryParser.class.php index ab1366a37..a7ec171a5 100644 --- a/classes/xml/xmlquery/QueryParser.class.php +++ b/classes/xml/xmlquery/QueryParser.class.php @@ -1,92 +1,106 @@ queryTag = new QueryTag($query, $isSubQuery); - } + /** + * Constructor + * + * @param object $query XML object obtained after reading the XML Query file + * @param bool $isSubQuery + * @return void + */ + function QueryParser($query = NULL, $isSubQuery = FALSE) + { + if ($query) + { + $this->queryTag = new QueryTag($query, $isSubQuery); + } + } - /** - * Return table information - * @param object $query_id - * @param bool $table_name - * @return array - */ - function getTableInfo($query_id, $table_name) { - $column_type = array(); - $module = ''; - - $id_args = explode('.', $query_id); - if (count($id_args) == 2) { - $target = 'modules'; - $module = $id_args[0]; - $id = $id_args[1]; - } elseif (count($id_args) == 3) { - $target = $id_args[0]; - $targetList = array('modules'=>1, 'addons'=>1, 'widgets'=>1); - if (!isset($targetList[$target])) - return; - $module = $id_args[1]; - $id = $id_args[2]; - } + /** + * Return table information + * Used for finding column type info (string/numeric) + * + * Obtains the table info from XE's XML schema files + * + * @param object $query_id + * @param bool $table_name + * @return array + */ + function getTableInfo($query_id, $table_name) { + $column_type = array(); + $module = ''; - // get column properties from the table - $table_file = sprintf('%s%s/%s/schemas/%s.xml', _XE_PATH_, 'modules', $module, $table_name); - if (!file_exists($table_file)) { - $searched_list = FileHandler::readDir(_XE_PATH_ . 'modules'); - $searched_count = count($searched_list); - for ($i = 0; $i < $searched_count; $i++) { - $table_file = sprintf('%s%s/%s/schemas/%s.xml', _XE_PATH_, 'modules', $searched_list[$i], $table_name); - if (file_exists($table_file)) - break; - } - } + $id_args = explode('.', $query_id); + if (count($id_args) == 2) { + $target = 'modules'; + $module = $id_args[0]; + $id = $id_args[1]; + } elseif (count($id_args) == 3) { + $target = $id_args[0]; + $targetList = array('modules'=>1, 'addons'=>1, 'widgets'=>1); + if (!isset($targetList[$target])) + return; + $module = $id_args[1]; + $id = $id_args[2]; + } - if (file_exists($table_file)) { - $table_xml = FileHandler::readFile($table_file); - $xml_parser = new XmlParser(); - $table_obj = $xml_parser->parse($table_xml); - if ($table_obj->table) { - if (isset($table_obj->table->column) && !is_array($table_obj->table->column)) { - $table_obj->table->column = array($table_obj->table->column); - } + // get column properties from the table + $table_file = sprintf('%s%s/%s/schemas/%s.xml', _XE_PATH_, 'modules', $module, $table_name); + if (!file_exists($table_file)) { + $searched_list = FileHandler::readDir(_XE_PATH_ . 'modules'); + $searched_count = count($searched_list); + for ($i = 0; $i < $searched_count; $i++) { + $table_file = sprintf('%s%s/%s/schemas/%s.xml', _XE_PATH_, 'modules', $searched_list[$i], $table_name); + if (file_exists($table_file)) + break; + } + } - foreach ($table_obj->table->column as $k => $v) { - $column_type[$v->attrs->name] = $v->attrs->type; - } - } - } + if (file_exists($table_file)) { + $table_xml = FileHandler::readFile($table_file); + $xml_parser = new XmlParser(); + $table_obj = $xml_parser->parse($table_xml); + if ($table_obj->table) { + if (isset($table_obj->table->column) && !is_array($table_obj->table->column)) { + $table_obj->table->column = array($table_obj->table->column); + } - return $column_type; - } + foreach ($table_obj->table->column as $k => $v) { + $column_type[$v->attrs->name] = $v->attrs->type; + } + } + } - /** - * Change code string from queryTag object - * @return string - */ - function toString() { - return "queryTag->toString() - . 'return $query; ?>'; - } + return $column_type; + } - } + /** + * Returns the contents for the query cache file + * + * @return string + */ + function toString() { + return "queryTag->toString() + . 'return $query; ?>'; + } + +} ?>