Разработка на PHP и MySQL: практические примеры и лучшие практики
Создание сайтов на PHP и MySQL: практическое руководство
Как обеспечить безопасное и эффективное взаимодействие с базой данных?
Основное решение: использование PDO с подготовленными запросами
PDO (PHP Data Objects) - это расширение для работы с базами данных, которое предоставляет единый интерфейс для разных СУБД. Оно позволяет выполнять подготовленные запросы, что предотвращает SQL-инъекции и улучшает производительность при многократном выполнении однотипных запросов.
// Подключение к MySQL через PDO
$host = 'localhost';
$dbname = 'test';
$user = 'root';
$password = '';
try {
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8", $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Ошибка подключения: ' . $e->getMessage());
}
// Подготовленный запрос INSERT
$sql = 'INSERT INTO users (name, email) VALUES (:name, :email)';
$stmt = $pdo->prepare($sql);
$stmt->execute([':name' => 'Иван', ':email' => 'ivan@example.com']);
Php mysql сайты (сайты на php и mysql)
Типичные ошибки и их решение:
- Ошибка подключения: неверные параметры host, dbname, user или password. Проверьте доступность сервера MySQL и правильность учётных данных.
- SQL-инъекция: если данные не экранируются. Использование подготовленных запросов полностью исключает эту проблему.
- Ошибка синтаксиса SQL: проверьте запрос в консоли MySQL перед использованием.
Цели использования:
- Безопасная передача пользовательских данных в запросы.
- Унификация кода для разных БД (например, MySQL и PostgreSQL).
- Удобство обработки ошибок через исключения.
Как выполнить запрос к MySQL с помощью mysqli (процедурный стиль)?
Процедурный mysqli - классический способ, который подходит для простых проектов. Он использует функции, а не объекты.
$link = mysqli_connect('localhost', 'root', '', 'test');
if (!$link) {
die('Ошибка соединения: ' . mysqli_connect_error());
}
$result = mysqli_query($link, 'SELECT * FROM users');
while ($row = mysqli_fetch_assoc($result)) {
echo $row['name'] . '
';
}
динамический php (динамические возможности php)
Проблемы:
- Ручное экранирование (mysqli_real_escape_string) увеличивает риск ошибок.
- Нет поддержки исключений - нужно вручную проверять ошибки.
Когда использовать:
Для быстрого прототипирования или в легаси-проектах, где уже используется процедурный подход.
Как работать с MySQL через mysqli в объектно-ориентированном стиле?
Объектно-ориентированный mysqli предоставляет классы и методы, делая код более структурированным.
$mysqli = new mysqli('localhost', 'root', '', 'test');
if ($mysqli->connect_error) {
die('Ошибка: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('INSERT INTO users (name) VALUES (?)');
$stmt->bind_param('s', $name);
$name = 'Петр';
$stmt->execute();
Типичная ошибка:
Забывают вызвать bind_param() после prepare. Это приводит к ошибке "No statement resource".
Сильные стороны:
Лучше процедурного стиля, но уступает PDO в переносимости.
Как использовать PDO для выборки данных с JOIN?
Пример более сложного запроса с объединением таблиц.
$sql = 'SELECT u.name, o.order_date FROM users u JOIN orders o ON u.id = o.user_id WHERE u.status = :status';
$stmt = $pdo->prepare($sql);
$stmt->execute([':status' => 'active']);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $row) {
echo "Пользователь {$row['name']} заказал {$row['order_date']}
";
}
Проблема:
Если JOIN возвращает дубли имён полей, то fetchAll(PDO::FETCH_ASSOC) перезаписывает значения. Решение - использовать алиасы в SQL.
Заключение
Для современной веб-разработки на PHP и MySQL рекомендуется использовать PDO из-за его безопасности, гибкости и поддержки разных СУБД. Варианты с mysqli подходят для унаследованных проектов или когда требуется максимальная производительность без слоя абстракции.
Расширенные примеры работы с PHP и MySQL
Пример 1: Регистрация пользователя с хэшированием пароля
// registration.php
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
if (empty($name) || empty($email) || empty($password)) {
die('Заполните все поля');
}
// Хэширование пароля
$hashedPassword = password_hash($password, PASSWORD_DEFAULT);
$sql = 'INSERT INTO users (name, email, password) VALUES (:name, :email, :password)';
$stmt = $pdo->prepare($sql);
$stmt->execute([
':name' => $name,
':email' => $email,
':password' => $hashedPassword
]);
echo 'Пользователь зарегистрирован';
При успешном выполнении: Пользователь зарегистрирован При дублировании email: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry...
Пример 2: Авторизация и проверка пароля
// login.php
$email = $_POST['email'] ?? '';
$password = $_POST['password'] ?? '';
$stmt = $pdo->prepare('SELECT id, password FROM users WHERE email = :email');
$stmt->execute([':email' => $email]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if ($user && password_verify($password, $user['password'])) {
session_start();
$_SESSION['user_id'] = $user['id'];
echo 'Вход выполнен';
} else {
echo 'Неверный email или пароль';
}
При верных данных: Вход выполнен При неверных: Неверный email или пароль
Пример 3: Постраничный вывод записей (пагинация)
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$perPage = 10;
$offset = ($page - 1) * $perPage;
// Общее количество записей
$countStmt = $pdo->query('SELECT COUNT(*) FROM articles');
$total = $countStmt->fetchColumn();
$totalPages = ceil($total / $perPage);
// Выборка с лимитом
$stmt = $pdo->prepare('SELECT id, title FROM articles ORDER BY id DESC LIMIT :limit OFFSET :offset');
$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
$articles = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($articles as $article) {
echo "{$article['title']}
";
}
// Вывод ссылок на страницы
for ($i = 1; $i <= $totalPages; $i++) {
echo "$i ";
}
Выводятся заголовки статей и ссылки страниц. Пример: Статья 1 Статья 2 ... 1 2 3 ...
Пример 4: Обновление записи с проверкой существования
$id = 5;
$newEmail = 'new@example.com';
$stmt = $pdo->prepare('SELECT id FROM users WHERE id = :id');
$stmt->execute([':id' => $id]);
if (!$stmt->fetch()) {
die('Пользователь не найден');
}
$updateStmt = $pdo->prepare('UPDATE users SET email = :email WHERE id = :id');
$updateStmt->execute([':email' => $newEmail, ':id' => $id]);
echo 'Email обновлён';
Email обновлён или Пользователь не найден
Пример 5: Удаление каскадом (с внешними ключами)
$userId = 10;
// Предполагается, что в таблице orders есть внешний ключ с ON DELETE CASCADE
$stmt = $pdo->prepare('DELETE FROM users WHERE id = :id');
$stmt->execute([':id' => $userId]);
echo 'Пользователь удалён вместе с заказами';
Пользователь удалён вместе с заказами Если каскад не настроен: SQLSTATE[23000]: Integrity constraint violation...