Ответ 1
Правила добавления переменной PHP внутри любого оператора MySQL просты и понятны:
- Любая переменная, представляющая литерал данных SQL (или, проще говоря, строку SQL или число) , должна быть добавлена с помощью подготовленного оператора. Без исключений.
- Любая другая часть запроса, такая как ключевое слово SQL, имя таблицы или поля или оператор, должна быть отфильтрована через белый список.
Итак, поскольку в вашем примере используются только литералы данных, все переменные должны быть добавлены через заполнители (также называемые параметрами). Для этого:
- В своем выражении SQL замените все переменные на заполнители
- подготовить полученный запрос
- привязать переменные к заполнителям
- выполнить запрос
А вот как это сделать со всеми популярными драйверами баз данных PHP:
Добавление литералов данных с помощью mysql_query
Такого драйвера не существует.
Добавление литералов данных с использованием mysqli
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
VALUES(?, ?, 'whatever')";
$stmt = $mysqli->prepare($query);
$stmt->bind_param("ss", $type, $reporter);
$stmt->execute();
Код немного сложен, но подробное объяснение всех этих операторов можно найти в моей статье, Как выполнить запрос INSERT с помощью Mysqli, а также решение, которое значительно облегчает процесс.
Добавление литералов данных с использованием PDO
$type = 'testing';
$reporter = "John O'Hara";
$query = "INSERT INTO contents (type, reporter, description)
VALUES(?, ?, 'whatever')";
$stmt = $pdo->prepare($query);
$stmt->execute([$type, $reporter]);
В PDO мы можем объединять части связывания и выполнения, что очень удобно. PDO также поддерживает именованные заполнители, которые некоторые считают чрезвычайно удобными.
Добавление ключевых слов или идентификаторов
Но иногда мы добавляли переменную, которая представляет другую часть запроса, такую как ключевое слово или идентификатор (база данных, таблица или имя поля). В этом случае ваша переменная должна быть проверена по списку значений, явно написанных в вашем скрипте. Это объясняется в другой моей статье: Добавление имени поля в предложении ORDER BY на основе выбора пользователя:
К сожалению, в PDO нет места для идентификаторов (имен таблиц и полей), поэтому разработчик должен отфильтровать их вручную. Такой фильтр часто называют "белым списком" (где мы только перечисляем допустимые значения), а не "черным списком", где мы перечисляем недопустимые значения.
Поэтому мы должны явно перечислить все возможные варианты в коде PHP и затем выбрать из них.
Вот пример:
$orderby = $_GET['orderby'] ?: "name"; // set the default value
$allowed = ["name","price","qty"]; // the white list of allowed field names
$key = array_search($orderby, $allowed, true); // see if we have such a name
if ($key === false) {
throw new InvalidArgumentException("Invalid field name");
}
Точно такой же подход следует использовать для направления,
$direction = $_GET['direction'] ?: "ASC";
$allowed = ["ASC","DESC"];
$key = array_search($direction, $allowed, true);
if ($key === false) {
throw new InvalidArgumentException("Invalid ORDER BY direction");
}
После такого кода обе переменные $direction
и $orderby
могут быть безопасно добавлены в запрос SQL, поскольку они либо равны одному из разрешенных вариантов, либо возникнет ошибка.
Последнее, что следует упомянуть об идентификаторах, они также должны быть отформатированы в соответствии с конкретным синтаксисом базы данных. Для MySQL это должно быть backtick
символов вокруг идентификатора. Таким образом, последняя строка запроса для нашего заказа в качестве примера будет выглядеть так:
$query = "SELECT * FROM 'table' ORDER BY '$orderby' $direction";