Кавычки в MySQL: одинарные, двойные и бэктики – полный разбор

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему кавычки в MySQL сводят с ума?

Если вы хоть раз писали SQL-запросы на PHP, то наверняка сталкивались с путаницей: когда ставить одинарные кавычки (' '), когда двойные (" "), а когда эти загадочные бэктики (` `)? Ошибка в одном символе — и вместо данных вы получаете синтаксическую ошибку MySQL или, что ещё хуже, дыру в безопасности.

Эта тема — один из самых популярных вопросов на Stack Overflow (более 2 миллионов просмотров!). И не зря. Даже опытные разработчики иногда путаются. Сегодня мы раз и навсегда расставим все точки над i. Вы узнаете:

  • За что отвечает каждый тип кавычек в MySQL
  • Как правильно экранировать данные в PHP
  • Почему двойные кавычки — это зло (почти всегда)
  • Как защититься от SQL-инъекций

Поехали! 🚀

Анатомия MySQL-запроса: три типа кавычек

В MySQL есть три разных символа, которые выглядят как кавычки, но выполняют совершенно разные задачи:

1. Одинарные кавычки (' ') — для строковых значений

Когда использовать: всегда, когда вы передаёте строку (текст, дату, email, пароль).

SELECT * FROM users WHERE name = 'Иван';
INSERT INTO articles (title) VALUES ('MySQL для чайников');

MySQL воспринимает всё, что внутри одинарных кавычек, как литерал строки. Это значит, что вы говорите базе: «Вот тут у меня значение, не пытайся интерпретировать его как имя столбца или команду».

2. Двойные кавычки (" ") — почти то же самое, но с нюансом

В стандартном SQL двойные кавычки используются для идентификаторов (имён таблиц и столбцов). Но MySQL по умолчанию работает в режиме, где двойные кавычки эквивалентны одинарным. Это часто сбивает с толку.

-- Это сработает, но лучше так не делать
SELECT * FROM users WHERE name = "Мария";

Проблема: если вы включите строгий режим ANSI_QUOTES, двойные кавычки начнут работать как бэктики. Ваш код сломается. Поэтому:

Правило №1: Используйте одинарные кавычки для строк. Всегда. Двойные — только если вы точно знаете, что делаете, или для совместимости с другими СУБД.

3. Бэктики (` `) — для имён таблиц и столбцов

Бэктики (обратные кавычки) — это идентификаторы. Они нужны, чтобы:

  • Использовать зарезервированные слова как имена (плохая практика, но бывает)
  • Работать с именами, содержащими пробелы или спецсимволы
  • Избежать конфликтов с ключевыми словами MySQL
-- Плохо: 'select' — зарезервированное слово
SELECT * FROM select;

-- Хорошо: экранируем бэктиками
SELECT * FROM `select`;

-- Обязательно: имя с пробелом
SELECT `user name` FROM users;

-- Рекомендуется: всегда экранировать имена таблиц и столбцов
SELECT `id`, `name` FROM `users` WHERE `status` = 'active';

Важно: бэктики НЕЛЬЗЯ использовать для значений. Это вызовет ошибку.

-- ОШИБКА: MySQL подумает, что 'Иван' — это имя столбца
SELECT * FROM users WHERE name = `Иван`;

PHP + MySQL: как не запутаться в кавычках

Теперь самое интересное — как это всё работает в PHP. PHP сам использует одинарные и двойные кавычки для строк, и тут легко ошибиться.

Случай №1: Прямая вставка переменной (опасно!)

// ПЛОХО: уязвимость к SQL-инъекциям
$name = "Иван'; DROP TABLE users; --";
$query = "SELECT * FROM users WHERE name = '$name'";
// Результат: SELECT * FROM users WHERE name = 'Иван'; DROP TABLE users; --'

Это классическая SQL-инъекция. Никогда так не делайте!

Случай №2: Экранирование через mysqli_real_escape_string (лучше, но не идеал)

$name = "Иван' OR '1'='1";
$safe_name = mysqli_real_escape_string($conn, $name);
$query = "SELECT * FROM users WHERE name = '$safe_name'";
// Теперь безопасно

Работает, но легко забыть экранировать. Плюс разные кодировки могут подкинуть сюрприз.

Случай №3: Подготовленные запросы (правильный путь!)

Золотой стандарт: используйте PDO или mysqli с подготовленными запросами. PHP сам позаботится о кавычках.

// PDO — современный и безопасный способ
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute([':name' => 'Иван']);
$users = $stmt->fetchAll();

// или с позиционными плейсхолдерами
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = ?');
$stmt->execute(['Иван']);

С подготовленными запросами вы никогда не думаете о кавычках для значений. PDO сам экранирует и подставляет данные.

Полный пример: работающая PHP-страница

Давайте соберём всё вместе. Представьте, что мы пишем функцию для поиска пользователей по имени:

<?php
// Подключение к БД через PDO
$dsn = 'mysql:host=localhost;dbname=myblog;charset=utf8mb4';
$user = 'root';
$pass = '';

try {
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);
} catch (PDOException $e) {
    die('Ошибка подключения: ' . $e->getMessage());
}

// Безопасный поиск пользователя
function findUserByName(PDO $pdo, string $name): ?array
{
    // Используем подготовленный запрос — кавычки не нужны!
    $sql = 'SELECT `id`, `name`, `email` FROM `users` WHERE `name` = ?';
    $stmt = $pdo->prepare($sql);
    $stmt->execute([$name]);
    
    return $stmt->fetch() ?: null;
}

// Пример использования
$searchName = "Олег'; DROP TABLE users; --"; // попытка инъекции
$user = findUserByName($pdo, $searchName);

if                

Блоги

Рекомендаций по книгам