Как подготовить SQL-запрос динамически (имена столбцов тоже), избегая SQL-инъекций - PullRequest
2 голосов
/ 04 апреля 2019

Я недавно узнал о SQL-инъекциях и рекомендациях PHP, чтобы их избежать, используя prepare() и bind_param().Теперь я хочу подготовить SQL-запросы динамически, добавляя имена и значения столбцов.

Я использовал для этого, имея поле name для ввода HTML с тем же именем, что и столбец базы данных MySQL.

    <input type="text" name="firstname" >
    <input type="text" name="lastname" >

И, создайте запрос SQLдинамически используя mysqli.

    // Extract values from POST
    $parameters = $_POST;
    // Organize the values in two strings
    foreach ($parameters as $id => $value) {
        $fields = $fields . "`" . $id . "`,";
        $values = $values . "'" . $value . "',"; 

        /*e.g.
            $fields = `firstname`,`lastname`
            $values = 'John','Wick'
        */
    }

    // Write into the database
    $sql = "INSERT INTO `user` ($fields) VALUES ($values)";

    /*e.g.
        INSERT INTO `user` (`firstname`,`lastname`) VALUES ('John','Wick')
    */

Я хотел бы знать, есть ли способ сделать это, используя prepare() и bind_param(), чтобы избежать SQL-инъекций, возможно, добавив несколько data-type="s" в HTMLтег ввода или, если есть лучший, лучший метод, способ сделать это.

Ответы [ 2 ]

4 голосов
/ 04 апреля 2019

Вы можете использовать связанные параметры только для элемента, который будет постоянным значением - строка в кавычках, дата-время в кавычках или числовой литерал.

Нельзя использовать заполнитель параметров для чего-либо еще в SQL, например имен столбцов, имен таблиц, списков значений, ключевых слов или выражений SQL или другого синтаксиса.

Если вам нужно сделать имена столбцов динамическими, единственный вариант - проверить их по списку известных столбцов.

$columns_in_user_table = [
  'userid'=>null,
  'username'=>'',
  'firstname'=>'',
  'lastname'=>''
];
// Extract values from POST, but only those that match known columns
$parameters = array_intersect_key($_POST, $columns_in_user_table);
// Make sure no columns are missing; assign default values as needed
$parameters = array_merge($columns_in_user_table, $parameters);

Если вы используете PDO вместо mysqli, вы можете пропустить привязку. Просто используйте именованные параметры и передайте свой ассоциативный массив пар столбец-значение непосредственно в execute():

$columns = [];
$placeholders = [];
foreach ($parameters as $col => $value) {
    $columns[] = "`$col`";
    $placeholders[] = ":$col";
}
$column_list = implode($columns, ',');
$placeholder_list = implode($placeholders, ',');

// Write into the database
$sql = "INSERT INTO `user` ($column_list) VALUES ($placeholder_list)";

$stmt = $pdo->prepare($sql);
$stmt->execute($parameters);
0 голосов
/ 04 апреля 2019

Я заметил, что вы включили тег mysqli в свой вопрос, поэтому, если ваша база данных MySQL и вы используете встроенные функции MySQL, то вы можете сделать что-то вроде этого:

$stmt = mysqli_prepare($link, "INSERT INTO CountryLanguage VALUES (?, ?, ?, ?)");
mysqli_stmt_bind_param($stmt, 'sssd', $code, $language, $official, $percent);

$code = 'DEU';
$language = 'Bavarian';
$official = "F";
$percent = 11.2;

/* execute prepared statement */
mysqli_stmt_execute($stmt);

И да, яразорвал это прямо из справочной страницы PHP на mysqli_stmt_bind_param.

...