【问题标题】:How to accept apostrophe in a form field for MySQL如何在 MySQL 的表单字段中接受撇号
【发布时间】:2015-07-13 08:23:48
【问题描述】:

我有一个表单,它接受一些姓名和电话号码,并将它们发布到 PHP 脚本,然后将这些值插入到 MySQL 表中。代码 (PHP) 非常简单,您可以在此处看到:

$sql = "INSERT INTO Contact_table (PHONE, NAME) VALUES ";
for ($i = 0; $i < $arr; ++$i){
    $sql .= "('".$numbers[$i]."', '".$names[$i]."'),";
}
$sql = substr($sql, 0, -1)." ON DUPLICATE KEY UPDATE name = COALESCE(VALUES(name), name);";
$connect = dbconn(PROJHOST,PROJDB,PROJDBUSER,PROJDBPWD);

$query = $connect->query($sql);
$connect = NULL;

除了拒绝接受像 O'Hara 或 D'Souza 这样的任何名字之外,这很完美。我隐约知道 PDO 的准备好的声明在这种情况下有一些用处,但我无法让它发挥作用。我尝试的是这样的:

$query = $connect->prepare($sql);
$query->execute();

而不是这个:

$query = $connect->query($sql);

有什么提示吗?我错过了什么?

【问题讨论】:

  • 您的代码不仅不适用于像 O'Hara 这样的名称,而且还有一个巨大的安全漏洞,容易受到 SQL 注入的影响。只需按照此处的建议...wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers .
  • 这就是我热衷于使用准备好的语句的确切原因(当然还有撇号问题),但它没有帮助,因此在这里。
  • 准备一个包含硬编码参数值的 SQL 语句是没有意义的......你需要类似 $stmt = $connect->prepare('INSERT INTO Contact_table (PHONE, NAME) VALUES(?, ?) ON DUPLICATE KEY UPDATE name = COALESCE(VALUES(name), name)');在循环之前,然后在循环内部: $stmt->execute(array($numbers[$i], $names[$i]));
  • @zgguy:感谢您的解释。但是,这不会导致很多查询,因为我们在循环的每次迭代中都执行一个查询吗?我的目标是将整个批处理作为单个查询执行,这就是为什么我在循环之后保留 query() 函数。另外,我刚刚了解了addslashes() 函数。这对注射足够安全吗?我问这个是因为这个功能确实解决了我的撇号问题。
  • 是的,它会引起很多查询,但是由于您只准备一次语句并执行多次,它为数据库节省了很多工作,因为不需要每次都解析和编译发出查询。您也可以尝试准备 INSERT INTO Contact_table (PHONE, NAME) VALUES (?, ?), (?, ?), ... 形式的语句,然后一次绑定所有变量。 addlashes() 将解决您的撇号问题,但准备好的语句绝对是要走的路,尤其是当您考虑到安全性时。

标签: mysql php prepared-statement


【解决方案1】:

有几种方法可以解决您的问题。你可以使用real_escape_string 转义你的字符串,但是你建议更好的方法。最好的方法是通过使用 mysqli 或 PDO 的准备好的语句。

既然你提到了 PDO,这是一种很好的方法,下面是如何处理它:

首先需要通过trycatch 运行连接,然后使用占位符运行查询,然后将变量绑定到这些占位符。以下是其工作原理的简单方法:

try {
$connect = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
 $stmt = $conn->prepare("INSERT INTO Contact_table (PHONE, NAME) VALUES (:PHONE, :NAME)");
 $stmt->bindParam(':PHONE', $PHONE);
 $stmt->bindParam(':NAME', $NAME);
//then name your variables like so
$PHONE = [whatever your phone number variable(s) is/are equal to];
$NAME = [whatever the NAME variable(s) is/are equal to];
$stmt->execute();
//note the last section can occur within a loop, much like you have above.
catch(PDOException $error)
}
{
echo "Error: " . $error->getMessage();
}
$connect = null;
}

请注意,这不仅允许任何带有特殊字符(例如撇号)的字段,对于大型查询,它的运行速度也会更快,并且具有更安全的额外好处,因为它几乎消除了大多数 SQL 注入方法.

您也可以使用 mysqli 准备好的语句来完成此操作,但是 PDO 具有与数据库无关的额外优势,因为可以轻松连接到 MySQL 以外的数据库。

此外,您可以将? 方法用于其中一个 cmets 中提到的松散定义的参数,但这也有助于将它们作为对象进行操作。

如果您想了解更多信息,这里是一个很好的参考:PHP Prepared Statements

【讨论】:

  • 感谢您的详细解释。但这仍然不能解决我的问题,因为我正在使用循环内构建的单个 INSERT 查询来整理多个(实际上是很多)插入操作。如果我使用 prepare-bind 方法(我确实想要),我无法将查询保留为单个实体,因为 execute() 函数必须在循环的每次迭代中运行一次。这可能会导致很多我想避免的查询。有什么方法可以使用prepare-bind,同时在我的原始代码中保留单查询目标?
  • 是的,任何时候你调用一个变量,你都可以用绑定的参数来替换它。例如$numbers[$i]$names[$i] 可以转换为参数,最好在调用之前将其转换为更清晰的变量。您也不应该需要多个参数。您始终可以通过 try 中的循环来获取多个值。您可以输入的数量也没有限制。只需在循环中通过$stmt-&gt;execute(); 运行每个变量迭代,它就会正常运行。这是关于准备好的陈述的最好的事情之一;
  • 为了缩短这个时间,您只需要一个查询。在对它们执行查询之前,您可以使用 whileforeach 循环获取这些其他项目。
  • 如果 $stmt->execute() 在循环中运行,由于每次迭代都会执行一次,它不会对数据库执行多个查询吗?
  • PDO 的工作方式是打开一个数据库连接,打开一个查询,然后放入它需要的所有行。 PDO 是类。所有这些都发生在try 中,并且在您完成之前它不会关闭连接。它将整个查询视为一个对象,execute 是其中一种方法,适用于您提供给它的属性。它实际上更高效,运行速度更快,具有更安全的巨大积极副作用。 “尝试”一下(双关语)。
猜你喜欢
  • 1970-01-01
  • 2016-07-27
  • 2012-03-24
  • 1970-01-01
  • 2012-08-18
  • 1970-01-01
  • 2013-09-30
  • 2022-11-15
相关资源
最近更新 更多