PHP и MySQL: интеграция для работы с данными
Основы взаимодействия PHP с MySQL
Наиболее эффективным решением для работы с MySQL в PHP является использование расширения PDO (PHP Data Objects). PDO предоставляет единый интерфейс для доступа к различным базам данных, поддерживает подготовленные запросы, что защищает от SQL-инъекций, и обеспечивает гибкую обработку ошибок.
Пример подключения к базе данных MySQL с помощью PDO:
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8mb4';
$user = 'root';
$password = '';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $user, $password, $options);
Пояснение: $dsn содержит строку подключения, где указывается драйвер mysql, хост, имя базы данных и кодировка. $options задает режим ошибок (исключения), режим извлечения данных (ассоциативный массив) и отключает эмуляцию подготовленных запросов для использования реальной функциональности MySQL.
После подключения можно выполнять запросы:
$stmt = $pdo->prepare('SELECT id, name FROM users WHERE email = :email');
$stmt->execute([':email' => 'user@example.com']);
$user = $stmt->fetch();
Подготовленные запросы предотвращают SQL-инъекции, так как данные передаются отдельно от SQL-кода.
Типичные проблемы:
- Ошибка подключения: неверный хост, имя базы, логин или пароль. Решение: проверять параметры подключения, использовать try-catch.
- Не установлен режим исключений: по умолчанию PDO не выбрасывает исключения, что затрудняет отладку. Решение: задать PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION.
- Проблемы с кодировкой: символы отображаются как ?. Решение: указать charset=utf8mb4 в DSN.
Как выполнить запрос к MySQL через процедурный интерфейс mysqli?
Расширение mysqli предоставляет два интерфейса: процедурный и объектно-ориентированный. Процедурный стиль удобен для быстрых скриптов, но требует внимательного экранирования данных.
$conn = mysqli_connect('localhost', 'user', 'pass', 'db');
if (!$conn) {
die('Ошибка подключения: ' . mysqli_connect_error());
}
$sql = "SELECT * FROM users WHERE email = '" . mysqli_real_escape_string($conn, $email) . "'";
$result = mysqli_query($conn, $sql);
if ($result) {
while ($row = mysqli_fetch_assoc($result)) {
echo $row['name'];
}
mysqli_free_result($result);
}
mysqli_close($conn);
Проблемы: необходимо вручную экранировать входящие данные, легко забыть, что приводит к SQL-инъекциям. Рекомендуется использовать подготовленные запросы.
Ошибки: не проверено подключение; забыт mysqli_real_escape_string; не освобождены ресурсы.
Цель: быстрая реализация простых запросов без подготовки, но с риском безопасности.
Как использовать объектно-ориентированный интерфейс mysqli для подготовленных запросов?
Объектно-ориентированный стиль mysqli более структурирован и поддерживает подготовленные запросы.
$mysqli = new mysqli('localhost', 'user', 'pass', 'db');
if ($mysqli->connect_error) {
die('Ошибка: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('SELECT name FROM users WHERE email = ?');
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->bind_result($name);
while ($stmt->fetch()) {
echo $name;
}
$stmt->close();
$mysqli->close();
Пояснение: bind_param привязывает переменные к параметрам (?), тип 's' означает строку. bind_result связывает столбцы результата с переменными.
Проблемы: легко перепутать порядок параметров; необходимо правильно указывать типы. В PDO это проще.
Расширенные примеры работы с MySQL в PHP
Пример 1: Создание таблицы и вставка данных с получением ID.
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
$pdo->exec('CREATE TABLE IF NOT EXISTS products (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4');
$stmt = $pdo->prepare('INSERT INTO products (name, price) VALUES (:name, :price)');
$stmt->execute([':name' => 'Товар 1', ':price' => 199.99]);
$lastId = $pdo->lastInsertId();
echo "Вставлен ID: $lastId";
Вставлен ID: 1
Пример 2: Транзакции.
$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();
} catch (Exception $e) {
$pdo->rollBack();
echo 'Ошибка: ' . $e->getMessage();
}
Пояснение: все изменения внутри транзакции применяются только после commit, в случае ошибки откатываются.
Пример 3: Извлечение данных в виде объектов.
class User {
public $id;
public $name;
public $email;
}
$stmt = $pdo->query('SELECT id, name, email FROM users');
$users = $stmt->fetchAll(PDO::FETCH_CLASS, 'User');
foreach ($users as $user) {
echo $user->name . ' (' . $user->email . ')<br>';
}
Иван (ivan@example.com)<br> Мария (maria@example.com)<br>
Пример 4: Массовая вставка с использованием одного подготовленного запроса.
$data = [
['name' => 'A', 'price' => 10],
['name' => 'B', 'price' => 20],
['name' => 'C', 'price' => 30],
];
$stmt = $pdo->prepare('INSERT INTO products (name, price) VALUES (:name, :price)');
foreach ($data as $row) {
$stmt->execute($row);
}
echo 'Вставлено записей: ' . $stmt->rowCount();
Вставлено записей: 3
Пример 5: Обработка ошибок с помощью исключений.
try {
$pdo->exec('SELECT * FROM non_existent_table');
} catch (PDOException $e) {
echo 'Ошибка: ' . $e->getMessage();
}
Ошибка: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test.non_existent_table' doesn't exist
Пример 6: Использование LIKE и подстановка параметров.
$search = '%иван%';
$stmt = $pdo->prepare('SELECT * FROM users WHERE name LIKE :search');
$stmt->execute([':search' => $search]);
$results = $stmt->fetchAll();
print_r($results);
Пример 7: Работа с NULL значениями.
$stmt = $pdo->prepare('UPDATE users SET email = NULL WHERE id = :id');
$stmt->execute([':id' => 5]);
echo 'Обновлено строк: ' . $stmt->rowCount();