Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Подготовленные запросы PHP PDO: Работа с базой данных

Как правило, запросы в базу формируются динамически на основе данных, которые поступают извне. Например, создание пользователя чаще всего происходит во время регистрации. В таком случае код вставки выглядит так:

$name = 'Tota';
$phone = '1234';

$sql = "INSERT INTO users (username, phone) VALUES ('{$name}', '{$phone}')";

$conn->exec($sql);

Составленные таким образом запросы несут в себе серьезную опасность — SQL-инъекции. Вместо обычных данных злоумышленник может отправить текст, который изменит SQL-запрос. Представьте, что внутри переменной $phone хранилась бы такая строка:

$phone = "'); INSERT INTO users (username, phone) VALUES ('i am hacker', '777777); --";

В таком случае после подстановки мы бы получили следующий запрос:

INSERT INTO users (username, phone) VALUES ('somename', '');
INSERT INTO users (username, phone) VALUES ('i am hacker', '777777');

Фактически, вместо одного запроса получилось два. Таким образом, злоумышленник может выполнить произвольный запрос в базу данных — то есть удалить, добавить или изменить все, что ему хочется.

В разработке существует правило «Никогда не доверяй пользовательским данным» — оно особенно важно в работе с базами данных. Любые данные перед вставкой нужно экранировать с помощью подготовленных запросов:

$sql = "INSERT INTO users (username, phone) VALUES (:name, :phone)";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':phone', $phone);

$name = 'Tota';
$phone = '12345';
$stmt->execute();

Подготовленные запросы создаются с помощью плейсхолдеров. Это заполнители, которые расставляются в местах, где ожидается подстановка данных. При этом плейсхолдеры не нужно оборачивать в кавычки, если это строки, драйвер сделает это автоматически.

Плейсхолдеры могут быть не только именованные, но и позиционные, в виде знака вопроса ?

$sql = "INSERT INTO users (username, phone) VALUES (?, ?)";
$stmt = $conn->prepare($sql);
$stmt->bindParam(1, $name);
$stmt->bindParam(2, $phone);

$name = 'Tota';
$phone = '12345';
$stmt->execute();

Заполнение данными выполняется с помощью метода bindParam(). Метод принимает на вход два обязательных параметра:

  • Идентификатор параметра. Для подготавливаемых запросов с именованными параметрами это будет имя в виде :name. Если используются позиционные параметры, то это будет позиция плейсхолдера в запросе, начиная с 1
  • Данные, которые нужно подставить

Ускорение запросов

Кроме того, подготовленные запросы могут работать быстрее обычных. Дело в том, что мы можем выполнять множество запросов подряд в рамках одного подготовленного запроса. При использовании подготовленного запроса СУБД анализирует и оптимизирует запрос только один раз, а приложение запускает на выполнение уже подготовленный шаблон. За счет этого ускоряется работа

$sql = "INSERT INTO users (username, phone) VALUES (:name, :phone)";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':phone', $phone);

$name = 'Tota';
$phone = '12345';
$stmt->execute();

// Выполняем уже подготовленный запрос с другими данными
$name = 'Anna';
$phone = '9876';
$stmt->execute();

Возврат идентификатора

Когда мы вставляем данные в базу, иногда нам нужно получить идентификатор вставленной записи и потом использовать его в коде. Например, когда мы создаем какую-то сущность и хотим потом ее использовать:

$user = new User();
// Сохраняем пользователя в базу данных
// После этого становится доступен id
$user->getId();
// Его можно использовать для формирования ссылок или вставки связанных записей

Чтобы выполнить эту задачу, используем метод lastInsertId(), который возвращает идентификатор последней вставленной записи в виде строки

$sql = "INSERT INTO users (username, phone) VALUES (:name, :phone)";
$stmt = $conn->prepare($sql);
$stmt->bindParam(':name', $name);
$stmt->bindParam(':phone', $phone);

$name = 'Tota';
$phone = '12345';
$stmt->execute();
$id = $conn->lastInsertId(); // 1

Самостоятельная работа

  • Выполните шаги из урока у себя на компьютере
  • Добавьте в базу данных несколько пользователей, используя один подготовленный запрос
  • Используя подготовленный запрос, удалите одного из созданных пользователей по его имени

Дополнительные материалы

  1. Подготовленные запросы

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Занимайтесь созданием сайтов, веб-приложений, сервисов и их интеграцией с внутренними бизнес-системами на бекенд-языке PHP
10 месяцев
с нуля
Старт 12 сентября

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»
Изображение Тото

Задавайте вопросы, если хотите обсудить теорию или упражнения. Команда поддержки Хекслета и опытные участники сообщества помогут найти ответы и решить задачу