PDO — подключаем PHP к базе данных
30 минЧто такое PDO?
PDO (PHP Data Objects) — это встроенный в PHP способ работы с базами данных. Он:
- Работает с разными базами (MySQL, PostgreSQL, SQLite...)
- Защищает от SQL-инъекций
- Удобен в использовании
Создаём файл подключения
Обновите файл public/includes/config.php:
<?php
declare(strict_types=1);
/**
* Конфигурация сайта
*/
// Настройки сайта
$site_name = "Мой блог";
$site_description = "Блог о веб-разработке";
$current_year = date("Y");
// Загружаем переменные окружения из .env файла
// В PHP 8.1+ можно использовать parse_ini_file, но для простоты используем простой парсер
function loadEnv(string $filePath): void {
if (!file_exists($filePath)) {
return;
}
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
// Пропускаем комментарии
if (strpos(trim($line), "#") === 0) {
continue;
}
// Разделяем на ключ и значение
if (strpos($line, "=") !== false) {
[$key, $value] = explode("=", $line, 2);
$key = trim($key);
$value = trim($value);
// Убираем кавычки если есть
if ((strpos($value, "\"") === 0 && substr($value, -1) === "\"") ||
(strpos($value, "'") === 0 && substr($value, -1) === "'")) {
$value = substr($value, 1, -1);
}
// Устанавливаем переменную окружения, если её ещё нет
if (!isset($_ENV[$key])) {
$_ENV[$key] = $value;
}
}
}
}
// Загружаем .env файл (находится на уровень выше public/)
loadEnv(__DIR__ . "/../../.env");
// Настройки базы данных из переменных окружения
$db_host = $_ENV["MYSQL_HOST"] ?? "mysql"; // Имя контейнера из docker-compose
$db_name = $_ENV["MYSQL_DATABASE"] ?? "blog"; // Имя базы данных
$db_user = $_ENV["MYSQL_USER"] ?? "blog_user"; // Пользователь
$db_pass = $_ENV["MYSQL_PASSWORD"] ?? "blog_pass"; // Пароль
// Подключение к базе данных
try {
$pdo = new PDO(
"mysql:host=$db_host;dbname=$db_name;charset=utf8mb4",
$db_user,
$db_pass,
[
// Выбрасывать исключения при ошибках
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// Получать данные как ассоциативные массивы
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
// Отключить эмуляцию подготовленных запросов (безопаснее)
PDO::ATTR_EMULATE_PREPARES => false,
]
);
} catch (PDOException $e) {
// Если подключение не удалось
die("Ошибка подключения к базе данных: " . $e->getMessage());
}
// Подключаем функции-помощники
require_once __DIR__ . "/helpers.php";
?>
- Безопасность: Пароли не хранятся в коде, не попадут в Git
- Гибкость: Разные настройки для разработки и продакшна
- Стандарт: В 2026 это стандартная практика для всех PHP проектов
Разбор подключения
DSN (Data Source Name)
"mysql:host=$db_host;dbname=$db_name;charset=utf8mb4"
mysql:— тип базы данныхhost=mysql— адрес сервера (имя контейнера Docker)dbname=blog— имя базы данныхcharset=utf8mb4— кодировка (поддержка эмодзи)
try-catch
try {
// Пытаемся подключиться
} catch (PDOException $e) {
// Если ошибка — обрабатываем её
}
Если подключение не удастся (неправильный пароль, сервер недоступен), код в catch покажет ошибку вместо "белого экрана".
Проверяем подключение
Создайте файл public/test_db.php:
<?php
require_once "includes/config.php";
echo "<h1>Тест подключения к базе данных</h1>";
// Проверяем подключение
$stmt = $pdo->query("SELECT VERSION() as version");
$result = $stmt->fetch();
echo "<p>Версия MySQL: " . $result["version"] . "</p>";
// Получаем пользователей
$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll();
echo "<h2>Пользователи:</h2>";
echo "<ul>";
foreach ($users as $user) {
echo "<li>" . htmlspecialchars($user["username"]) . " — " . htmlspecialchars($user["email"]) . "</li>";
}
echo "</ul>";
// Получаем посты
$stmt = $pdo->query("SELECT * FROM posts ORDER BY created_at DESC");
$posts = $stmt->fetchAll();
echo "<h2>Посты:</h2>";
foreach ($posts as $post) {
echo "<article style='background:#f5f5f5; padding:15px; margin:10px 0;'>";
echo "<h3>" . htmlspecialchars($post["title"]) . "</h3>";
echo "<p>" . htmlspecialchars($post["content"]) . "</p>";
echo "</article>";
}
?>
Откройте http://localhost:8080/test_db.php. Если видите данные — подключение работает!
Подготовленные запросы — защита от SQL-инъекций
Что такое SQL-инъекция?
Представьте форму входа. Пользователь вводит логин, а мы подставляем его в запрос:
// ПЛОХО! Никогда так не делайте!
$username = $_POST["username"];
$sql = "SELECT * FROM users WHERE username = '$username'";
$pdo->query($sql);
Если злоумышленник введёт: ' OR '1'='1, запрос станет:
SELECT * FROM users WHERE username = '' OR '1'='1'
Это вернёт ВСЕХ пользователей, потому что '1'='1' всегда истина!
Подготовленные запросы — решение
// ХОРОШО!
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
Или с именованными параметрами:
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username");
$stmt->execute(["username" => $username]);
$user = $stmt->fetch();
PDO автоматически экранирует данные. Даже если пользователь введёт вредоносный код, он будет воспринят как обычный текст.
Основные методы PDO
| Метод | Что делает |
|---|---|
$pdo->query($sql) |
Выполнить простой запрос без параметров |
$pdo->prepare($sql) |
Подготовить запрос с параметрами |
$stmt->execute($params) |
Выполнить подготовленный запрос |
$stmt->fetch() |
Получить одну запись |
$stmt->fetchAll() |
Получить все записи |
$pdo->lastInsertId() |
ID последней добавленной записи |
$stmt->rowCount() |
Количество затронутых строк |
Примеры запросов
Получить одну запись
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([1]);
$user = $stmt->fetch();
if ($user) {
echo "Пользователь: " . $user["username"];
} else {
echo "Пользователь не найден";
}
Получить все записи
$stmt = $pdo->query("SELECT * FROM posts ORDER BY created_at DESC");
$posts = $stmt->fetchAll();
foreach ($posts as $post) {
echo $post["title"] . "<br>";
}
Добавить запись
$stmt = $pdo->prepare("INSERT INTO posts (user_id, title, content) VALUES (?, ?, ?)");
$stmt->execute([1, "Новый пост", "Содержимое поста"]);
$newId = $pdo->lastInsertId();
echo "Создан пост с ID: " . $newId;
Обновить запись
$stmt = $pdo->prepare("UPDATE posts SET title = ? WHERE id = ?");
$stmt->execute(["Обновлённый заголовок", 1]);
echo "Обновлено строк: " . $stmt->rowCount();
Удалить запись
$stmt = $pdo->prepare("DELETE FROM posts WHERE id = ?");
$stmt->execute([5]);
echo "Удалено строк: " . $stmt->rowCount();
✅ Подключаться к MySQL из PHP
✅ Использовать PDO безопасно
✅ Выполнять SELECT, INSERT, UPDATE, DELETE
В следующем уроке создадим функции для работы с данными блога!