W3docs

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-строковом литерале. Сначала установите кодировку соединения, помните, что функция бесполезна для идентификаторов, и по возможности используйте подготовленные запросы.

Практика

Практика
Что делает функция PHP mysql_real_escape_string?
Что делает функция PHP mysql_real_escape_string?
Was this page helpful?