Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有一个用PHP编写的轻量级sql解析器类来实现这一点?_Php_Sql_Postgresql - Fatal编程技术网

是否有一个用PHP编写的轻量级sql解析器类来实现这一点?

是否有一个用PHP编写的轻量级sql解析器类来实现这一点?,php,sql,postgresql,Php,Sql,Postgresql,在跳进去玩我自己的之前,我想我应该先在这里问一下 我希望对随机SQL命令进行一些基本分析,以便: 检查“选择”中使用的字段名(包括任何子查询) 检查“联接”中使用的字段名(包括任何子查询) 检查查询中使用的表的名称(包括任何子查询) 我已经看到了一些SQL解析器类,但是对于上面描述的用例来说,它们太重了 有人知道轻量级类至少具有一些必需的功能吗 最坏的情况是,如果我必须编写一个解析器,那么编写这样一个解析器的最佳方式是什么(通常,要编写解析器,我通常会使用PHP中没有的工具),关于如何编写一个“

在跳进去玩我自己的之前,我想我应该先在这里问一下

我希望对随机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());