3

我一直在寻找过去 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();
        }
    }  

这是错误:

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

我做错了什么?...

4

2 回答 2

3

如此处所述(感谢@YourCommonSense),您不能将参数用作表名;如果你这样做,将会发生以下两种情况之一:

  1. 使用适当的准备好的语句,准备好的语句模块将抛出异常(这是非常正确的,因为您已经要求它完成不可能的事情)。
  2. 使用模拟的prepared statements,参数将被盲目转义、单引号和替换,导致SQL语法错误。这就是这里发生的事情。

那就是问题所在。至于解决方案:

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

    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")). 感谢在我的答案开头链接到的帖子以获得灵感。

于 2013-06-08T09:25:12.313 回答
0

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

在提供的示例中,表名参数 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();
    }
}
于 2013-06-08T08:52:24.203 回答