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

Posted

技术标签:

【中文标题】如何在 MySQL 语句中包含 PHP 变量【英文标题】:How to include a PHP variable inside a MySQL statement 【发布时间】:2011-09-24 06:12:08 【问题描述】:

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

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

【问题讨论】:

重要提示: 将变量直接插入 SQL 是SQL Injection Attacks的主要来源 【参考方案1】:

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

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

因此,由于您的示例仅涉及数据文字,因此必须通过占位符(也称为参数)添加所有变量。这样做:

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

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

使用 mysql ext 添加数据文字

这样的司机doesn't exist。

使用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 还支持命名占位符,有些人觉得这非常方便。

添加关键字或标识符

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

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

不幸的是,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";

【讨论】:

【参考方案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();

【讨论】:

如果我试图显示一个配置文件,并且在我的 $stmt 我有 'SELECT * FROM Profile WHERE profile_id LIKE (?)' .. 我只有一个参数可以插入我的SQL,我该怎么做?【参考方案3】:

最好的选择是准备好的语句。 使用引号和转义符开始变得更加困难,并且难以维护。迟早你会不小心忘记引用某些东西,或者两次转义相同的字符串,或者搞砸类似的东西。可能需要数年才能找到此类错误。

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

【讨论】:

【参考方案4】:

$type 中的文本直接替换为插入字符串,因此 MySQL 得到:

... VALUES(testing, 'john', 'whatever')

请注意,测试周围没有引号,您需要像这样将它们放入:

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

我还建议您阅读SQL injection,因为如果您不清理正在使用的数据,这种参数传递很容易遭到黑客攻击:

MySQL - SQL Injection Prevention

【讨论】:

【参考方案5】:

答案很简单:

$query="SELECT * FROM CountryInfo WHERE Name = '".$name."'";

然后你定义 $name 任何你想要的。 而另一种方式,复杂的方式,是这样的:

$query = " SELECT '" . $GLOBALS['Name'] . "' .* " .
         " FROM CountryInfo " .
         " INNER JOIN District " .
         " ON District.CountryInfoId = CountryInfo.CountryInfoId " .
         " INNER JOIN City " .
         " ON City.DistrictId = District.DistrictId " .
         " INNER JOIN '" . $GLOBALS['Name'] . "' " .
         " ON '" . $GLOBALS['Name'] . "'.CityId = City.CityId " .
         " WHERE CountryInfo.Name = '" . $GLOBALS['CountryName'] .
         "'";

【讨论】:

....但这也是所有答案中最危险的。您甚至没有尝试以任何方式避免 SQL 注入,并且应该从不使用此类代码

以上是关于如何在 MySQL 语句中包含 PHP 变量的主要内容,如果未能解决你的问题,请参考以下文章

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

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

如何在执行立即语句中包含变量?

如何在多行 innerHTML 属性的 javascript 中包含 if 语句?

php我如何在变量中包含@

PHP计算在许多列中包含相同值的MYSQL行