如何在 MySQL 语句中包含 PHP 变量

新手上路,请多包涵

我正在尝试在目录表中插入值。如果我在 VALUES 中没有 PHP 变量,它工作正常。当我将变量 $type 放入 VALUES ,这不起作用。我究竟做错了什么?

 $type = 'testing';
mysql_query("INSERT INTO contents (type, reporter, description)
     VALUES($type, 'john', 'whatever')");

原文由 Pinkie 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 684
2 个回答

在任何 MySQL 语句中添加 PHP 变量的规则很简单:

1. 使用准备好的语句

此规则涵盖 99% 的查询,尤其是您的查询。任何表示 SQL 数据文字 的变量,(或者,简单地说 - SQL 字符串或数字)都必须通过准备好的语句添加。 _没有例外_。

这种方法包括四个基本步骤

  • 在您的 SQL 语句中,将所有变量替换为 占位符
  • 准备 结果查询
  • 将变量 绑定 到占位符
  • 执行 查询

以下是如何使用所有流行的 PHP 数据库驱动程序:

使用 mysqli 添加数据文字
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
             VALUES(?, ?, 'whatever')";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("ss", $type, $reporter);
$stmt->execute();

代码有点复杂,但所有这些运算符的详细解释可以在我的文章 How to run an INSERT query using Mysqli 中找到,以及显着简化该过程的解决方案。

对于 SELECT 查询,您只需添加对 get_result() 方法的调用即可获得熟悉的 mysqli_result ,您可以通过通常的方式从中获取数据:

 $reporter = "John O'Hara";
$stmt = $mysqli->prepare("SELECT * FROM users WHERE name=?");
$stmt->bind_param("s", $reporter);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc(); // or while (...)

使用 PDO 添加数据文字
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
             VALUES(?, ?, 'whatever')";
$stmt = $pdo->prepare($query);
$stmt->execute([$type, $reporter]);

在 PDO 中,我们可以将 bind 和 execute 部分结合起来,非常方便。 PDO 还支持命名占位符,有些人觉得这非常方便。

2.使用白名单过滤

任何其他查询部分,例如 SQL 关键字、表或字段名称或运算符 - 都必须通过 白名单 进行过滤。

有时我们必须添加一个表示查询的另一部分的变量,例如关键字或标识符(数据库、表或字段名称)。这是一种罕见的情况,但最好做好准备。

在这种情况下,必须根据脚本中 明确 写入的值列表检查您的变量。这在我的另一篇文章中进行了解释, 根据用户的选择在 ORDER BY 子句中添加字段名称

不幸的是,PDO 没有标识符(表和字段名)的占位符,因此开发人员必须手动过滤掉它们。这样的过滤器通常称为“白名单”(我们只列出允许的值),而不是列出不允许的值的“黑名单”。

因此,我们必须明确列出 PHP 代码中所有可能的变体,然后从中进行选择。

这是一个例子:

 $orderby = $_GET['orderby'] ?: "name"; // set the default value
$allowed = ["name","price","qty"]; // the white list of allowed field names
$key = array_search($orderby, $allowed, true); // see if we have such a name
if ($key === false) {
    throw new InvalidArgumentException("Invalid field name");
}

方向应该使用完全相同的方法,

 $direction = $_GET['direction'] ?: "ASC";
$allowed = ["ASC","DESC"];
$key = array_search($direction, $allowed, true);
if ($key === false) {
    throw new InvalidArgumentException("Invalid ORDER BY direction");
}

在这样的代码之后, $direction$orderby 变量可以安全地放入 SQL 查询中,因为它们要么等于允许的变体之一,要么会引发错误。

关于标识符的最后一件事是,它们还必须根据特定的数据库语法进行格式化。对于 MySQL,它应该是 backtick 标识符周围的字符。因此,我们的示例订单的最终查询字符串将是

$query = "SELECT * FROM `table` ORDER BY `$orderby` $direction";

原文由 Your Common Sense 发布,翻译遵循 CC BY-SA 4.0 许可协议

最好的选择是准备好的陈述。 开始使用引号和转义符是一项更难的工作,也难以维护。迟早你会不小心忘记引用某些内容,或者两次转义相同的字符串,或者搞砸类似的事情。可能需要几年时间才能找到这些类型的错误。

http://php.net/manual/en/pdo.prepared-statements.php

原文由 Tel 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏