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

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

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

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

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

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

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

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

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

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

Чтобы отформатировать идентификатор, необходимо применить эти 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 :: quote