Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 将准备好的语句包装到函数中_Php_Sql_Prepared Statement_Xss_Sql Injection - Fatal编程技术网

Php 将准备好的语句包装到函数中

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

我一直在阅读有关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($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"
  }
}