如何在PHP中解析和转义sql连接条件
我已经在自己的SQL库/查询生成器上工作了一段时间。(https://github.com/aviat4ion/Query)在很大程度上,我对事情的运作方式很满意 一个问题是查询联接 比如说如何在PHP中解析和转义sql连接条件,php,escaping,Php,Escaping,我已经在自己的SQL库/查询生成器上工作了一段时间。(https://github.com/aviat4ion/Query)在很大程度上,我对事情的运作方式很满意 一个问题是查询联接 比如说 $db->join($table, 'table1.field1=table2.field2', 'inner'); 对于如何解析第二个参数,我感到相当困惑,它需要正确地转义表标识符 我希望能够在这种情况下处理函数 我当前的实现相当幼稚-拆分空间上的条件,因此“table1.field1=table
$db->join($table, 'table1.field1=table2.field2', 'inner');
对于如何解析第二个参数,我感到相当困惑,它需要正确地转义表标识符
我希望能够在这种情况下处理函数
我当前的实现相当幼稚-拆分空间上的条件,因此“table1.field1=table2.field2”将失败,“table1.field1=table2.field2”将起作用
每个数据库驱动程序都有一个抽象标识符转义的函数,该函数用于表标识符,如database.table.field
,以便将其转义为“database”。“table”。“field”
所以我的基本问题是:如何解析出标识符以在连接条件中转义它们
编辑:
我需要以一种可以用于MySQL、Postgres、SQLite和Firebird的方式来实现这一点 如果您只想解析where表达式,一个简单的运算符优先解析器就可以做到这一点。您必须对解析树应用一些检查以确保表达式有效,但这并不困难 您可以在这里下载一个优秀的解析指南(“解析技术-实用指南”)。优先解析在第187页9.2优先解析中介绍 该技术假设您有两件事:
$db->join->inner($table, array(
'=' => array(
'left' => array (
'table' => 'tab1'
, 'column' => 'col1'
)
, 'right' => array (
'table' => 'tab2'
, 'column' => 'col2'
)
)
));
下面是我大致得出的结论:
class Query_Parser {
/**
* Regex patterns for various syntax components
*
* @var array
*/
private $match_patterns = array(
'function' => '([a-zA-Z0-9_]+\((.*?)\))',
'identifier' => '([a-zA-Z0-9_-]+\.?)+',
'operator' => '=|AND|&&?|~|\|\|?|\^|/|>=?|<=?|-|%|OR|\+|NOT|\!=?|<>|XOR'
);
/**
* Regex matches
*
* @var array
*/
public $matches = array(
'functions' => array(),
'identifiers' => array(),
'operators' => array(),
'combined' => array(),
);
/**
* Constructor/entry point into parser
*
* @param string
*/
public function __construct($sql = '')
{
// Get sql clause components
preg_match_all('`'.$this->match_patterns['function'].'`', $sql, $this->matches['functions'], PREG_SET_ORDER);
preg_match_all('`'.$this->match_patterns['identifier'].'`', $sql, $this->matches['identifiers'], PREG_SET_ORDER);
preg_match_all('`'.$this->match_patterns['operator'].'`', $sql, $this->matches['operators'], PREG_SET_ORDER);
// Get everything at once for ordering
$full_pattern = '`'.$this->match_patterns['function'].'+|'.$this->match_patterns['identifier'].'|('.$this->match_patterns['operator'].')+`i';
preg_match_all($full_pattern, $sql, $this->matches['combined'], PREG_SET_ORDER);
// Go through the matches, and get the most relevant matches
$this->matches = array_map(array($this, 'filter_array'), $this->matches);
}
// --------------------------------------------------------------------------
/**
* Public parser method for seting the parse string
*
* @param string
*/
public function parse_join($sql)
{
$this->__construct($sql);
return $this->matches;
}
// --------------------------------------------------------------------------
/**
* Returns a more useful match array
*
* @param array
* @return array
*/
private function filter_array($array)
{
$new_array = array();
foreach($array as $row)
{
if (is_array($row))
{
$new_array[] = $row[0];
}
else
{
$new_array[] = $row;
}
}
return $new_array;
}
}
类查询解析器{
/**
*各种语法组件的正则表达式模式
*
*@var数组
*/
私有$match_patterns=数组(
“函数'=>'([a-zA-Z0-9\]+\(.*)”,
'标识符'=>'([a-zA-Z0-9.-]+\.?)+',
“运算符”=>“==”和“&&&”&&&&&&&&&··············································································这里可能是一个更简单的方法。我可以理解对更简单解决方案的诱惑。根据经验,我必须不幸地建议不要落入这个陷阱。要么重新构造API,这样你就不必解析任何东西(第二个选项),要么构建一个解析器。从另一方面来说,是一个“全面的”这种情况下的解析器真的没有那么难。它只需要一点时间。你的观点很好。我不想更改API,因为我希望API与另一个库兼容。如果没有其他问题,这是一个很好的学习练习。好的。给自己一点时间阅读优先级解析。我相信你会发现它符合你的目的ose非常好,也没有那么难。例如,标记器很容易使用一些正则表达式魔术创建(这不会很快,但实现起来相当快),优先级查找也没有那么难-只是一点点工作,不多不少。
// Parse out the join condition
$parts = $parser->parse_join($condition);
$count = count($parts['identifiers']);
// Go through and quote the identifiers
for($i=0; $i <= $count; $i++)
{
if (in_array($parts['combined'][$i], $parts['identifiers']) && ! is_numeric($parts['combined'][$i]))
{
$parts['combined'][$i] = $this->quote_ident($parts['combined'][$i]);
}
}
$parsed_condition = implode(' ', $parts['combined']);