将准备好的语句包装在函数中 [英] Wrapping a prepared statement in a function
问题描述
我一直在阅读有关SQL注入的文章,并决定修改我的代码以防止SQL注入.
I've been reading articles about SQL Injection, and decided to modify my code to prevent SQL injection.
例如,我有一个输入,将该值插入到数据库中.最初,我的预防注射措施是:
For example, I have an input which I insert the value to my database. Initially, my guard against injection was this:
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.";
}
在我读过的文章中,有人建议应该使用准备好的语句.我已经更改了代码并使用了它:
In the articles I've read, it was suggested that one should use prepared statements. I've changed my code and used that:
$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);
)并使用它来防止脚本注入.
While this prevents SQL injection, it doesn't do anything about XSS. So I decided to modify test_input
(removed $data = mysql_real_escape_string($data);
) and use it to prevent script injection.
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);
现在,我的问题是关于使用准备好的语句.我将插入三个项目;艺术家,专辑和歌曲.一遍又一遍地重复相同的过程(准备,绑定,执行,关闭)对我来说似乎是多余的.我想创建一个函数,并用它包装准备好的语句过程.像这样:
Now, my problem is about using prepared statements. I'll be inserting three items; artist, album, and song. Repeating the same process (prepare, bind, execute, close) over and over again seems redundent to me. I want to create a function and wrap the prepared statement process with it. Something like this:
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,)
,并且我有一个数组.
Though, this presents a problem: $vars
array. Since the number of variables that'll be passed to mysqli_stmt::bind_param()
will be variable/dynamic, I've used an array in the main function p_statement
. I don't know how I should the pass the items in the array to the mysqli_stmt::bind_param()
. bind_param
expects (type, var1, var2, varn,)
, and I've got an array.
我该如何进行这项工作?
How can I make this work?
推荐答案
您正在寻找 implode()
查看联机帮助页,它显示了有关使用call_user_func_array
的信息.然后,我编辑了您的一些代码段.
Looking at to manpage and it shows a light about using call_user_func_array
. And I edit some of your snippet.
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;
}
这篇关于将准备好的语句包装在函数中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!