PHP`Create Table`在表名中包含引号

PHP`Create Table`在表名中包含引号,php,mysql,database-design,mariadb,create-table,Php,Mysql,Database Design,Mariadb,Create Table,我遇到了一个奇怪的问题,创建一个表会在数据库中的表名中添加反勾号 public function create_table($name) { $sql = " CREATE TABLE IF NOT EXISTS `?` ( id int(11) NOT NULL AUTO_INCREMENT, url varchar(255) NOT NULL, resolved tinyint(1) NOT NULL,

我遇到了一个奇怪的问题,创建一个表会在数据库中的表名中添加反勾号

public function create_table($name)
{
    $sql = "
        CREATE TABLE IF NOT EXISTS `?` (
          id int(11) NOT NULL AUTO_INCREMENT,
          url varchar(255) NOT NULL,
          resolved tinyint(1) NOT NULL,
          PRIMARY KEY (id)
        )";

    $query = $this->_pdo->prepare($sql);


    $query->bindValue(1, $name);

    if($query->execute())
    {
        print("Created");
    }
    else
    {
        var_dump($query->errorInfo());
    }   
}
我这样做并绑定$name的原因是,它将由一个web爬虫动态完成,我正在寻找常见的文件和目录名,并且由于可收集的大量路径,我决定为每个站点创建一个表,并根据其主机名生成其名称。可能存在的不可靠主机名示例:

但这导致了这一点

所以我试着不带它们,结果它抛出了一个错误

您的SQL语法有错误;查看与您的MariaDB服务器版本相对应的手册,以了解可在近随机_站点使用的正确语法

我没有看到或思考的是什么,我已经有一段时间没有使用PHP了,我不知所措,因为我所有的搜索都让我明白了为什么在进行一个不属于我的问题的查询时,表名应该用反勾号括起来

谢谢

信息:MariaDB
PHP:7.4.6

这是因为您绑定的是一个字符串值,所以它被注入了周围的单引号。但归根结底,您不能将表名作为参数传递到查询中。绑定机制旨在传递文本值,而表名显然不是

在这种特定情况下,除了字符串串联之外,您没有其他选择:

$sql = "
    CREATE TABLE IF NOT EXISTS `$name` (
      id int(11) NOT NULL AUTO_INCREMENT,
      url varchar(255) NOT NULL,
      resolved tinyint(1) NOT NULL,
      PRIMARY KEY (id)
    )";

$query = $this->_pdo->prepare($sql);
if ($query->execute()) { 
    ... 
} else {
    ... 
}
这意味着您需要在将变量传递给查询之前在应用程序端彻底验证变量,这不是一项容易的任务


这最终提出了一个问题,为什么每个站点都有一个单独的表。我不推荐这种设计,因为它违反了基本的规范化规则,很快就会变成维护的噩梦。相反,您应该有一个列出站点的引用表,和一个用于所有路径的表,以及一个引用站点表的外键列。使用正确的模式和索引,您不太可能遇到性能问题,除非您有无数行,在这种情况下,还可以使用其他选项,例如逻辑分区。

这是因为您绑定的是字符串值,所以它会被周围的单引号所插入。但归根结底,您不能将表名作为参数传递到查询中。绑定机制旨在传递文本值,而表名显然不是

在这种特定情况下,除了字符串串联之外,您没有其他选择:

$sql = "
    CREATE TABLE IF NOT EXISTS `$name` (
      id int(11) NOT NULL AUTO_INCREMENT,
      url varchar(255) NOT NULL,
      resolved tinyint(1) NOT NULL,
      PRIMARY KEY (id)
    )";

$query = $this->_pdo->prepare($sql);
if ($query->execute()) { 
    ... 
} else {
    ... 
}
这意味着您需要在将变量传递给查询之前在应用程序端彻底验证变量,这不是一项容易的任务


这最终提出了一个问题,为什么每个站点都有一个单独的表。我不推荐这种设计,因为它违反了基本的规范化规则,很快就会变成维护的噩梦。相反,您应该有一个列出站点的引用表,和一个用于所有路径的表,以及一个引用站点表的外键列。使用正确的模式和索引,您不太可能遇到性能问题,除非您有无数行,在这种情况下,可以使用其他选项,例如逻辑分区。

这些是引号,而不是反勾号。不能绑定表名。它之所以被引用是因为您绑定了它,然后它在backticks中被执行,所以您所说的实际名称是“+name+”。您应该创建一个包含所有可能名称的数组,并与之进行比较。请看白名单检查。@user3783243谢谢,这就是我所想的,只是我不确定,所以在这里被问到。我实际上认为您当前的实现可以被注入。我不认为prepared语句会碰到反勾号,或者恶意用户会关闭create命令并执行其他操作。假设仿真是基于$name的确切值是多少?@Martin$name本来是动态的,但在阅读了@GMB的答案后,我想我将改变我的方式,这些是引号,而不是反勾号。不能绑定表名。它之所以被引用是因为您绑定了它,然后它在backticks中被执行,所以您所说的实际名称是“+name+”。您应该创建一个包含所有可能名称的数组,并与之进行比较。请看白名单检查。@user3783243谢谢,这就是我所想的,只是我不确定,所以在这里被问到。我实际上认为您当前的实现可以被注入。我不认为prepared语句会碰到反勾号,或者恶意用户会关闭create命令并执行其他操作。假设仿真是在上,$name的确切值是多少?@Martin$name本来是动态的,但在阅读了@GMB的答案后,我想我会改变我将要做的方式。我想清理名称应用程序端并将其浓缩是解决方案,但我想在这里问一下,以防我遗漏了什么。谢谢,非常感谢。@akaBase:你可能想把答案读到最后。简言之,我认为你应该
改变你的设计…谢谢,值得思考!我在想,清理名称应用程序端,然后像这样对其进行合并是解决方案,但我想在这里问一下,以防我遗漏了什么。谢谢,非常感谢。@akaBase:你可能想把答案读到最后。简言之,我认为你应该改变你的设计……谢谢,值得深思!