Полный цикл в digital

Параметризация запросов PDO

Недостаток выше описаного скрипа заключается в том, что мы никак не констролируем присылаемые данные и сохраняем их в базу данных как есть. Что несет потенциальную угрозу безопасности, особенно при добавлении строк типа "DELETE FROM `Users`;. Кроме того, в ряде случае может быть проблематично добавить даже безопасные данные, например, строку, которая содержит одинарную кавычку, типа Tom O'Brian.

Для решения этих проблем PDO предлагает параметризацию запросов с помощью применения заранее подготовленных выражений - prepared statement. Выражения prepared statement вместо жестко установленных значений или переменных принимают параметры, которые не привязаны к конкретным значениям. Эти выражения prepared statement посылаются серверу базы данных до того, как станут известны используемые данные, что позволяет серверу приготовить их к выполнению, но при этом они не выполняются. А когда пользователь присылает данные - параметры заменяются пришедшими данными и выражение prepared statement выполняется.

Если требуется выполнить параметрический запрос, вначале необходимо его создать с помощью метода prepare:

// в обоих примерах за место знака ? подставится 2
$sql = "SELECT test_text FROM test_table WHERE id=?";
$stmt = $conn->prepare($sql);

Затем нужно связать параметры при помощи одного из двух методов:

  • bindValue() присваивает параметру конкретное значение жёстко фиксированное в коде
  • bindParam() присваивает параметру значение некоторой переменной
$stmt->bindValue(1,2);
$val=2;
$stmt->bindParam(1,$val);

После создания запроса и связывания параметров его можно выполнить при помощи метода execute():

$stmt->execute();

Напишем боевой пример с использованием bindValue():

<!DOCTYPE html>
<html>
<head>
<title>hmarketing.ru</title>
<meta charset="utf-8" />
</head>
<body>
<?php
if (isset($_POST["username"]) && isset($_POST["userage"])) {
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";
// определяем prepared statement
$stmt = $conn->prepare($sql);
// привязываем параметры к значениям
$stmt->bindValue(":username", $_POST["username"]);
$stmt->bindValue(":userage", $_POST["userage"]);
// выполняем prepared statement
$affectedRowsNumber = $stmt->execute();
// если добавлена как минимум одна строка
if($affectedRowsNumber > 0 ){
echo "Data successfully added: name=" . $_POST["username"] ."  age= " . $_POST["userage"];  
} 
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
}
?>
<h3>Create a new User</h3>
<form method="post">
<p>User Name:
<input type="text" name="username" />
</p>
<p>User Age:
<input type="number" name="userage" />
</p>
<input type="submit" value="Save">
</form>
</body>
</html>

В SQL-выражении теперь применяются параметры:

$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";

:username и :userage - это названия параметров. Причем они начинаются с символа двоеточия :.

Само выражение prepared statement создается с помощью метода prepare() объекта PDO, в который передается выполняемая sql-команда:

$stmt = $conn->prepare($sql);

Фактически здесь создается объект PDOStatement, который сохраняется в переменную $stmt.

Чтобы связать параметр с конкретным значением у объекта PDOStatement вызывается метод bindValue(). Первый параметр этого метода - собственно параметр из sql-команды, а второй параметр - передаваемое ему значение.

$stmt->bindValue(":username", $_POST["username"]);

Так, в данном случае параметр :username привязывается к значению из $_POST["username"]

Причем привязка может производиться и к конкретным значениям и обычным переменным, например:

$user = "Tom"
// привязка к переменной $user
$stmt->bindValue(":username", $user);

Для выполнения sql-выражения у объекта PDOStatement вызывается метод execute(), который для команды INSERT возвращает число добавленных строк.

Передача значений параметрам через массив по имени

В примере выше для параметризации применялся метод bindValue():

$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";
$stmt = $conn->prepare($sql);
// привязываем параметры к значениям
$stmt->bindValue(":username", $_POST["username"]);
$stmt->bindValue(":userage", $_POST["userage"]);
// выполняем prepared statement
$affectedRowsNumber = $stmt->execute();

Но есть и другой способ привязки параметров к значениям - мы можем передать в метод execute() параметры и их значения в виде ассоциативного массива:

$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";
$stmt = $conn->prepare($sql);
// через массив передаем значения параметрам по имени
$rowsNumber = $stmt->execute(array(":username" => $_POST["username"], ":userage" => $_POST["userage"]));

В этом случае названия параметров являются ключами.

Передача значений параметрам через массив по позиции

Третий способ привязки значений к параметрам представляет передачу значений по позиции:

$sql = "INSERT INTO Users (name, age) VALUES (?, ?)";
$stmt = $conn->prepare($sql);
// через массив передаем значения параметрам по позиции
$rowsNumber = $stmt->execute(array($_POST["username"], $_POST["userage"]));

В этом случае вместо названий параметров применяются знаки вопроса ?. Для передачи этим параметрам значений в метод execute() также передается массив. Первое значение массива привязывается к первому параметру (условно добавляется вместо первого знака вопроса), второе значение привязывается ко второму параметру и т.д.

Заполните форму уже сегодня!
Для начала сотрудничества необходимо заполнить заявку или заказать обратный звонок. В ответ получите коммерческое предложение, которое будет содержать индивидуальную стратегию с учетом требований и поставленных задач
Работаем по будням с 9:00 до 18:00. Заявки, отправленные в выходные, обрабатываем в первый рабочий день до 12:00.
Спасибо, ваш запрос принят и будет обработан!
Эйч Маркетинг