提问人: 提问时间:10/27/2019 最后编辑:Dharman 更新时间:10/27/2019 访问量:74
如何将此sql-injection-susceptible函数转换为MySQLi中准备好的函数?
How do I translate this sql-injection-susceptible function to a prepared function in MySQLi?
问:
我有两个易受 sql 注入影响的函数,我已经设法将第一个函数转换为准备好的函数,但我不明白如何转换第二个函数。这是原始的第一个:
function modify($sql, &$id)
{
$link = database_link();
$result = mysqli_query($link, $sql);
$insertId = mysqli_insert_id($link);
return mysqli_affected_rows($link);
}
我翻译为:
function preparedModify($sql, $types, &$insertId, ...$value)
{
$statement = mysqli_prepare(database_link(), $sql);
$statement->bind_param($types, ...$value);
$statement->execute();
$insertId = $statement->insert_id;
return $statement->affected_rows;
}
这奏效了,我很满意。这是我需要翻译的第二个函数:
function select($sql, &$rows)
{
$link = database_link();
$result = mysqli_query($link, $sql);
$rows = array();
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$rows[] = $row;
}
return mysqli_num_rows($result);
}
作为初学者,我完全不清楚我将如何翻译它。你能帮我,同时分解你的答案,指出你的翻译背后的策略是什么吗?因为我对第一个函数的策略只是在谷歌上搜索替代函数,这样我就设法完成了第一个函数,但我使用相同的方法对第二个函数一无所获。
答:
1赞
Your Common Sense
10/27/2019
#1
我不得不承认,运行准备好的 SELECT 查询有一个怪癖,因为你不能直接从语句中获取一个熟悉的数组,所以你将需要一个额外的函数调用。但至少你可以像使用其他函数一样开始,因为它是使用预准备语句运行函数的正确方法。get_result()
其他几点需要注意
- 我想每次调用它时都会创建一个新的数据库连接。永远不应该是这样,连接只能创建一次。因此,请先创建它,然后将该变量传递到所有函数调用中。
database_link()
$link
- 通过参数返回函数的结果是丑陋且不可读的,因此不受欢迎。而且您不必返回行计数 - 这毫无意义,因为您始终可以使用它来获取行计数。
count($rows)
- 将单独的变量放入函数调用中非常不方便,我通过艰难的方式学会了它。相反,将它们以数组的形式放置。这样,您将能够拥有单独的变量或已包含所有所需数据的单个变量。
鉴于我们可以根据我的 Mysqli 辅助函数创建一个易于使用和阅读的过程:
function select($link, $sql, $values = [], $types = '')
{
if (!$values) {
$result = $link->query($sql);
} else {
$types = $types ?: str_repeat("s", count($values));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($types, ...$values);
$stmt->execute();
$result = $stmt->get_result();
}
return $result->fetch_all(MYSQLI_ASSOC);
}
$link = database_link();
$rows = select($link, "SELECT * FROM employees WHERE salary > ?", [$gross]);
if ($rows) {
// you don't actually need even a count() call
}
0赞
Nick
10/27/2019
#2
如果您已经安装(以允许使用 mysqli_stmt::get_result
),则更改可能相当简单。第一部分与 相同,然后我们只使用 调用 ,函数的其余部分保持不变:mysqlnd
preparedModify
get_result
function preparedSelect($sql, $types, &$rows, ...$value)
{
$statement = mysqli_prepare(database_link(), $sql);
$statement->bind_param($types, ...$value);
$statement->execute();
$result = $statement->get_result();
$rows = array();
while ($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
$rows[] = $row;
}
return $statement->num_rows;
}
如前所述,您不需要循环来生成,您可以简单地使用:$rows
mysqli_result::fetch_all
$rows = $result->fetch_all(MYSQLI_ASSOC);
同样,这需要安装本机驱动程序。mysqlnd
评论
0赞
10/27/2019
请问您为什么选择使用而不是?num_rows
affected_rows
1赞
Nick
10/27/2019
@Doesitmatter 用于 和 查询。 用于查询。affected_rows
INSERT
UPDATE
DELETE
num_rows
SELECT
1赞
Dharman
10/27/2019
您不需要 while 循环。您可以只获取所有记录并返回。
1赞
Nick
10/27/2019
@Doesitmatter查询不应该有子句...这就是失败的原因。SELECT
VALUES
prepare
1赞
Nick
10/27/2019
@Doesitmatter REGEXP 表达式占位符也不应放在引号中。
评论
$rows