Могу ли я использовать подготовленный документ PDO для привязки идентификатора (имя таблицы или поля) или ключевое слово синтаксиса? - программирование
Подтвердить что ты не робот

Могу ли я использовать подготовленный документ 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);

Ожидаемые результаты: массив строк из базы данных

Фактические результаты: пустой массив

4b9b3361

Ответ 1

Могу ли я использовать подготовленный оператор PDO для привязки идентификатора (имя таблицы или поля) или ключевое слово синтаксиса?

К сожалению, подготовленный оператор может представлять только литерал данных. Итак, очень распространенная ошибка - это такой запрос:

$opt = "id";
$sql = "SELECT :option FROM t WHERE id=?";
$stm  = $pdo->prepare($sql);
$stm->execute(array($opt));
$data = $stm->fetchAll();

Зависит от настроек PDO, этот запрос будет вызван либо ошибкой (в случае использования реальных подготовленных операторов), либо буквальной строкой 'id' в наборе полей (в случае эмулированных подготавливаний).

Итак, разработчик должен сам позаботиться об идентификаторах - PDO предлагает без помощи.

Чтобы сделать динамический идентификатор безопасным, нужно следовать двум строгим правилам:

  • для правильного форматирования идентификатора
  • чтобы проверить его на жестком закодированном белом списке.

Чтобы отформатировать идентификатор, нужно применить эти 2 правила:

  • Введите идентификатор в backticks.
  • Сбегите назад, удвоив их.

После такого форматирования безопасно вставить переменную $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:: quote