我正在尝试在内容表中插入值。如果我在 VALUES 中没有 PHP 变量,它就可以正常工作。当我将变量
$type
放入 VALUES
中时,这不起作用。我做错了什么?
$type = 'testing';
mysql_query("INSERT INTO contents (type, reporter, description)
VALUES($type, 'john', 'whatever')");
在任何 MySQL 语句中添加 PHP 变量的规则简单明了:
这条规则涵盖了 99% 的查询,特别是您的查询。任何表示 SQL 数据文字(或者简单地说 - SQL 字符串或数字)的变量都必须通过准备好的语句添加。 无一例外。
此方法涉及四个基本步骤
以下是如何使用所有流行的 PHP 数据库驱动程序执行此操作:
mysqli
当前的 PHP 版本允许您在一次调用中完成准备/绑定/执行:
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
VALUES(?, ?, 'whatever')";
$mysqli->execute_query($query, [$type, $reporter]);
如果您的 PHP 版本较旧,则必须显式完成准备/绑定/执行:
$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 版本较旧,您将需要执行准备/绑定/执行例程,并添加对
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 (...)
$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 还支持命名占位符,有些人觉得这非常方便。
任何其他查询部分,例如 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";
为了避免 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();
最好的选择是准备好的陈述。乱搞引号和转义符是一项更难的工作,而且很难维护。迟早你会不小心忘记引用某些内容,或者最终转义同一个字符串两次,或者搞砸类似的事情。可能要过几年你才能发现这些类型的错误。
$type 中的文本直接替换到插入字符串中,因此 MySQL 得到:
... VALUES(testing, 'john', 'whatever')
请注意,测试周围没有引号,您需要将它们像这样放入:
$type = 'testing';
mysql_query("INSERT INTO contents (type, reporter, description) VALUES('$type', 'john', 'whatever')");
我还建议您阅读SQL注入,因为如果您不清理正在使用的数据,这种参数传递很容易遭受黑客攻击:
这是简单的答案:
$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'] .
"'";