Я читал статьи о SQL Injection и решил изменить свой код, чтобы предотвратить 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,)
, и у меня есть массив.
Как это сделать?
Неа. 'implode'" склеивает "элементы массива и возвращает строку. Мне нужно передать элементы массива в качестве аргументов функции 'bind_param'. – akinuri
Вы пробовали? Второй аргумент bind_param похож на вызов func_get_args, но со ссылкой. Заблокировать ее - это единственный способ сделать это. Пока вы указываете количество совпадений и его тип (первые аргументы) – Chay22
Да. Он вызывает mysqli_stmt :: bind_param(): количество элементов в определении типа ... '. Как я уже сказал, implode возвращает одну строку, содержащую элементы массива. Элементы должны передаваться индивидуально в 'bind_param'. 'bind_param (type, string1, string2)', а не 'bind_param (type," string1, string2 ")'. Можете ли вы переписать функцию 'p_statement' и показать ее здесь? Может быть, я делаю что-то неправильно. – akinuri