Я работаю над динамическим запросом, который использует переменные для указания таблицы, поля / столбца и значения для поиска. Я получил запрос работать как ожидалось без переменных, как в 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);
Ожидаемые результаты : массив строк из базы данных
Фактические результаты : пустой массив
К сожалению, подготовленный оператор может представлять только литерал данных. Итак, очень распространенная ошибка – это такой запрос:
$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