错误:SQLSTATE [42000]:语法错误或访问冲突:1064

时间:2013-06-08 08:44:04

标签: sql pdo panic

我在寻找最近3个小时的答案,我不知道该怎么做。这是代码:

    function get_data($tablename)
    {
        try
        {
            $conn = $this->conn();
            $stmt = $conn->prepare("SELECT * FROM :tablename ORDER BY id");
            $stmt->bindParam(':tablename', $tablename, PDO::PARAM_STR);
            $stmt->execute();
            return $stmt;
        }
        catch (Exception $e)
        {
            echo "ERROR:" . $e->getMessage();
        }
    }  

这是错误:

  

错误:SQLSTATE [42000]:语法错误或访问冲突:1064 SQL语法中有错误;检查与您的MySQL服务器版本相对应的手册,以便在第1行的''products'ORDER BY id'附近使用正确的语法

我做错了什么?...

2 个答案:

答案 0 :(得分:2)

如上所述here(感谢@YourCommonSense),您不能将参数用作表名;如果你这样做,将会发生以下两件事之一:

  1. 使用适当的预处理语句,预备语句模块将抛出异常(并且非常正确,因为您已经要求它执行不可能的操作)。
  2. 使用模拟的预准备语句,该参数将被盲目转义,单引号和替换,从而导致SQL语法错误。这就是这里发生的事情。
  3. 这就是问题所在。至于解决方案:

    • 重新评估您的数据库设计。您真的是否需要在不同的表中分割数据?如果没有,请将相关数据合并到一个表中,然后进行相应的查询。
    • 如果您对设计感到满意(或无法改变设计),您需要一个丑陋不安全的黑客,如下所示:

      function get_data($tablename, $acceptable_tablenames = array()) {
        /* $acceptable_tablenames is an array of strings, containing
         *  table names that you'll accept. It's your job to make sure
         *  these are safe; this is a much easier task than arbitrary
         *  sanitization.
         */
        if (array_search($tablename, $acceptable_tablenames, true) === FALSE) {
          throw new Exception("Invalid table name"); /* Improve me! */
        } else {
          /* your try/catch block with PDO stuff in it goes here
           * make sure to actually return the data
           */
        }
      }
      

      将其称为get_data($table, array("my_datatable_1", "my_datatable_2"))。感谢我在回答灵感时所链接的帖子。

答案 1 :(得分:0)

PDO使用单引号(')转义参数。需要使用反引号(`)来转义MySql表名。

在提供的示例中,tablename参数Products正在转义单引号。这是PDO引擎的一个安全功能,可以防止注入攻击。

假设$tablename的值在应用程序上下文中有意义(例如,验证当前用户可以看到指定表中的所有数据。)。

以下方法可行:

function get_data($tablename)
{
    try
    {
        $conn = $this->conn();
        $stmt = $conn->prepare("SELECT * FROM `" . str_replace("`","``",$tablename) . "` ORDER BY id;");
        $stmt->execute();
        return $stmt;
    }
    catch (Exception $e)
    {
        echo "ERROR:" . $e->getMessage();
    }
}