我有两个可通过sql-injection接受的函数,我设法将第一个函数转换为准备好的函数,但是我看不到如何转换第二个函数。这是原始的第一个:
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);
}
我完全不清楚我作为初学者如何翻译。您能同时帮您分解答案,指出翻译背后的策略是什么?因为我对第一个功能的策略只是谷歌搜索其他功能,所以我设法做到了第一个功能,但是使用相同的方法我对第二个功能一无所获。
如果已安装mysqlnd
(以允许使用mysqli_stmt::get_result
),则更改可能非常简单。第一部分与mysqli_stmt::get_result
相同,然后我们仅使用对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);
驱动程序。
我不得不承认,运行准备好的SELECT查询有一个怪癖,因为您不能直接从语句中获取熟悉的数组,因此您将需要一个附加的函数调用mysqlnd
。但是至少您应该以与其他函数相同的方式开始,因为这是使用预准备语句运行函数的正确方法。
需要注意的几件事
get_result()
都会创建一个新的数据库连接。绝不应该这样,连接只能创建一次。因此,首先创建它,然后将database_link()
变量传递到所有函数调用中。$link
来获取计数。 基于我们的count($rows)
,我们将创建一个易于使用和阅读的程序,
Mysqli helper function
我完全同意这里的先前建议。
但是首先:这是我认为您应该使用的prepareSelect()(如果您不想关心这里提到的所有其他事情):
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
}
另外一件事:我认为您正在混合使用面向对象的样式和过程样式
代替
function preparedSelect($sql, &$rows)
{
$mysqli = database_link();
$statement = $mysqli->prepare($sql);
$statement->execute();
$rows = $statement->get_result()->fetch_all(MYSQLI_ASSOC);
return $statement->get_result()->num_rows;
}
应该看起来像这样(面向对象)
$mysqli = database_link();
$statement = mysqli_prepare(database_link(), $sql);
$statement->bind_param($types, ...$value);