Как грамотно вставить название таблицы из переменной в SQL-запрос? PHP/PDO

03.04.2024

Как грамотно вставить название таблицы из переменной в SQL-запрос? PHP/PDO

Поскольку через подготовленные выражения можно подставлять только данные, то для имен полей и таблиц остается только фильтрация через белый список - то есть проверка по явно прописанному в коде списку разрешенных значений.


Использование ORM

Вариантов реализации может быть много, один из них предложен автором в комментариях - считать из БД все названия таблиц и запомнить их. Это, в принципе, может сработать. Некоторые фреймворки даже кэшируют эту информацию (например Yii). В случае с продвинутыми ORM названия полей-таблиц берутся из свойств соответствующего класса, опять же, прописанные вручную.


Фильтрация через белый список

Но если мы колупаемся по-старинке, выполняя запросы напрямую через PDO, то проще всего будет прописать доступные варианты прямо перед использованием, тем более что таких случаев не должно быть много - иначе у нас явные проблемы с проектированием.

Плюс надо не забыть оформить имя поля или таблицы в соответствии с синтаксисом базы данных. Например, для mysql это будет заключение значения в backtick-и.


В итоге получаем примерно такой код:

if (!in_array($table, ["user","product","catalog"]));
{
throw new \InvalidArgumentException("Invalid table name!");
}
$sql = "SELECT * FROM `$table` WHERE foo = ?" // далее как обычно
Динамическое составление запросов INSERT/UPDATE

Куда более частой является ситуация, когда нам надо выполнить запрос UPDATE динамически, если имена полей приходят, допустим, из $_POST. Принцип остается тем же:

/ список допустимых значений
$allowed = ["name","surname","email"];

// инициализация массива для значений
$params = [];

// инициализация строки с парами `fieldname` = :placeholder
$setStr = "";

// цикл по разрешенным полям
foreach ($allowed as $key)
{
if (isset($_POST[$key]) && $key != "id")
{
$setStr .= " `$key` = ?,";
$params[] = $_POST[$key];
}
}
$setStr = rtrim($setStr, ",");

$params[] = $_POST['id'];
$pdo->prepare("UPDATE users SET $setStr WHERE id = ?")->execute($params);

что делать нельзя


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

mysql_real_escape_string. многие поколения пхп кодеров считали и считают, что эта функция служит для защиты от неких инъекций. С такой точки зрения ее применение, конечно, оправдано. Но если однажды открыть для себя реальное предназначение этой функции, то станет ясно, что она здесь нужна как хипстеру андроид. Можно даже посмотреть действующий пример SQL инъекции, которой эта, как и любая другая функция искейпинга строк, не может помешать ни в малейшей степени.


PDO::quote(). Уже гораздо лучше. В отличие от предыдущего варианта, который пройдет незамеченным, а потом пропустит инъекцию, quote() вызовет ошибку немедленно, поскольку выбирать данные из строки БД еще не научились - им нужно название таблицы.
Некоторое время назад в комментариях к этой функции в мануале висел комментарий, причем с кучей положительных оценок, предлагавший оторвать от полученного значения добавленные к нему кавычки. Я посоветовал вместо этого оторвать руки предложившему, но сошлись на том, что оторвут только его комментарий. В итоге я написал свой, с объяснениями, как делать правильно.

Мужчину осудили за пересылку порно на Тернопольщине, — решение суда

Мужчину осудили за пересылку порно на Тернопольщине, — решение суда

03.04.2024

Мужчину осудили за пересылку порно на Тернопольщине, — решение суда

Подробности...
США готовятся к войне с Китаем. Продолжаются учения, — WP

США готовятся к войне с Китаем. Продолжаются учения, — WP

03.04.2024

США готовятся к войне с Китаем. Продолжаются учения, — WP

Подробности...
Росія атакує південь, щоб змусити населення звертатись до влади шодо перемовин

Росія атакує південь, щоб змусити населення звертатись до влади шодо перемовин

03.04.2024

Росія атакує південь, щоб змусити населення звертатись до влади шодо перемовин

Подробности...
Финансирование разработок военных технологий в Украине увеличится с $162 млн. до $1,3 млрд. до 2030 года, — The New York Times

Финансирование разработок военных технологий в Украине увеличится с $162 млн. до $1,3 млрд. до 2030 года, — The New York Times

03.04.2024

Финансирование разработок военных технологий в Украине увеличится с $162 млн. до $1,3 млрд. до 2030 года, — The New York Times

Подробности...
Призывной возраст останется на уровне 27 лет, если в «мобилизационном» законопроекте его не снизят до 25, — нардеп Олег Дунда

Призывной возраст останется на уровне 27 лет, если в «мобилизационном» законопроекте его не снизят до 25, — нардеп Олег Дунда

03.04.2024

Призывной возраст останется на уровне 27 лет, если в «мобилизационном» законопроекте его не снизят до 25, — нардеп Олег Дунда

Подробности...
Україна та Фінляндія підписали Угоду про співробітництво у сфері безпеки та довгострокову підтримку, — Зеленський

Україна та Фінляндія підписали Угоду про співробітництво у сфері безпеки та довгострокову підтримку, — Зеленський

03.04.2024

Україна та Фінляндія підписали Угоду про співробітництво у сфері безпеки та довгострокову підтримку, — Зеленський

Подробности...