Страница сайта на PHP, работающая с базой данных

Раздел: Разработка на PHP -> Базы данных

Основные методы интеграции базы данных в PHP-страницу

Как выполнить безопасное взаимодействие с базой данных через PDO?

PDO обеспечивает универсальный доступ к разным СУБД и поддержку подготовленных выражений. Цель - создать защищенное от SQL-инъекций соединение с возможностью легкой смены драйвера.


<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$pass = 'password';
try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $stmt = $pdo->prepare('SELECT name, email FROM users WHERE id = :id');
    $stmt->execute(['id' => 1]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    echo 'Имя: ' . $row['name'] . ', Email: ' . $row['email'];
} catch (PDOException $e) {
    echo 'Ошибка: ' . $e->getMessage();
}
?>
Имя: Иван, Email: ivan@example.com

Типичные ошибки:

  • Отсутствие драйвера PDO для MySQL (выброс исключения "could not find driver"). Решение: установить расширение php_pdo_mysql.
  • Неверные учетные данные (код 1045). Проверять параметры подключения.
  • Игнорирование исключений: без установки ATTR_ERRMODE ошибки остаются незамеченными.
  • Неправильное экранирование: использование подготовленных выражений обязательно, конкатенация чревата инъекциями.

Как использовать MySQLi в объектно-ориентированном стиле?

Подходит для проектов, где гарантированно используется только MySQL. Случаи использования: миграция с mysql_* на современный API, работа с асинхронными запросами (через poll).


<?php
$mysqli = new mysqli('localhost', 'root', 'password', 'testdb');
if ($mysqli->connect_error) {
    die('Ошибка подключения: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('SELECT name FROM users WHERE id = ?');
$stmt->bind_param('i', $id);
$id = 2;
$stmt->execute();
$stmt->bind_result($name);
$stmt->fetch();
echo 'Имя: ' . $name;
$stmt->close();
$mysqli->close();
?>
Имя: Мария

Проблемы: привязка параметров только по позиции (?, ?). Переключение на другую СУБД потребует замены кода. Обработка ошибок через методы error* (исключения не выбрасываются по умолчанию).

Почему устаревшие функции mysql_* опасны?

Удалены в PHP 7, не имеют поддержки подготовленных выражений, открыты для SQL-инъекций. Случаи использования: только поддержка легаси-кода до миграции.


// НЕ ИСПОЛЬЗОВАТЬ
$link = mysql_connect('localhost', 'root', 'password') or die(mysql_error());
mysql_select_db('testdb', $link);
$id = $_GET['id']; // инъекция
$result = mysql_query("SELECT * FROM users WHERE id = $id");

Результат: злоумышленник может вставить ' OR '1'='1', получив доступ ко всем записям. Функции удалены начиная с PHP 7.0, код не будет работать в современных версиях.

Как упростить запросы через ORM (illuminate/database)?

Библиотека Eloquent (из Laravel) может использоваться вне фреймворка. Цель: абстрагировать SQL, использовать объекты и отношения.


<?php
require 'vendor/autoload.php';
use Illuminate\Database\Capsule\Manager as Capsule;
$capsule = new Capsule;
$capsule->addConnection([
    'driver' => 'mysql',
    'host' => 'localhost',
    'database' => 'testdb',
    'username' => 'root',
    'password' => 'password',
    'charset' => 'utf8mb4',
]);
$capsule->bootEloquent();
$users = Capsule::table('users')->where('id', '>', 1)->get();
foreach ($users as $user) {
    echo $user->name . ' ' . $user->email . '<br>';
}
?>
Мария maria@example.com
Петр petr@example.com

Проблемы: требуется установка composer и дополнительная настройка. При малых проектах излишняя сложность. Необходимо знание синтаксиса Fluent.

Расширенные примеры работы с базой данных

Транзакции в PDO (перевод средств)

Пример

<?php
$pdo->beginTransaction();
try {
    $pdo->exec('UPDATE accounts SET balance = balance - 100 WHERE id = 1');
    $pdo->exec('UPDATE accounts SET balance = balance + 100 WHERE id = 2');
    $pdo->commit();
    echo 'Перевод выполнен успешно';
} catch (Exception $e) {
    $pdo->rollBack();
    echo 'Ошибка: ' . $e->getMessage();
}
?>
Перевод выполнен успешно (при отсутствии ошибок)

Именованные плейсхолдеры в сложных запросах

Пример

<?php
$sql = 'SELECT * FROM orders WHERE (status = :status OR :status IS NULL) AND total > :min';
$stmt = $pdo->prepare($sql);
$stmt->execute([
    'status' => 'active',
    'min' => 100
]);
$orders = $stmt->fetchAll();
?>

Пакетная вставка через подготовленные выражения

Пример

<?php
$stmt = $pdo->prepare('INSERT INTO logs (message, created_at) VALUES (:msg, NOW())');
$messages = ['Ошибка 1', 'Ошибка 2', 'Предупреждение'];
foreach ($messages as $msg) {
    $stmt->execute(['msg' => $msg]);
}
echo 'Вставлено ' . count($messages) . ' записей';
?>
Вставлено 3 записей

Получение данных в виде объекта с помощью fetchObject

Пример

<?php
$stmt = $pdo->query('SELECT id, name FROM users');
$stmt->setFetchMode(PDO::FETCH_OBJ);
while ($user = $stmt->fetch()) {
    echo $user->id . ': ' . $user->name . '<br>';
}
?>
1: Иван
2: Мария

Установка кодировки через MYSQL_ATTR_INIT_COMMAND

Пример

<?php
$dsn = 'mysql:host=localhost;dbname=testdb';
$options = [
    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8mb4',
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
];
$pdo = new PDO($dsn, 'root', 'password', $options);
?>

Позволяет задать кодировку сразу после соединения, без отдельного вызова query.

Обработка всех ошибок через try-catch с PDOException

Пример

<?php
try {
    $pdo = new PDO($dsn, $user, $pass, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
    // любые запросы
} catch (PDOException $e) {
    error_log('DB error: ' . $e->getMessage());
    echo 'Внутренняя ошибка, попробуйте позже';
}
?>

Unbuffered query для больших данных

Пример

<?php
$pdo->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
$stmt = $pdo->query('SELECT * FROM huge_table');
while ($row = $stmt->fetch()) {
    // обработка без загрузки всего набора в память
}
?>

Риск: во время итерации нельзя выполнять другие запросы к тому же соединению.

Вызов хранимой процедуры через PDO

Пример

<?php
$stmt = $pdo->prepare('CALL get_user(:id)');
$stmt->execute(['id' => 1]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
?>

База данных страницы на PHP - comments

En
Page php bd (php)