Подготовленные заявления PHP MySQL
Подготовленные заявления PHP MySQL в основном используются для предотвращения атак SQL-инъекций и повышения производительности.
Подготовленные заявления отделяют данные от команд SQL.
Подготовленные заявления в основном работают следующим образом:
- Подготовка: Шаблон SQL-запроса с заполнителями отправляется на сервер. Значения данных не отправляются. Пример: INSERT INTO MyGuests VALUES(?, ?, ?). Затем сервер анализирует, компилирует и оптимизирует шаблон SQL-запроса без его выполнения
- Выполнение: Позже приложение связывает значения с параметрами, и база данных выполняет запрос. Приложение может выполнять запрос столько раз, сколько захочет, с разными значениями
Подготовленные заявления имеют четыре основных преимущества:
- Сокращение времени анализа — подготовка запроса выполняется только один раз (хотя выражение выполняется несколько раз)
- Минимизация пропускной способности — связанные параметры минимизируют пропускную способность на сервер, так как вам нужно отправлять только параметры каждый раз, а не весь запрос
- Безопасность — подготовленные заявления очень полезны против SQL-инъекций, потому что значения параметров, которые передаются позже с использованием другого протокола, не требуют правильного экранирования. Если исходный шаблон заявления не получен из внешнего ввода, SQL-инъекция невозможна
- Более чистый код — за счет отделения данных от команд SQL
Подготовленные заявления в MySQLi
В следующем примере используются подготовленные заявления в MySQLi:
Пример - MySQLi с подготовленными заявлениями
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
// Создаем подключение
$conn = new mysqli($servername, $username, $password, $dbname);
// Проверяем подключение
if ($conn->connect_error) {
die("Подключение не удалось: " . $conn->connect_error);
}
// Шаблон SQL-запроса
$sql = "INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)";
// Подготавливаем шаблон SQL-запроса
if($stmt = $conn->prepare($sql)) {
// Привязываем параметры
$stmt->bind_param("sss", $firstname, $lastname, $email);
//
Устанавливаем параметры и выполняем
$firstname = "Иван";
$lastname = "Петров";
$email = "ivan@example.com";
$stmt->execute();
$firstname = "Мария";
$lastname = "Иванова";
$email = "maria@example.com";
$stmt->execute();
$firstname = "Анна";
$lastname = "Сидорова";
$email = "anna@example.com";
$stmt->execute();
echo "Новые записи успешно созданы";
} else {
echo "Ошибка: " . $sql . "<br>" . $conn->error;
}
$stmt->close();
$conn->close();
?>
Пояснение к коду
В SQL вопросительные знаки (?) являются заполнителями для значений firstname, lastname и email:
"INSERT INTO MyGuests (firstname, lastname, email) VALUES (?, ?, ?)"
Теперь посмотрите на функцию bind_param(). Эта функция связывает переменные с заполнителями в SQL-запросе. Заполнители (?) будут заменены фактическими значениями, содержащимися в переменных в момент выполнения. Аргумент "sss" перечисляет тип данных, которыми является каждый параметр. Символ s сообщает mysql, что параметр является строкой. Мы должны определить один из таких символов для КАЖДОГО параметра. Сообщая mysql, какой тип данных ожидать, мы минимизируем риск SQL-инъекций:
$stmt->bind_param("sss", $firstname, $lastname, $email);
Аргумент типа может быть одного из четырех типов:
- i - integer (целое число)
- d - double (число с плавающей точкой)
- s - string (строка)
- b - binary (изображение, PDF и т.д.)
Примечание: Если мы хотим вставить данные из внешних источников (например, пользовательский ввод), очень важно, чтобы данные были очищены и проверены.
Подготовленные заявления в PDO
В следующем примере используются подготовленные заявления в PDO:
Пример - PDO с подготовленными заявлениями (аргументы с вопросительными знаками)
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// устанавливаем режим ошибок PDO в исключение
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
die("Не удалось подключиться. " .
$e->getMessage());
}
try {
$sql = "INSERT INTO
MyGuests (firstname, lastname, email) VALUES (?, ?, ?)";
// Подготавливаем шаблон SQL-запроса
$stmt = $conn->prepare($sql);
// Выполняем со значениями
$stmt->execute(['Иван', 'Петров', 'ivan@example.com']);
$stmt->execute(['Мария', 'Иванова', 'maria@example.com']);
$stmt->execute(['Анна', 'Сидорова', 'anna@example.com']);
echo "Новые записи успешно созданы";
} catch(PDOException $e)
{
echo "Ошибка: " . $e->getMessage();
}
$stmt =
null;
$conn = null;
?>
Пример - PDO с подготовленными заявлениями (именованные аргументы)
<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "myDB";
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// устанавливаем режим ошибок PDO в исключение
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
die("Не удалось подключиться. " .
$e->getMessage());
}
try {
$sql = "INSERT INTO
MyGuests (firstname, lastname, email) VALUES (:firstname, :lastname, :email)";
// Подготавливаем шаблон SQL-запроса
$stmt = $conn->prepare($sql);
// Привязываем параметры
$stmt->bindParam(':firstname', $firstname,
PDO::PARAM_STR);
$stmt->bindParam(':lastname', $lastname,
PDO::PARAM_STR);
$stmt->bindParam(':email', $email, PDO::PARAM_STR);
// Выполняем со значениями
$firstname = "Иван";
$lastname = "Петров";
$email = "ivan@example.com";
$stmt->execute();
$firstname = "Мария";
$lastname = "Иванова";
$email = "maria@example.com";
$stmt->execute();
$firstname = "Анна";
$lastname = "Сидорова";
$email = "anna@example.com";
$stmt->execute();
echo "Новые записи успешно созданы";
} catch(PDOException $e)
{
echo "Ошибка: " . $e->getMessage();
}
$stmt =
null;
$conn = null;
?>