Взаимодействие PHP с MySQL через PDO
Студент освоит безопасное подключение к базе данных с помощью PDO, научится выполнять CRUD-операции и защищаться от SQL-инъекций.
Введение в работу с базами данных в PHP. На предыдущих уроках мы изучили основы языка PHP 8 и принципы объектно-ориентированного программирования. Теперь пришло время сделать наше приложение динамическим. Интернет-магазин не может существовать без базы данных: именно там хранятся товары, пользователи, заказы и настройки. В экосистеме PHP стандартом де-факто для работы с базами данных является расширение PDO (PHP Data Objects). PDO предоставляет абстрактный уровень доступа к данным, что означает единый интерфейс (набор методов) для работы с различными СУБД, будь то MySQL, PostgreSQL или SQLite. Главное преимущество PDO заключается в его безопасности и объектно-ориентированной архитектуре. В прошлом разработчики часто использовали процедурные функции вроде mysqli_query, что нередко приводило к уязвимостям. Метод прямого обучения (Direct Instruction) требует от нас четкого понимания: никогда не доверяйте пользовательскому вводу. PDO решает проблему SQL-инъекций через механизм подготовленных выражений (Prepared Statements), который мы детально разберем. Для начала работы нам необходимо сформировать DSN (Data Source Name) — строку, содержащую информацию для подключения к базе данных.
php
$dsn = 'mysql:host=localhost;dbname=shop;charset=utf8mb4';
$pdo = new PDO($dsn, 'root', 'password', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]);
Разбор подключения и обработки ошибок. Давайте детально проанализируем код выше. Переменная $dsn содержит драйвер (mysql), хост, имя базы данных и кодировку. Использование кодировки utf8mb4 критически важно для корректного сохранения любых символов, включая эмодзи, что часто встречается в отзывах товаров. При создании объекта PDO мы передаем DSN, имя пользователя и пароль. Четвертый аргумент — это массив опций. Здесь мы применяем принцип Scaffolding (постепенное усложнение), сразу задавая правильные настройки для production-среды. PDO::ATTR_ERRMODE со значением PDO::ERRMODE_EXCEPTION заставляет PDO выбрасывать исключения (Exceptions) при любых ошибках SQL. Это позволяет перехватывать их с помощью блоков try-catch и избегать вывода чувствительной информации пользователю. PDO::ATTR_DEFAULT_FETCH_MODE со значением PDO::FETCH_ASSOC указывает, что по умолчанию данные из базы будут возвращаться в виде ассоциативных массивов, где ключами являются названия столбцов таблицы. Это наиболее удобный формат для последующей передачи данных в шаблоны или преобразования в JSON. Если не задать этот параметр, PDO вернет массив, содержащий данные как по ассоциативным ключам, так и по числовым индексам, что удвоит потребление памяти.
Подготовленные выражения и защита от SQL-инъекций. SQL-инъекция — это атака, при которой злоумышленник внедряет вредоносный SQL-код через формы ввода. Представьте запрос: 'SELECT * FROM users WHERE email = ' . $email. Если $email равно 'admin@mail.com' OR '1'='1', запрос вернет данные всех пользователей. PDO решает это с помощью методов prepare() и execute(). При использовании prepare() база данных сначала компилирует структуру запроса, а лишь затем, при вызове execute(), подставляет данные. Данные отправляются отдельно от самого запроса, что делает невозможным изменение логики SQL-команды. Вместо реальных значений в строке запроса мы используем именованные плейсхолдеры, например :price. Это краеугольный камень безопасности любого веб-приложения. В контексте архитектуры интернет-магазина, когда мы фильтруем каталог товаров по цене, категории или поисковому запросу, все эти данные поступают от клиента (через GET-параметры) и должны проходить через подготовленные выражения.
php
$stmt = $pdo->prepare('SELECT * FROM products WHERE price > :price');
$stmt->execute(['price' => 100]);
$products = $stmt->fetchAll();
foreach ($products as $product) {
echo $product['name'] . ' - $' . $product['price'] . '<br>';
}
Какую константу PDO необходимо передать в настройки подключения (опции), чтобы результаты запросов по умолчанию возвращались в виде ассоциативного массива?
Какой механизм в PDO является основным для защиты от SQL-инъекций при передаче пользовательских данных в запрос?
Задание
Сценарий: Вам необходимо реализовать функцию добавления нового товара в базу данных из административной панели. Разработайте алгоритм действий с использованием PDO.
- Создать объект подключения PDO с обработкой исключений.
- Подготовить SQL-запрос INSERT INTO products с именованными плейсхолдерами (:name, :price).
- Вызвать метод execute(), передав ассоциативный массив с данными из формы.
- Проверить успешность выполнения и получить ID добавленной записи через lastInsertId().