有没有办法让PHP在不执行的情况下验证SQL语法?

时间:2011-11-08 03:17:47

标签: php mysql sql

我想构建一个PHP脚本来验证SQL查询,但不执行它。它不仅应该验证语法,而且如果可能的话,应该告诉您是否可以根据查询中的命令执行查询。这是我希望它做的伪代码:

<?php
//connect user
//connect to database
//v_query = $_GET['usrinput'];
if(validate v_query == true){
echo "This query can be executed";
}
else{
echo "This query can't be executed because the table does not exist.";
}

//disconnect 
?>

像这样的东西。我希望它在不执行查询的情况下模拟查询。这就是我想要的,我在这方面找不到任何东西。

我们不希望执行查询的原因的一个示例是查询是否向数据库添加了某些内容。我们只是希望它在不修改数据库的情况下进行模拟。

非常感谢任何链接或示例!

3 个答案:

答案 0 :(得分:4)

从MySQL 5.6.3开始,您可以使用EXPLAIN进行大多数查询

我做了这个,它很可爱:

function checkMySqlSyntax($mysqli, $query) {
   if ( trim($query) ) {
      // Replace characters within string literals that may *** up the process
      $query = replaceCharacterWithinQuotes($query, '#', '%') ;
      $query = replaceCharacterWithinQuotes($query, ';', ':') ;
      // Prepare the query to make a valid EXPLAIN query
      // Remove comments # comment ; or  # comment newline
      // Remove SET @var=val;
      // Remove empty statements
      // Remove last ;
      // Put EXPLAIN in front of every MySQL statement (separated by ;) 
      $query = "EXPLAIN " .
               preg_replace(Array("/#[^\n\r;]*([\n\r;]|$)/",
                              "/[Ss][Ee][Tt]\s+\@[A-Za-z0-9_]+\s*=\s*[^;]+(;|$)/",
                              "/;\s*;/",
                              "/;\s*$/",
                              "/;/"),
                        Array("","", ";","", "; EXPLAIN "), $query) ;

      foreach(explode(';', $query) as $q) {
         $result = $mysqli->query($q) ;
         $err = !$result ? $mysqli->error : false ;
         if ( ! is_object($result) && ! $err ) $err = "Unknown SQL error";
         if ( $err) return $err ;
      }
      return false ;
  }
}

function replaceCharacterWithinQuotes($str, $char, $repl) {
    if ( strpos( $str, $char ) === false ) return $str ;

    $placeholder = chr(7) ;
    $inSingleQuote = false ;
    $inDoubleQuotes = false ;
    for ( $p = 0 ; $p < strlen($str) ; $p++ ) {
        switch ( $str[$p] ) {
            case "'": if ( ! $inDoubleQuotes ) $inSingleQuote = ! $inSingleQuote ; break ;
            case '"': if ( ! $inSingleQuote ) $inDoubleQuotes = ! $inDoubleQuotes ; break ;
            case '\\': $p++ ; break ;
            case $char: if ( $inSingleQuote || $inDoubleQuotes) $str[$p] = $placeholder ; break ;
        }
    }
    return str_replace($placeholder, $repl, $str) ;
 }

如果de query为OK(多个;允许使用分隔语句),则返回False;如果存在语法或其他MySQL其他MySQL(如不存在的表或列),则返回错误消息。

PHP Fiddle

KNOWN BUGS:

  • 亚麻布的MySQL错误:亚麻布大多不匹配。
  • 不适用于SELECT,UPDATE,REPLACE,INSERT,DELETE以外的MySQL语句

答案 1 :(得分:2)

您可以尝试使用此库:http://code.google.com/p/php-sql-parser/。我还没有使用它,所以我不能保证它,但代码看起来能够分辨出有效和无效的SQL之间的区别。

另一种选择可能是在SQL变体允许的情况下使用事务。事务将允许您执行SQL,然后在撤消已完成的任何损坏后取消它。我想我更喜欢选项1。

答案 2 :(得分:1)

您不能只解析和验证SQL,因为您需要检查表的存在,JOIN的有效性等。进行完整综合测试的唯一方法是实际运行查询。您可以将其包装在事务中然后回滚。但是,设计糟糕或恶意的查询仍然可能使您的服务器陷入困境或破坏数据。