Php 将准备好的语句包装到函数中
我一直在阅读有关SQL注入的文章,并决定修改代码以防止SQL注入Php 将准备好的语句包装到函数中,php,sql,prepared-statement,xss,sql-injection,Php,Sql,Prepared Statement,Xss,Sql Injection,我一直在阅读有关SQL注入的文章,并决定修改代码以防止SQL注入 function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; } $artist = $_POST["artist"]; // can be anything $artist = test_input($art
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 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.";
}
虽然这可以防止SQL注入,但它对XSS没有任何作用。所以我决定修改test\u input
(删除$data=mysql\u real\u escape\u 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_语句中使用了一个数组。我不知道如何将数组中的项传递给mysqli_stmt::bind_param()
bind_param
需要(type,var1,var2,varn,)
,我得到了一个数组
我怎样才能完成这项工作?您正在寻找的
查看手册页,它显示了如何使用call\u user\u func\u array
。我编辑了你的一些片段
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;
}
我已经找到了一种方法来解决这个问题
产出:
array(1) {
[0]=>
array(3) {
["album"]=>
string(15) "The Better Life"
["year"]=>
int(2000)
["artist"]=>
string(12) "3 Doors Down"
}
}
没有<代码>内爆
将数组项“粘合”在一起并返回字符串。我需要将数组项作为参数传递给bind_param
函数。您尝试过吗?bind_param的第二个参数有点像调用func_get_参数,但带有引用。逗号分隔它,是唯一的方法。只要您提供匹配的计数和它的类型(第一个参数)是。它抛出mysqli\u stmt::bind\u param():类型定义中的元素数…
。正如我所说,内爆返回一个包含数组项的字符串。项目需要单独传递到bind_param
<代码>绑定参数(类型,string1,string2),而不是绑定参数(类型,“string1,string2”)
。您能否重写p_语句
函数并在此处显示它?也许我做错了什么。
$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"
}
}