real_escape_string
Функция mysqli_real_escape_string() в PHP: синтаксис, применение, экранирование спецсимволов в строках для безопасного использования в SQL.
Функция mysqli_real_escape_string() экранирует специальные символы в строке, чтобы её можно было безопасно включить в SQL-запрос. На этой странице описывается, что делает функция, её синтаксис и возвращаемое значение, ошибка с кодировкой, которая нарушает её работу, устаревшая mysql_real_escape_string(), которую она заменила, и почему сегодня предпочтительнее использовать подготовленные запросы.
Что делает mysqli_real_escape_string()
Когда вы строите SQL-запрос, напрямую конкатенируя пользовательский ввод в строку запроса, значение вроде O'Reilly преждевременно завершает строку в кавычках, а остаток обрабатывается как SQL. Злоумышленник может этим воспользоваться для чтения, изменения или удаления данных — это атака SQL-инъекция.
mysqli_real_escape_string() предотвращает это, добавляя обратные слэши перед символами, имеющими специальное значение внутри строкового литерала MySQL: одинарная кавычка ', двойная кавычка ", обратный слэш \, байт NUL, перевод строки \n, возврат каретки \r и Ctrl+Z. После экранирования значение безопасно встраивать в кавычках в запрос.
Она называется «real» (настоящая), потому что учитывает кодировку соединения и корректно экранирует даже многобайтовые кодировки — чего не умеет старый addslashes().
Синтаксис
mysqli_real_escape_string(mysqli $connection, string $string): string| Параметр | Описание |
|---|---|
$connection | Ссылка, возвращённая функцией mysqli_connect(). Функции она нужна, чтобы знать кодировку соединения. |
$string | Строка для экранирования. |
Функция возвращает экранированную строку. Обратите внимание: обрамляющие кавычки она не добавляет — вы сами пишете '$escaped' в запросе.
В объектно-ориентированном стиле вызывайте как метод: $mysqli->real_escape_string($string).
Как использовать
<?php
$con = mysqli_connect('localhost', 'username', 'password', 'database');
if (!$con) {
exit('Could not connect: ' . mysqli_error($con));
}
// Set charset to prevent multi-byte character vulnerabilities
mysqli_set_charset($con, 'utf8mb4');
$name = "John O'Reilly";
$name = mysqli_real_escape_string($con, $name);
$sql = "INSERT INTO customers (name) VALUES ('$name')";
if (!mysqli_query($con, $sql)) {
exit('Error: ' . mysqli_error($con));
}
echo '1 record added';
mysqli_close($con);
?>Здесь мы подключаемся с помощью mysqli_connect(), задаём $name с одинарной кавычкой и экранируем её. Экранированное значение John O\'Reilly безопасно вставляется в заполнитель '$name', поэтому INSERT выполняется без синтаксической ошибки и без создания уязвимости для инъекции. Смотрите Вставка данных в MySQL для полного рабочего процесса вставки.
Сначала установите кодировку
mysqli_real_escape_string() корректно экранирует только в том случае, если соединение знает свою кодировку. Всегда вызывайте mysqli_set_charset() сразу после подключения:
mysqli_set_charset($con, 'utf8mb4');Пропуск этого шага для некоторых кодировок (в частности, GBK) оставляет вектор многобайтовой инъекции, при которой экранирующий обратный слэш «поглощается» многобайтовой последовательностью. Установка кодировки на уровне соединения, а не только в запросе, закрывает эту уязвимость.
От чего она не защищает
Экранирование делает значение безопасным внутри строкового литерала в кавычках. Оно не делает значения безопасными в местах, где нельзя использовать кавычки — именах таблиц и столбцов, числах в LIMIT или ключевых словах. Никогда не экранируйте идентификатор и не вставляйте его в запрос; вместо этого проверяйте его по списку разрешённых значений.
// WRONG — escaping does nothing useful for an identifier
$column = mysqli_real_escape_string($con, $_GET['sort']);
$sql = "SELECT * FROM users ORDER BY $column"; // still injectable
// RIGHT — allow-list
$allowed = ['name', 'email', 'created_at'];
$column = in_array($_GET['sort'], $allowed, true) ? $_GET['sort'] : 'name';mysql_real_escape_string() vs mysqli_real_escape_string()
Старая mysql_real_escape_string() (без i) принадлежала оригинальному расширению mysql_*, которое было удалено в PHP 7. Используйте версию mysqli_* — или PDO — в любом современном PHP. При вызове без активного соединения она молча открывает соединение по умолчанию и выдаёт предупреждение — ещё одна причина, по которой она была упразднена.
Предпочитайте подготовленные запросы
Экранирование работает, но требует, чтобы вы никогда не забыли ни одного значения. Подготовленные запросы надёжнее, потому что шаблон запроса и данные передаются раздельно, и пользовательский ввод никогда не может изменить структуру запроса:
<?php
$con = mysqli_connect('localhost', 'username', 'password', 'database');
mysqli_set_charset($con, 'utf8mb4');
$stmt = mysqli_prepare($con, 'INSERT INTO customers (name) VALUES (?)');
mysqli_stmt_bind_param($stmt, 's', $name);
$name = "John O'Reilly"; // no manual escaping needed
mysqli_stmt_execute($stmt);
echo '1 record added';
mysqli_close($con);
?>Используйте mysqli_real_escape_string(), когда вам действительно нужно строить динамический SQL вручную; в остальных случаях обращайтесь к mysqli_prepare(). Обзор расширения см. в PHP MySQLi.
Заключение
mysqli_real_escape_string() экранирует специальные символы, которые иначе нарушили бы или были использованы в SQL-строковом литерале. Сначала установите кодировку соединения, помните, что функция бесполезна для идентификаторов, и по возможности используйте подготовленные запросы.