我一直在阅读有关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);
现在,我的问题是如何使用预先准备好的语句。我将插入三个项目;艺术家、专辑和歌曲。一遍又一遍地重复相同的过程(prepare、bind、execute、close)对我来说似乎是多余的。我想创建一个函数,并用它包装准备好的语句过程。类似这样:
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,)
,我得到了一个数组。
我如何能使这工作?
我找到了一种使用call_user_func_array解决问题的方法。
function p_statement($mysqli, $query_string = "", $type = "", $vars = []) {
$query = $mysqli->prepare($query_string);
// create an empty array
$parameters = array();
// push the type string into the array by reference
$parameters[] = & $type;
// push the items from $vars array into the array by reference
for ($i = 0; $i < count($vars); $i++) {
$parameters[] = & $vars[$i];
}
// call mysqli_stmt::bind_param with the $parameters array, which contains [type, var1, var2, ...]
call_user_func_array(array($query, "bind_param"), $parameters);
$query->execute();
$result = null;
preg_match("/^[A-Z]+/", $query_string, $command);
switch ($command[0]) {
case "SELECT":
$result = $query->get_result();
break;
case "INSERT":
case "UPDATE":
case "DELETE":
$result = $query->affected_rows;
break;
}
$query->close();
return $result;
}
$artist = "3 Doors Down";
$year = 2000;
$artist_select = p_statement($mysqli, "SELECT * FROM albums WHERE artist = ? AND year = ?", "si", [$artist, $year]);
var_dump($artist_select->fetch_all(MYSQLI_ASSOC));
输出:
array(1) {
[0]=>
array(3) {
["album"]=>
string(15) "The Better Life"
["year"]=>
int(2000)
["artist"]=>
string(12) "3 Doors Down"
}
}
<罢工>你在找内爆()
查看手册页,它显示了有关使用<code>call_user_func_array</code>的信息。我还编辑了你的一些片段。
function p_statement($mysqli, $query_string = "", $type = "", $vars = []) {
$query = $mysqli->prepare($query_string);
//assign $type to first index of $vars
array_unshift($vars, $type);
//Turn all values into reference since call_user_func_array
//expects arguments of bind_param to be references
//@see mysqli::bind_param() manpage
foreach ($vars as $key => $value) {
$vars[$key] =& $vars[$key];
}
call_user_func_array(array($query, 'bind_param'), $vars);
$query->execute();
//INSERT, SELECT, UPDATE and DELETE have each 6 chars, you can
//validate it using substr() below for better and faster performance
if (strtolower(substr($query_string, 0, 6)) == "select") {
$result = $query->get_result();
} else {
$result = $query->affected_rows;
}
$query->close();
return $result;
}
问题内容: 我一直在阅读有关SQL注入的文章,并决定修改我的代码以防止SQL注入。 例如,我有一个输入,将值插入到数据库中。最初,我的预防注射措施是: 在我读过的文章中,有人建议应该使用准备好的语句。我已经更改了代码并使用了它: 尽管这可以防止SQL注入,但是它对XSS并没有任何作用。因此,我决定修改(removed )并使用它来防止脚本注入。 现在,我的问题是关于使用准备好的语句。我将插入三个项
我有以下准备的一个准备好的声明失败了... 我在我的第一份准备好的声明中几乎有同样的准备,而且它进行得很好。我不确定是否我有两个准备好的声明,如果这是造成一个问题,或情况可能是什么? 现在我有个错误... 更新-可能的内部连接,像这样?
问题内容: 我一直在做的简单连接,: 虽然使用这个我一直使用的简单的方法,使查询之前逃脱的任何数据,不管是,,或者通过使用 现在我知道这在一定程度上是安全的! 它逃脱了危险人物;但是,它仍然容易受到其他攻击的攻击,这些攻击可能包含安全字符,但可能有害于显示数据或在某些情况下恶意修改或删除数据。 因此,我进行了一些搜索,以了解有关PDO,MySQLi和准备好的语句的信息。是的,我可能迟到了游戏,但是
问题内容: 我正在自定义由hibernate生成的插入SQL,并遇到了问题。当Hibernate自己生成查询时,它将数据插入表的前两列,但这会导致数据库错误,因为表的所有四列都是不可为空的。为了正确执行插入,它必须将相同的数据插入到新记录的两列中。这意味着我需要Hibernate将相同的数据绑定到我正在编写的查询(准备好的语句)中的两个不同的参数上。 是否有一些SQL语法可让我以与绑定到绑定语句不
问题内容: 在mysqli准备好的语句中,NULL变成’‘(对于字符串)或0(对于整数)。我想将其存储为真正的NULL。有什么办法吗? 问题答案: 我知道这是一个旧线程,但是可以将真实的NULL值绑定到准备好的语句(请阅读this)。 实际上,您可以使用mysqli_bind_parameter将NULL值传递给数据库。只需创建一个变量并将NULL值(请参见手册页)存储到该变量并将其绑定即可。无论