- Подготовленные запросы
- Неименованный плейсхолдер
- Именованный плейсхолдер
- Метод bindParam()
- Php mysql параметрический запрос
- Множественное добавление
- Добавление данных из формы HTML
- Create a new User
- Параметризация запросов
- Create a new User
- Передача значений параметрам через массив по имени
- Передача значений параметрам через массив по позиции
Подготовленные запросы
Подготовленные запросы рекомендуется использовать вместо обычных запросов, потому что подготовленный запрос — это уже готовое, скомпилированное выражение к которому можно обращаться многократно просто передавая необходимые параметры.
Эти запросы работают намного быстрее и намного безопаснее , особенно, если в запросах используются условия с передаваемыми параметрами.
То есть, подготовленные запросы обеспечивают очень высокую безопасность от sql-инъекций.
Запрос на выборку данных :
Выбрать все из таблицы news , где id = 2 .
Обычно параметр id передается из вне, поэтому создадим переменную $id и в ней будем хранить передаваемые данные (в данном случае — 2).
Данный параметр мы получаем, например, из формы: формы авторизации, формы регистрации и т.д.
И, соответственно, этот параметр попадет в запрос ( id = ‘$id’ ).
С помощью стандартного метода query() выполняем запрос и распечатываем его на экран, используя метод fetchAll() .
$id = 2 ;
$sql = «SELECT id, title FROM news WHERE >$id ‘» ;
$result = $pdo -> query ( $sql );
print_r ( $result -> fetchAll ( PDO :: FETCH_ASSOC ));
После выполнения запроса получим:
Успешное подключение
Array ( [0] => Array ( [id] => 2 [title] => Новость 2 ) )
— все успешно работает, но данный код не безопасен .
Чтобы обеспечить безопасность от sql-инъекций будем использовать подготовленное выражение .
Неименованный плейсхолдер
Определив некий sql-запрос, в качестве параметра указываем метку — ? (вопросительный знак) — так называемый неименованный плэйсхолдер (placeholder — заполнитель).
Этим мы как бы указываем, что здесь должен быть указан некий параметр.
Затем данное выражение мы должны подготовить с помощью метода prepare() — то есть, указываем объекту PDO, что необходимо подготовить данное выражение.
Данный запрос будет скомпилирован, подготовлен и будет ждать своего выполнения
Далее, при необходимости, мы можем выполнять некий код, а в конце скрипта мы можем выполнить данный запрос.
Чтобы выполнить запрос обращаемся к объекту PDOStatement ($result) и вызываем на исполнение метод execute()
Метод execute() — выполняет подготовленное выражение .
В качестве параметра метода execute() передаем массив:
— в качестве первой ячейки мы используем переменную, которую заменил плэйсхолдер , в нашем случае — $id .
$id = 2 ;
$sql = «SELECT id, title FROM news WHERE >;
$result = $pdo -> prepare ( $sql );
// При необходимости, здесь мы можем выполнять некий код .
$result -> execute ( array ( $id ));
print_r ( $result -> fetchAll ( PDO :: FETCH_ASSOC ));
После выполнения запроса получим:
Успешное подключение
Array ( [0] => Array ( [id] => 2 [title] => Новость 2 ) )
— после выполнения запроса в браузере ни чего не изменилось.
Данный запрос уже безопасен и ему не страшны sql-инъекции.
Именованный плейсхолдер
Вместо неименованных плейсхолдеров (?) можно использовать именованные плейсхолдеры (например, для нашего случая — :id) — то есть, мы явно указываем имя данного параметра.
А это значит, что при вызове метода execute(), в качестве параметра, мы уже передаем ассоциативный массив.
В качестве ячейки которого указываем ключ ‘id’ , а в качестве значения данной ячейки указываем параметр $id :
.
$sql = «SELECT id, title FROM news WHERE >;
.
$result -> execute ( array ( ‘id’ => $id ));
или (альтернативная запись для массива):
$result -> execute ([ ‘id’ => $id ]);
.
Связывание параметра запроса с некой переменной .
Метод bindParam()
Метод bindParam() привязывает параметр запроса (плэйсхолдер) к определенной переменной .
Первым параметром он принимает имя плэйсхолдера ( ‘:id’ ), а в качестве второго параметра — переменную ( $id ), к значению которой ( 2 ) будет привязан данный плэйсхолдер.
В качестве третьего параметра указываем тип данных, который будет передаваться в данный плэйсхолдер, в нашем случае — PDO::PARAM_INT (целочисленный тип данных).
.
$result -> bindParam ( ‘:id’ , $id , PDO :: PARAM_INT );
$result -> execute ();
.
try <
$pdo = new PDO ( ‘mysql:host=localhost;dbname=test2’;charset=utf-8 , ‘root’ , » );
$pdo -> setAttribute ( PDO :: ATTR_ERRMODE , PDO :: ERRMODE_EXCEPTION );
echo «Успешное подключение
» ;
> catch exit ( ‘Ошибка подключения:
‘ . $e -> getMessage ());
>
——- Без использования плэйсхолдера ———
$id = 2 ;
$sql = «SELECT id, title FROM news WHERE >$id ‘» ;
$result = $pdo -> query ( $sql );
print_r ( $result -> fetchAll ( PDO :: FETCH_ASSOC ));
$id = 2 ;
$sql = «SELECT id, title FROM news WHERE >;
$result = $pdo -> prepare ( $sql );
// При необходимости, здесь мы можем выполнять некий код .
$result -> execute ( array ( $id ));
print_r ( $result -> fetchAll ( PDO :: FETCH_ASSOC ));
$id = 2 ;
$sql = «SELECT id, title FROM news WHERE >;
$result = $pdo -> prepare ( $sql );
// При необходимости, здесь мы можем выполнять некий код .
$result -> execute ( array ( ‘id’ => $id ));
print_r ( $result -> fetchAll ( PDO :: FETCH_ASSOC ));
$id = 2 ;
$sql = «SELECT id, title FROM news WHERE >;
$result = $pdo -> prepare ( $sql );
// При необходимости, здесь мы можем выполнять некий код .
$result -> bindParam ( ‘:id’ , $id , PDO :: PARAM_INT );
$result -> execute ();
print_r ( $result -> fetchAll ( PDO :: FETCH_ASSOC ));
> catch exit ( ‘Ошибка в запросе:
‘ . $e -> getMessage ());
>
?>
Во всех случаях получим:
Успешное подключение
Array ( [0] => Array ( [id] => 2 [title] => Новость 2 ) )
Php mysql параметрический запрос
Для добавления данных в БД MySQL применяется sql-команда INSERT , которая имеет следующий синтаксис:
INSERT INTO название_таблицы (столбец1, столбец2, столбецN) VALUES ( значение1, значение2, значениеN)
Данная команда также выполняется методом exec() объекта PDO. Стоит отметить, что для sql-команд INSERT , UPDATE и DELETE метод exec() возвращает количество затронутных командой строк (добавленных, измененных или удаленных). Таким образом, мы можем узнать сколько строк было добавлено.
Сначала рассмотрим простейшее добавление одного объекта в БД. Для примера возьмем созданную в прошлой теме базу данных «testdb1» и созданную в ней таблицу Users со следующим определением:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)
И для добавления определим следующий скрипт PHP:
exec($sql); echo "В таблицу Users добавлено строк: $affectedRowsNumber"; > catch (PDOException $e) < echo "Database error: " . $e->getMessage(); > ?>
Команда на добавление здесь выглядит следующим образом:
"INSERT INTO Users (name, age) VALUES ('Tom', 37)"
То есть в столбец name добавляется строка «Tom», а в столбец age — число 37. Для столбца id не добавляется никакого значения, потому что при создании таблицы для него указан параметр AUTO_INCREMENT — то есть значение этого столбца у каждой добавляемой строки будет автоматически увеличиваеться по сравнению с предыдущей на единицу.
При добавлении мы получаем количество добавленных строк в переменую $affectedRowsNumber и затем выводим ее значение в браузере. Поэтому при успешном добавлении мы увидим
Множественное добавление
Также мы можем добавить сразу несколько объектов:
exec($sql); echo "В таблицу Users добавлено строк: $affectedRowsNumber"; > catch (PDOException $e) < echo "Database error: " . $e->getMessage(); > ?>
Здесь в таблицу добавляется три строки. Соответственно в браузере мы увидим:
Добавление данных из формы HTML
В большинстве случаев добавляемые данные будут приходить из вне, например, присылаться в запросе пользователя. Рассмотрим добавление данных, отправленных из формы HTML. Для этого определим следующий скрипт:
exec($sql); // если добавлена как минимум одна строка if($affectedRowsNumber > 0 ) < echo "Data successfully added: name=$username age= $userage"; >> catch (PDOException $e) < echo "Database error: " . $e->getMessage(); > > ?>Create a new User
User Name:
User Age:
Здесь мы проверяем, пришли ли с сервера данные в POST-запросе, которые имеют ключи «username» и «userage»:
if (isset($_POST["username"]) && isset($_POST["userage"]))Если эти данные имеются, то есть был отправлен post-запрос с данными на добавление, то мы получаем эти данные в переменные и добавляем их в бд.
$sql = "INSERT INTO Users (name, age) VALUES ('$username', $userage)";Если была добавлена строка, то есть метод exec() возвратил число больше нуля, то выводим пользователю соответствующее сообщение.
После кода php собственно определена форма на добавление данных с помощью post-запроса.
Запустим скрипт. Введем в форму данные и нажмем на кнопку:
И данные будут добавлены. Вроде все хорошо. Однако здесь есть большой недостаток.
Параметризация запросов
Недостаток выше приведенного скрипа заключается в том, что мы никак не констролируем присылаемые данные и сохраняем их в базу данных как есть. Что несет потенциальную угрозу безопасности, особенно при добавлении строк типа "; DELETE FROM `Users`; -- . Кроме того, в ряде случае может быть проблематично добавить даже безопасные данные, например, строку, которая содержит одинарную кавычку, типа "Tom O'Brian".
Для решения этих проблем PDO предлагает параметризацию запросов с помощью применения заранее подготовленных выражений - prepared statement . Выражения prepared statement вместо жестко установленных значений или переменных принимают параметры, которые не привязаны к конкретным значениям. Эти выражения prepared statement посылаются серверу базы данных до того, как станут известны используемые данные, что позволяет серверу приготовить их к выполнению, но при этом они не выполняются. А когда пользователь присылает данные - параметры заменяются пришедшими данными, и выражение prepared statement выполняется.
Перепишем предыдущий пример с использованием параметров:
prepare($sql); // привязываем параметры к значениям $stmt->bindValue(":username", $_POST["username"]); $stmt->bindValue(":userage", $_POST["userage"]); // выполняем prepared statement $affectedRowsNumber = $stmt->execute(); // если добавлена как минимум одна строка if($affectedRowsNumber > 0 ) < echo "Data successfully added: name=" . $_POST["username"] ." age= " . $_POST["userage"]; >> catch (PDOException $e) < echo "Database error: " . $e->getMessage(); > > ?>Create a new User
User Name:
User Age:
В SQL-выражении теперь применяются параметры:
$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";:username и :userage - это названия параметров. Причем они начинаются с символа двоеточия :.
Само выражение prepared statement создается с помощью метода prepare() объекта PDO, в который передается выполняемая sql-команда:
Фактически здесь создается объект PDOStatement , который сохраняется в переменную $stmt .
Чтобы связать параметр с конкретным значением у объекта PDOStatement вызывается метод bindValue() . Первый параметр этого метода - собственно параметр из sql-команды, а второй параметр - передаваемое ему значение.
$stmt->bindValue(":username", $_POST["username"]);Так, в данном случае параметр :username привязывается к значению из $_POST["username"]
Причем привязка может производиться и к конкретным значениям и обычным переменным, например:
$user = "Tom" // привязка к переменной $user $stmt->bindValue(":username", $user);Для выполнения sql-выражения у объекта PDOStatement вызывается метод execute() , который для команды INSERT возвращает число добавленных строк.
Передача значений параметрам через массив по имени
В примере выше для параметризации применялся метод bindValue() :
$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)"; $stmt = $conn->prepare($sql); // привязываем параметры к значениям $stmt->bindValue(":username", $_POST["username"]); $stmt->bindValue(":userage", $_POST["userage"]); // выполняем prepared statement $affectedRowsNumber = $stmt->execute();Но есть и другой способ привязки параметров к значениям - мы можем передать в метод execute() параметры и их значения в виде ассоциативного массива:
$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)"; $stmt = $conn->prepare($sql); // через массив передаем значения параметрам по имени $rowsNumber = $stmt->execute(array(":username" => $_POST["username"], ":userage" => $_POST["userage"]));В этом случае названия параметров являются ключами.
Передача значений параметрам через массив по позиции
Третий способ привязки значений к параметрам представляет передачу значений по позиции:
$sql = "INSERT INTO Users (name, age) VALUES (?, ?)"; $stmt = $conn->prepare($sql); // через массив передаем значения параметрам по позиции $rowsNumber = $stmt->execute(array($_POST["username"], $_POST["userage"]));В этом случае вместо названий параметров применяются знаки вопроса ? . Для передачи этим параметрам значений в метод execute() также передается массив. Первое значение массива привязывается к первому параметру (условно добавляется вместо первого знака вопроса), второе значение привязывается ко второму параметру и т.д.