19 августа 2026
mysqli_quote_string(): безопасное экранирование строк в PHP 8.6

Проблема: SQL-инъекции в mysqli

В mysqli уже давно есть real_escape_string() для ручного экранирования строк. Но у неё есть известная уязвимость: при включённом режиме NO_BACKSLASH_ESCAPES и использовании двойных кавычек для обёртывания значения, экранирование не спасает от инъекции.

$mysqli->query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"');

$value = '" OR 1=1 -- foo';
$sql = sprintf('SELECT id FROM foo WHERE name="%s"', $mysqli->real_escape_string($value));
$result = $mysqli->query($sql);
// Инъекция сработала! Запрос: SELECT id FROM foo WHERE name="" OR 1=1 -- foo"

Кроме того, real_escape_string() только экранирует спецсимволы, но не добавляет кавычки. Разработчик должен сам обернуть результат в '...' через sprintf или конкатенацию. Длинное имя функции + ручное добавление кавычек = слишком легко ошибиться.

Решение: mysqli_quote_string()

Новая функция mysqli_quote_string(), реализованная в PHP 8.6 (RFC от Kamil Tekiela), делает две вещи сразу:

  1. Экранирует строку так же, как real_escape_string()
  2. Оборачивает результат в одинарные кавычки
// ОО-стиль
$quoted = $mysqli->quote_string("Don't!");
// результат: "'Don\'t!'"

// Процедурный стиль
$quoted = mysqli_quote_string($mysqli, "Don't!");

Почему только одинарные кавычки

Двойные кавычки — нестандартный SQL. Стандарт SQL использует их для идентификаторов, а не для строковых литералов. MySQL поддерживает их как расширение, но именно это и создаёт уязвимость. Функция PDO::quote() в PDO тоже всегда использует одинарные кавычки — и это безопаснее. Новая функция в mysqli следует тому же принципу: нет выбора символа квотирования — нет уязвимости.

Безопасный пример

$mysqli->query('SET SQL_MODE="NO_BACKSLASH_ESCAPES"');

$value = '" OR 1=1 -- foo';
$sql = sprintf('SELECT id FROM foo WHERE name=%s', $mysqli->quote_string($value));
$result = $mysqli->query($sql);
// Безопасно! Запрос: SELECT id FROM foo WHERE name='" OR 1=1 -- foo'
// Инъекция не сработала.

Сигнатура

public function quote_string(string $string): string {}

function mysqli_quote_string(mysqli $mysql, string $string): string {}

Почему именно "quote_string", а не "quote"

В PDO функция называется quote(), но в mysqli важно подчеркнуть, что она работает только со строками. В не-strict режиме PHP можно передать другие типы, и в mysqli это распространённая ошибка новичков, подогретая онлайн-туториалами. Слово "string" в названии прямо указывает на тип параметра и помогает избежать ошибок.

Что дальше

Автор RFC надеется, что mysqli::real_escape_string() будет помечен как устаревший (deprecated) в одном из следующих минорных релизов. При миграции разработчикам нужно будет убрать вручную добавленные кавычки и заменить саму функцию. Важно не забыть заменить именно функцию — иначе инъекция останется.

Совместимость

Обратной несовместимости нет — просто добавляется новая функция. Если в вашем коде уже определена пользовательская функция mysqli_quote_string(), это вызовет конфликт.

Ссылки

Теги: