PHP И MYSQL

PDO И ПОДГОТОВЛЕННЫЕ ЗАПРОСЫ

PHP и MySQL через PDO

MySQL через PDO

Безопасные запросы без склейки строк

Подключение

PDO — единый интерфейс к разным базам. Подключение делается один раз и переиспользуется:

$dsn = 'mysql:host=localhost;dbname=blog;charset=utf8mb4';
$pdo = new PDO($dsn, 'root', '', [
  PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

ERRMODE_EXCEPTION — главное, что нужно включить: без него ошибки базы молча возвращают false, и вы часами ищете, почему данные не сохраняются.

Почему не конкатенация

Такой код опасен: если в $id придёт 1 OR 1=1, вернутся все записи, а при ; DROP TABLE — всё хуже.

// ТАК НЕЛЬЗЯ
$pdo->query("SELECT * FROM posts WHERE id = $id");

Подготовленный запрос отделяет структуру от данных: значение приходит как значение, а не как часть SQL.

SELECT с параметрами

$stmt = $pdo->prepare("SELECT * FROM posts WHERE id = ?");
$stmt->execute([$id]);
$post = $stmt->fetch();

if (!$post) { http_response_code(404); exit; }

Именованные параметры читаются лучше, когда их несколько:

$stmt = $pdo->prepare("SELECT * FROM posts WHERE status = :status AND year = :year");
$stmt->execute(['status' => 'published', 'year' => 2026]);

Список строк

$stmt = $pdo->query("SELECT id, title FROM posts ORDER BY created_at DESC");
$posts = $stmt->fetchAll();

foreach ($posts as $post) {
  echo htmlspecialchars($post['title']);
}

query() допустим только для запросов без пользовательских данных. Всё, что пришло из формы или адреса, идёт через prepare.

INSERT и обновление

$stmt = $pdo->prepare(
  "INSERT INTO posts (title, body) VALUES (?, ?)"
);
$stmt->execute([$title, $body]);

$newId = $pdo->lastInsertId();

Для массовой вставки не делайте execute в цикле — оберните всё в транзакцию через beginTransaction() и commit(), иначе база получит сотни отдельных записей.

Обработка ошибок

try {
  $stmt->execute([$id]);
} catch (PDOException $e) {
  error_log($e->getMessage());
  http_response_code(500);
  echo "Ошибка сервера";
}

Текст исключения пишите в лог, а пользователю показывайте общую фразу. Подробности ошибки reveal структуру базы.

Частые ошибки

  • Конкатенация переменных в SQL. SQL-инъекция в чистом виде.
  • Выключенные исключения. Ошибка не видна, данные не сохраняются.
  • Вывод из базы без экранирования. XSS через поле заголовка.
  • Соединение в каждом файле. Сотни подключений вместо одного.

Нужен сайт, а не статья?

Спроектирую базу и напишу слой доступа без инъекций и дублирования. С 2009 года, по договору, с поддержкой после запуска.

ОБСУДИТЬ ПРОЕКТ

Полезно по теме: PHP с нуля, формы на PHP, ORM в Django.