Почему нельзя использовать устаревшие функции mysql_* в PHP и чем их заменить?
Главные причины отказаться от mysql_*
Вы столкнулись с классической проблемой устаревшего кода. Функции mysql_* удалены из PHP 7.0 и выше. Но даже если бы они остались, их категорически нельзя использовать по трём основным причинам:
- Отсутствие поддержки подготовленных запросов — вы вынуждены вручную экранировать данные, что часто забывают делать;
- SQL-инъекции — ваш код уязвим, как показано в примере с
$_GET['id']; - Устаревшее API — нет поддержки хранимых процедур, множественных запросов, транзакций.
Ваш пример с конкатенацией $_GET['id'] — это прямая брешь в безопасности. Злоумышленник может передать ?id=1 UNION SELECT * FROM users и получить все данные. Функция mysql_real_escape_string() не спасает на 100%, особенно при работе с кодировками.
Правильное решение: используем PDO
Современный стандарт — PDO (PHP Data Objects) или MySQLi. Я рекомендую PDO, потому что он поддерживает разные СУБД (MySQL, PostgreSQL, SQLite). Вот как переписать ваш код:
<?php
// Подключение с обработкой ошибок
try {
$pdo = new PDO('mysql:host=localhost;dbname=my_database;charset=utf8', 'root', '');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Ошибка подключения: ' . $e->getMessage());
}
// Безопасный запрос с подготовленным выражением
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute([':id' => $_GET['id']]); // Данные экранируются автоматически
// Получение результатов
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8'); // Защита от XSS
}
?>
Преимущества PDO перед mysql_*
- Подготовленные запросы — данные и SQL-код разделены, инъекции невозможны;
- Именованные плейсхолдеры (
:id) — код читаемее; - Режимы выборки — FETCH_ASSOC, FETCH_OBJ и другие;
- Транзакции —
$pdo->beginTransaction(); - Обработка ошибок через исключения — вы всегда знаете, что пошло не так.
Альтернатива: MySQLi (объектный стиль)
Если вы точно работаете только с MySQL, можно использовать MySQLi:
<?php
$mysqli = new mysqli('localhost', 'root', '', 'my_database');
if ($mysqli->connect_error) {
die('Ошибка: ' . $mysqli->connect_error);
}
$stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param('i', $_GET['id']);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo htmlspecialchars($row['name']);
}
?>
Итог: прекратите использовать mysql_* немедленно. Перепишите старый код на PDO или MySQLi. Это не просто «новый стандарт» — это вопрос безопасности вашего сайта и данных пользователей.
Дополнение: почему mysql_* опасны даже с экранированием
Многие начинающие думают: «Я же использую mysql_real_escape_string() — значит, всё безопасно». Это опасное заблуждение. Рассмотрим пример:
$id = mysql_real_escape_string($_GET['id']);
$query = "SELECT * FROM users WHERE id = $id"; // Всё ещё опасно!
Проблема в том, что mysql_real_escape_string() зависит от текущей кодировки соединения. Если кодировка соединения отличается от кодировки данных (например, из-за SET NAMES), экранирование может быть обойдено. Известны атаки через многобайтовые кодировки (GBK, Big5), когда злоумышленники используют символы, которые «съедают» экранирующий слеш.
Кроме того, mysql_* не поддерживает:
- Привязку параметров по типу (integer, string);
- Автоматическое преобразование типов;
- Пул соединений и повторное использование.
Вывод: даже если ваш код кажется безопасным, используйте PDO или MySQLi. Подготовленные запросы — это не рекомендация, а обязательное требование для любого современного PHP-приложения. Не полагайтесь на «ручное» экранирование — доверьте эту работу драйверу базы данных.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги