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

标签 php mysql sql string variables

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

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

最佳答案

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

1。使用准备好的语句

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

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

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

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

使用 mysqli 添加数据文字

当前的 PHP 版本允许您在一次调用中完成准备/绑定(bind)/执行:

$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description) 
             VALUES(?, ?, 'whatever')";
$mysqli->execute_query($query, [$type, $reporter]);

如果您的 PHP 版本较旧,则必须显式完成准备/绑定(bind)/执行:

$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 查询,您可以使用与上述相同的方法:

$reporter = "John O'Hara";
$result = $mysqli->execute_query("SELECT * FROM users WHERE name=?", [$reporter]);
$row = $result->fetch_assoc(); // or while (...)

但同样,如果您的 PHP 版本较旧,您将需要执行准备/绑定(bind)/执行例程并添加对 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 关键字、表或字段名称或运算符 - 都必须通过白名单进行过滤。

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

在这种情况下,必须根据脚本中明确编写的值列表检查您的变量。这在我的另一篇文章 Adding a field name in the ORDER BY clause based on the user's choice 中有解释。 :

Unfortunately, PDO has no placeholder for identifiers (table and field names), therefore a developer must filter them out manually. Such a filter is often called a "white list" (where we only list allowed values) as opposed to a "black-list" where we list disallowed values.

So we have to explicitly list all possible variants in the PHP code and then choose from them.

这是一个例子:

$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"); 
}

Exactly the same approach should be used for the direction,

$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";

关于php - 如何在 MySQL 语句中包含 PHP 变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58786337/

相关文章:

MySQL:CASE 语句问题

mysql - 在mysql中选择两个用户通信之间的最新消息

sql - 如何限制CTE递归深度但选择通用表?

php - Windows 上的 nohup,无需等待完成即可执行

java - 如何在thrift中使用PHP和JAVA

sql - MySQL查询查找订购了两种特定产品的客户

sql - Presto:将 array<struct<key:string,value:array<string>>> 转换为 map<string,array<string>>

php - 发现那一天

php - 阿拉伯语的 mysql 和 UTF8 问题

MySQL 使用 Group By 来限制结果