我一直在阅读有关 SQL 注入的文章,并决定修改我的代码以防止 SQL 注入。
例如,我有一个输入,我将其值插入到数据库中。最初,我对注射的防范是这样的:
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
// $data = addslashes($data);
$data = mysql_real_escape_string($data);
return $data;
}
$artist = $_POST["artist"]; // can be anything
$artist = test_input($artist); // escaped chars are &, quotes, <, >, \n, \r, etc.
if ($mysqli->query("SELECT * FROM `my_table` WHERE `artist` = '$artist'")->num_rows == 0) {
$mysqli->query("INSERT INTO my_table (artist) VALUES ('$artist')");
echo "New artist is added.";
} else {
echo "Artist already exists.";
}
在我读过的文章中,建议人们应该使用准备好的语句。我改变了我的代码并使用了它:
$artist = $_POST["artist"]; // can be anything
$query = $mysqli->prepare("SELECT * FROM my_table WHERE artist = ?");
$query->bind_param("s", $artist);
$query->execute();
$result = $query->get_result();
$query->close();
if ($result->num_rows == 0) {
echo "Artist doesn't exist in the DB." . PHP_EOL;
$query = $mysqli->prepare("INSERT INTO my_table (artist) VALUES (?)");
$query->bind_param("s", $artist);
$query->execute();
if ($query->affected_rows > 0) {
echo "Artist is added to the DB." . PHP_EOL;
}
$query->close();
} else {
echo "Artist already exists in the DB." . PHP_EOL;
}
虽然这可以防止 SQL 注入,但它对 XSS 没有任何作用。所以我决定修改test_input
(已删除$data = mysql_real_escape_string($data);
)并用它来防止脚本注入。
function test_input($data) {
$data = trim($data);
$data = stripslashes($data);
$data = htmlspecialchars($data);
return $data;
}
$artist = $_POST["artist"]; // can be anything
$artist = test_input($artist);
现在,我的问题是关于使用准备好的语句。我将插入三个项目;艺术家、专辑和歌曲。一遍又一遍地重复相同的过程(准备、绑定、执行、关闭)对我来说似乎是多余的。我想创建一个函数并用它包装准备好的语句过程。像这样的事情:
function p_statement($mysqli, $query_string = "", $type = "", $vars = []) {
$query = $mysqli->prepare($query_string);
$query->bind_param($type, $vars);
$query->execute();
$result = null;
preg_match("/^[A-Z]+/", $query_string, $command);
switch ($command[0]) {
case "SELECT":
$result = $query->get_result();
break;
case "INSERT":
$result = $query->affected_rows;
break;
}
$query->close();
return $result;
}
不过,这提出了一个问题:$vars
大批。由于将传递给的变量数量mysqli_stmt::bind_param()
将是可变/动态的,我在主函数中使用了一个数组p_statement
。我不知道应该如何将数组中的项目传递给mysqli_stmt::bind_param()
. bind_param
期望(type, var1, var2, varn,)
,我有一个数组。
我怎样才能做到这一点?