是否有一个用PHP编写的轻量级sql解析器类来实现这一点?
在跳进去玩我自己的之前,我想我应该先在这里问一下 我希望对随机SQL命令进行一些基本分析,以便:是否有一个用PHP编写的轻量级sql解析器类来实现这一点?,php,sql,postgresql,Php,Sql,Postgresql,在跳进去玩我自己的之前,我想我应该先在这里问一下 我希望对随机SQL命令进行一些基本分析,以便: 检查“选择”中使用的字段名(包括任何子查询) 检查“联接”中使用的字段名(包括任何子查询) 检查查询中使用的表的名称(包括任何子查询) 我已经看到了一些SQL解析器类,但是对于上面描述的用例来说,它们太重了 有人知道轻量级类至少具有一些必需的功能吗 最坏的情况是,如果我必须编写一个解析器,那么编写这样一个解析器的最佳方式是什么(通常,要编写解析器,我通常会使用PHP中没有的工具),关于如何编写一个“
//rough sketch
<?php
class SqlParser()
{
protected $sqlstr;
protected $m_tablenames = array();
protected $m_fieldnames = array();
public function __construct($sql){
$this->sqlstr = $sqlcmd;
$this->parseString($sqlstr);
}
public function __destroy(){}
public function getTableNames(){ return m_tablenames; }
public function getFieldNames(){ return m_fieldnames; }
private function parseString($sql)
{
//TODO
}
}
?>
//草图
我希望解析尽可能与SQL方言无关(即不与任何特定的SQL方言或特定于db的SQL相关联)
如果这是不可能的,那么我将使用的SQL方言是PostgreSQL。您可以尝试一下,我不太清楚,但它可能就是您正在寻找的东西。可能就是您正在寻找的东西。从链接中可以看到,它将处理相当复杂的查询。从项目首页下载代码。唯一的缺点是它只针对MySQL。添加对PostgreSQL的支持应该不是什么大问题
还有一个更基本的SQL解析解决方案:,但它只提供select/from/where/order分隔:无字段名、子查询提取等功能。我最近尝试过这样做
这是更轻的其他类
<?php
/**
* Light SQL Parser Class
* @author Marco Cesarato <cesarato.developer@gmail.com>
* @copyright Copyright (c) 2018
* @license http://opensource.org/licenses/gpl-3.0.html GNU Public License
* @link https://github.com/marcocesarato/PHP-Light-SQL-Parser-Class
* @version 0.1.86
*/
class LightSQLParser {
// Public
public $query = '';
// Private
protected static $connectors = array('OR', 'AND', 'ON', 'LIMIT', 'WHERE', 'JOIN', 'GROUP', 'ORDER', 'OPTION', 'LEFT', 'INNER', 'RIGHT', 'OUTER', 'SET', 'HAVING', 'VALUES', 'SELECT', '\(', '\)');
protected static $connectors_imploded = '';
/**
* Constructor
*/
public function __construct($query = '') {
$this->query = $query;
if(empty(self::$connectors_imploded))
self::$connectors_imploded = implode('|', self::$connectors);
return $this;
}
/**
* Set SQL Query string
*/
public function setQuery($query) {
$this->query = $query;
return $this;
}
/**
* Get SQL Query method
* @param $query
* @return string
*/
public function method($query = null){
$methods = array('SELECT','INSERT','UPDATE','DELETE','RENAME','SHOW','SET','DROP','CREATE INDEX','CREATE TABLE','EXPLAIN','DESCRIBE','TRUNCATE','ALTER');
$queries = empty($query) ? $this->_queries() : array($query);
foreach($queries as $query){
foreach($methods as $method) {
$_method = str_replace(' ', '[\s]+', $method);
if(preg_match('#^[\s]*'.$_method.'[\s]+#i', $query)){
return $method;
}
}
}
return '';
}
/**
* Get Query fields (at the moment only SELECT/INSERT/UPDATE)
* @param $query
* @return array
*/
public function fields(){
$fields = array();
$queries = $this->_queries();
foreach($queries as $query) {
$method = $this->method($query);
switch ($method){
case 'SELECT':
preg_match('#SELECT[\s]+([\S\s]*)[\s]+FROM#i', $query, $matches);
if (!empty($matches[1])) {
$match = trim($matches[1]);
$match = explode(',', $match);
foreach ($match as $field) {
$field = preg_replace('#([\s]+(AS[\s]+)?[\w\.]+)#i', '', trim($field));
$fields[] = $field;
}
}
break;
case 'INSERT':
preg_match('#INSERT[\s]+INTO[\s]+([\w\.]+([\s]+(AS[\s]+)?[\w\.]+)?[\s]*)\(([\S\s]*)\)[\s]+VALUES#i', $query, $matches);
if (!empty($matches[4])) {
$match = trim($matches[4]);
$match = explode(',', $match);
foreach ($match as $field) {
$field = preg_replace('#([\s]+(AS[\s]+)?[\w\.]+)#i', '', trim($field));
$fields[] = $field;
}
} else {
preg_match('#INSERT[\s]+INTO[\s]+([\w\.]+([\s]+(AS[\s]+)?[\w\.]+)?[\s]*)SET([\S\s]*)([\;])?#i', $query, $matches);
if (!empty($matches[4])) {
$match = trim($matches[4]);
$match = explode(',', $match);
foreach ($match as $field) {
$field = preg_replace('#([\s]*\=[\s]*[\S\s]+)#i', '', trim($field));
$fields[] = $field;
}
}
}
break;
case 'UPDATE':
preg_match('#UPDATE[\s]+([\w\.]+([\s]+(AS[\s]+)?[\w\.]+)?[\s]*)SET([\S\s]*)([\s]+WHERE|[\;])?#i', $query, $matches);
if (!empty($matches[4])) {
$match = trim($matches[4]);
$match = explode(',', $match);
foreach ($match as $field) {
$field = preg_replace('#([\s]*\=[\s]*[\S\s]+)#i', '', trim($field));
$fields[] = $field;
}
}
break;
case 'CREATE TABLE':
preg_match('#CREATE[\s]+TABLE[\s]+\w+[\s]+\(([\S\s]*)\)#i', $query, $matches);
if (!empty($matches[1])) {
$match = trim($matches[1]);
$match = explode(',', $match);
foreach ($match as $_field) {
preg_match('#^w+#', trim($_field), $field);
if (!empty($field[0])) {
$fields[] = $field[0];
}
}
}
break;
}
}
return array_unique($fields);
}
/**
* Get SQL Query First Table
* @param $query
* @return string
*/
public function table(){
$tables = $this->tables();
return $tables[0];
}
/**
* Get SQL Query Tables
* @return array
*/
function tables(){
$results = array();
$queries = $this->_queries();
foreach($queries as $query) {
$patterns = array(
'#[\s]+FROM[\s]+(([\s]*(?!'.self::$connectors_imploded.')[\w]+([\s]+(AS[\s]+)?(?!'.self::$connectors_imploded.')[\w]+)?[\s]*[,]?)+)#i',
'#[\s]*INSERT[\s]+INTO[\s]+([\w]+)#i',
'#[\s]*UPDATE[\s]+([\w]+)#i',
'#[\s]+[\s]+JOIN[\s]+([\w]+)#i',
'#[\s]+TABLE[\s]+([\w]+)#i'
);
foreach($patterns as $pattern){
preg_match_all($pattern,$query, $matches, PREG_SET_ORDER);
foreach ($matches as $val) {
$tables = explode(',', $val[1]);
foreach ($tables as $table) {
$table = trim(preg_replace('#[\s]+(AS[\s]+)[\w\.]+#i', '', $table));
$results[] = $table;
}
}
}
}
return array_unique($results);
}
/**
* Get all queries
* @return array
*/
protected function _queries(){
$queries = preg_replace('#\/\*[\s\S]*?\*\/#','', $this->query);
$queries = preg_replace('#;(?:(?<=["\'];)|(?=["\']))#', '', $queries);
$queries = preg_replace('#[\s]*UNION([\s]+ALL)?[\s]*#', ';', $queries);
$queries = explode(';', $queries);
return $queries;
}
}
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分,并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能无效。-@mac_zbc我已经添加了代码,但是如果我更新这个类(我已经更新了大约70次),我的anwser中的类可能会被窃听
header("Content-Type: text/plain");
echo '========= Light SQL Parser DEMO =========' . PHP_EOL;
echo PHP_EOL . '### UPDATE ###' . PHP_EOL;
$lsp = new LightSQLParser("UPDATE Customers as ae
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
WHERE CustomerID = 1;");
// OR
/*
$lsp = new LightSQLParser();
$lsp->setQuery("UPDATE Customers as ae
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
WHERE CustomerID = 1;");
*/
echo PHP_EOL . 'METHOD' . PHP_EOL;
var_dump($lsp->method());
echo PHP_EOL . 'TABLES' . PHP_EOL;
var_dump($lsp->tables());
echo PHP_EOL . 'FIELDS' . PHP_EOL;
var_dump($lsp->fields());
echo PHP_EOL . '### SELECT ###' . PHP_EOL;
$lsp->setQuery("SELECT surname, given_names, title FROM Person
JOIN Author on person.ID = Author.personID
JOIN Book on Book.ID = Author.publicationID
UNION ALL
SELECT surname, given_names, title FROM Person
JOIN Author on person.ID = Author.personID
JOIN Article on Article.ID = Author.publicationID");
echo PHP_EOL . 'METHOD' . PHP_EOL;
var_dump($lsp->method());
echo PHP_EOL . 'TABLES' . PHP_EOL;
var_dump($lsp->tables());
echo PHP_EOL . 'FIELDS' . PHP_EOL;
var_dump($lsp->fields());
echo PHP_EOL . '### INSERT ###' . PHP_EOL;
$lsp->setQuery("INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');");
echo PHP_EOL . 'METHOD' . PHP_EOL;
var_dump($lsp->method());
echo PHP_EOL . 'TABLES' . PHP_EOL;
var_dump($lsp->tables());
echo PHP_EOL . 'FIELDS' . PHP_EOL;
var_dump($lsp->fields());