Могу ли я использовать подготовленный оператор PDO для привязки идентификатора (таблицы или имени поля) или синтаксического ключевого слова?
Я работаю над динамическим запросом, который использует переменные для указания таблицы, поля / столбца и значения для поиска. Я получил запрос для работы, как и ожидалось, без переменных, как в phpMyAdmin (вручную вводя запрос), так и из кода путем объединения переменных в полный запрос.
Тем не менее, когда я использую bindParam()
или же bindValue()
чтобы связать переменные, он возвращает пустой массив.
Вот мой код:
function search_db($db, $searchTerm, $searchBy, $searchTable){
try{
$stmt = $db->prepare('
SELECT
*
FROM
?
WHERE
? LIKE ?
');
$stmt->bindParam(1, $searchTable);
$stmt->bindParam(2, $searchBy);
$stmt->bindValue(3, '%'. $searchTerm.'%');
$stmt->execute();
} catch(Exception $e) {
return array();
}
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
// database initialization, creates the $db variable
require(ROOT_PATH . "include/database.php");
$matches = search_db($db, 'search term', 'myColumn', 'myTable');
var_dump($matches);
Ожидаемые результаты: массив строк из базы данных
Фактические результаты: пустой массив
1 ответ
Могу ли я использовать подготовленный оператор PDO для привязки идентификатора (таблицы или имени поля) или синтаксического ключевого слова?
К сожалению, подготовленное утверждение может представлять только литерал данных. Итак, очень распространенная ловушка - это такой запрос:
$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();
Зависит от настроек PDO, этот запрос приведет к ошибке (в случае использования реально подготовленных операторов) или просто литеральной строке 'id'
в поле fieldset (в случае эмулируемых приготовлений).
Таким образом, разработчик должен сам позаботиться об идентификаторах - PDO не предлагает никакой помощи в этом вопросе.
Для обеспечения безопасности динамического идентификатора необходимо соблюдать 2 строгих правила:
- правильно отформатировать идентификатор
- чтобы проверить это в жестко закодированном белом списке.
Чтобы отформатировать идентификатор, нужно применить эти 2 правила:
- Вложите идентификатор в кавычки.
- Побег задних внутри, удвоив их.
После такого форматирования безопасно вставить переменную $table в запрос. Итак, код будет:
$field = "`".str_replace("`","``",$field)."`";
$sql = "SELECT * FROM t ORDER BY $field";
Однако, хотя такого форматирования было бы достаточно для таких случаев, как ORDER BY, в большинстве других случаев существует возможность для другого вида внедрения: если пользователь может выбрать таблицу или поле, которое он может видеть, мы можем выявить некоторые конфиденциальная информация, такая как пароль или другие личные данные. Поэтому всегда лучше проверять динамические идентификаторы по списку допустимых значений. Вот краткий пример:
$allowed = array("name","price","qty");
$key = array_search($_GET['field'], $allowed);
$field = $allowed[$key];
$query = "SELECT $field FROM t"; //value is safe
Для ключевых слов правила одинаковы, но, конечно, нет доступного форматирования - поэтому возможен только белый список, и его следует использовать:
$dir = $_GET['dir'] == 'DESC' ? 'DESC' : 'ASC';
$sql = "SELECT * FROM t ORDER BY field $dir"; //value is safe
Смотрите также это примечание, внесенное пользователем в документацию PHP: Примечание пользователя на PDO:: цитата