PHP и MySQL для начинающих: от подключения до выборки данных

Раздел: Веб-разработка -> Обучение PHP и MySQL

Основы работы с PHP и MySQL: варианты подключения и безопасные запросы

Как эффективно соединиться с MySQL и выполнять запросы с защитой от SQL-инъекций?

Рекомендуемый подход: использование PDO (PHP Data Objects) с подготовленными выражениями. Это универсальный интерфейс, поддерживающий множество СУБД и обеспечивающий безопасную передачу параметров.

Пример базового подключения и запроса SELECT:


<?php
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8mb4';
$user = 'root';
$pass = '';
try {
    $pdo = new PDO($dsn, $user, $pass);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $stmt = $pdo->prepare('SELECT id, name FROM users WHERE age > :age');
    $stmt->execute(['age' => 18]);
    $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
    print_r($users);
} catch (PDOException $e) {
    error_log('Database error: ' . $e->getMessage());
}
?>
  

Код подключается к базе testdb, устанавливает режим исключений для обработки ошибок, подготавливает запрос с именованным параметром :age и выполняет его с переданным значением. Результат получается в виде ассоциативного массива.

Типичные проблемы:

  • Неверный DSN (например, пропущен порт или кодировка) - выбрасывается PDOException.
  • Отсутствие драйвера PDO для MySQL - проверяется функция extension_loaded('pdo_mysql').
  • Утечка данных при выводе ошибок в production - рекомендуется логировать, а не выводить сообщения.

Как подключиться к MySQL через MySQLi (процедурный стиль)?

MySQLi (MySQL Improved) - расширение, ориентированное только на MySQL. Процедурный вариант удобен для быстрых скриптов.


<?php
$conn = mysqli_connect('localhost', 'root', '', 'testdb');
if (!$conn) {
    die('Connect error: ' . mysqli_connect_error());
}
$result = mysqli_query($conn, "SELECT * FROM users WHERE age > 18");
if ($result) {
    while ($row = mysqli_fetch_assoc($result)) {
        echo $row['name'] . '<br>';
    }
    mysqli_free_result($result);
}
mysqli_close($conn);
?>
  

Здесь mysqli_connect возвращает объект соединения, а запрос выполняется напрямую. Важно: такой код уязвим для SQL-инъекций, если в запрос подставлять пользовательские данные без экранирования (функция mysqli_real_escape_string).

Ошибки:

  • При неправильных учётных данных mysqli_connect() возвращает false, но соединение при этом может быть частично создано - проверять следует через mysqli_connect_errno().
  • Забыть освободить результат (mysqli_free_result) - может привести к утечке памяти.

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

Объектная версия MySQLi выглядит компактнее и допускает цепочки вызовов.


<?php
$mysqli = new mysqli('localhost', 'root', '', 'testdb');
if ($mysqli->connect_errno) {
    die('Connect error: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare('SELECT name, email FROM users WHERE id = ?');
$stmt->bind_param('i', $userId);
$userId = 5;
$stmt->execute();
$stmt->bind_result($name, $email);
$stmt->fetch();
echo "$name - $email";
$stmt->close();
$mysqli->close();
?>
  

Метод prepare возвращает объект statement, параметры связываются через bind_param (первый аргумент - типы: i - integer, s - string и т.д.). Затем результат извлекается в переменные.

Сложности:

  • Привязка параметров требует точного соответствия типов, иначе запрос может вернуть пустой результат.
  • После bind_result нельзя использовать fetchAll - только построчное чтение.

Какие ещё способы обработки ошибок существуют?

Кроме исключений PDO и проверки возвращаемых значений, можно использовать пользовательские функции обработки ошибок или механизм error_reporting для вывода предупреждений на этапе разработки.


<?php
// PDO без исключений
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$stmt = $pdo->prepare('INVALID SQL');
$stmt->execute(); // только предупреждение, скрипт продолжается
?>
  

Проблема:

Режим предупреждений может скрыть серьёзные ошибки. Для production лучше использовать исключения или логирование.

Расширенные примеры работы с PHP и MySQL

1. Создание таблицы и вставка данных с подготовленным выражением (PDO)

Пример

<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$pdo->exec('CREATE TABLE IF NOT EXISTS products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(100) NOT NULL,
    price DECIMAL(10,2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4');

$stmt = $pdo->prepare('INSERT INTO products (title, price) VALUES (:title, :price)');
$products = [
    ['title' => 'Мышка', 'price' => 15.50],
    ['title' => 'Клавиатура', 'price' => 45.00],
];
foreach ($products as $item) {
    $stmt->execute($item);
}
echo 'Добавлено записей: ' . count($products);
?>
Добавлено записей: 2

2. Выборка с JOIN (PDO)

Пример

<?php
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$sql = 'SELECT o.id, o.total, u.name 
        FROM orders o 
        JOIN users u ON o.user_id = u.id 
        WHERE o.status = :status 
        ORDER BY o.created_at DESC 
        LIMIT :limit';
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':status', 'paid', PDO::PARAM_STR);
$stmt->bindValue(':limit', 10, PDO::PARAM_INT);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($result);
?>
Array
(
    [0] => Array
        (
            [id] => 101
            [total] => 235.00
            [name] => Иванов
        )
    [1] => Array
        (
            [id] => 102
            [total] => 87.50
            [name] => Петрова
        )
)

3. Транзакции с откатом (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();
} catch (Exception $e) {
    $pdo->rollBack();
    error_log('Transaction failed: ' . $e->getMessage());
}
?>
(без вывода, при успехе – данные обновлены, при ошибке – откат к исходному состоянию)

4. Использование placeholders и like в MySQLi (объектный стиль)

Пример

<?php
$mysqli = new mysqli('localhost', 'root', '', 'test');
$search = '%клав%';
$stmt = $mysqli->prepare('SELECT title FROM products WHERE title LIKE ?');
$stmt->bind_param('s', $search);
$stmt->execute();
$stmt->bind_result($title);
while ($stmt->fetch()) {
    echo $title . '<br>';
}
$stmt->close();
$mysqli->close();
?>
Клавиатура

5. Обновление и удаление с проверкой количества затронутых строк

Пример

<?php
$pdo->exec("UPDATE products SET price = price * 1.1 WHERE id < 100");
echo 'Обновлено строк: ' . $pdo->rowCount();

$stmt = $pdo->prepare('DELETE FROM products WHERE price = 0');
$stmt->execute();
echo 'Удалено строк: ' . $stmt->rowCount();
?>
Обновлено строк: 3
Удалено строк: 0

PHP и MySQL для начинающих - comments

En
Php mysql для начинающих (php)