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

2022-08-30 08:31:46

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

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

答案 1

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

  1. 任何表示 SQL 数据文本(或者,简单地说 - SQL 字符串或数字)的变量都必须通过预准备语句添加。没有例外。
  2. 任何其他查询部分(如 SQL 关键字、表或字段名称或运算符)都必须通过白名单进行筛选。

因此,由于您的示例仅涉及数据文本,因此必须通过占位符(也称为参数)添加所有变量。为此,请执行以下操作:

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

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

使用 mysql ext 添加数据文本

这样的驱动程序不存在

使用添加数据文本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();

代码有点复杂,但所有这些运算符的详细说明可以在我的文章中找到,如何使用Mysqli运行INSERT查询,以及一个大大简化该过程的解决方案。

对于 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中,我们可以将绑定和执行部分组合在一起,非常方便。PDO还支持命名占位符,有些人发现这非常方便。

添加关键字或标识符

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

在这种情况下,必须根据脚本中显式编写的值列表检查变量。这在我的另一篇文章中进行了解释,根据用户的选择在 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"); 
}

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

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

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

答案 2

为避免 SQL 注入,请使用 be 插入语句

$type = 'testing';
$name = 'john';
$description = 'whatever';

$con = new mysqli($user, $pass, $db);
$stmt = $con->prepare("INSERT INTO contents (type, reporter, description) VALUES (?, ?, ?)");
$stmt->bind_param("sss", $type , $name, $description);
$stmt->execute();

推荐