Для создания подключения к серверу базы данных в PDO применяется конструктор new PDO(), который принимает в качестве параметров настройки подключения:
new PDO("mysql:host=адрес_сервера;port=номер_порта;dbname=имя_базы_данных", "имя_пользователя", "пароль")
Принимаемые параметры:
mysql:
.host
, которая задает хост сервера, например, host=localhost
(если сервер MySQL запущен локально).3306
.dbname
, которая устанавливает имя базы данных.При успешном подключении вызов конструктора new PDO() возвращает созданный объект PDO, который представляет установленное подключение и через который мы сможем взавмодействовать с базой данных. Однако если установка подключения прошла неудачно (например, сервер базы данных недоступен, указаны неправильные имя пользователя и/или пароль, какая-то еще ошибка), то вызов конструктора генерирует исключение. Соответственно вызов данного конструктора лучше помещать в конструкцию try catch
.
Определим простейший скрипт для подключения к серверу базы данных MySQL:
try {
// подключаемся к серверу
$conn = new PDO("mysql:host=localhost", "root", "mypassword");
echo "Database connection established";
}
catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
Здесь производится подключение к локальному серверу, поэтому в строке подключения параметр host имеет значение localhost
. Поскольку база данных пока не важна, то параметр dbname не указан. Подключение производится для пользователя - пользователя root
, для которого установлен пароль mypassword
.
root
- это пользователь по умолчанию, который существует для сервера MySQL. А mypassword
- пароль, установленный для этого пользователя. Естественно в каждом конкретном случае пароль для этого пользователя может отличаться. Однако если на сервере MySQL созданы другие пользователи, то можно указывать этих пользователей и их пароли.
При успешном подключении созданный объект PDO будет сохранен в переменную $conn, через которую мы затем сможем взаимодействовать с MySQL:
$conn = new PDO("mysql:host=localhost", "root", "mypassword");
Если произойдет ошибка, то будет сгенерировано исключение типа PDOException. Как и у других классов исключений с помощью метода getMessage() мы можем получить сообщение об ошибке.
И при успешном подключении мы увидим в браузере следующее сообщение:
Database connection established
А если произойдет ошибка, то браузер выведет сообщение об ошибке. Например, сообщение об ошибке при некорректном пароле:
Connection failed: SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES)
Если при взаимодействии с MySQL произойдет ошибка, то, как правило, ожидается, что мы получим сообщение об ошибке. Однако реальное поведение зависит от редима вывода ошибок, который установлен для объекта PDO. Режим вывода ошибок задается с помощью атрибута PDO::ATTR_ERRMODE
, который может принимать следующие значения:
PDO::ERRMODE_SILENT:
PDO просто устанавливает код ошибки. Для получения которого и для получения информации об ошибке по которому необходимо было вызывать специальные методы. Поскольку при этом режиме необходимо вызывать дополнительные методы, то этот способ обычно рассматривался как не самый удобный. Он был значением по умолчанию до версии PHP 8.0.
PDO::ERRMODE_WARNING:
PDO генерирует сообщение типа E_WARNING
. Обычно применяется при отладке или тестировании
PDO::ERRMODE_EXCEPTION:
PDO передает информацию об ошибке в объект PDOException, благодаря чему через блок catch
в конструкции try catch
мы можем отловить ошибку и получить информацию об этом исключении. Этот режим применяется как режим по умолчанию начиная с версии PHP 8.0.
Если мы хотим получать информацию об ошибке через исключение PDOException и обрабатывать его в блоке catch, то нам нужно значение PDO::ERRMODE_EXCEPTION
. В PHP 8.0 и выше это значение применяется по умолчанию, однако, если версия ниже 8.0, то необходимо это значение установить явным образом с помощью метода setAttribute()
объекта PDO:
try {
$conn = new PDO("mysql:host=localhost", "root", "mypassword");
// установка режима вывода ошибок
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
echo "Database connection established";
}
catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
После завершения работы скрипта PHP автоматически закрывает открытые подключения к базе данных. Но может потребоваться закрыть подключение еще в процессе работы скрипта. В этом случае объекту PDO можно присвоить значение null:
$conn = null; // отключаемся от сервера базы данных
Для выполнения запросов к серверу базы данных у объекта PDO вызывается метод exec(), в который передается выполняемое выражение SQL.
$conn = new PDO("mysql:host=localhost", "root", "mypassword");
$conn->exec(команда_sql);
Для создания базы данных применяется SQL-команда CREATE DATABASE, после которой указывается имя создаваемой базы данных.
Создадим базу данных через PHP:
try {
// подключаемся к серверу
$conn = new PDO("mysql:host=localhost", "root", "mypassword");
// SQL-выражение для создания базы данных
$sql = "CREATE DATABASE testdb1";
// выполняем SQL-выражение
$conn->exec($sql);
echo "Database has been created";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
В данном случае после подключения к серверу определяется переменная $sql, которая хранит команду на создание бд с именем "textdb1":
$sql = "CREATE DATABASE testdb1";
Далее для выполнения этой команды передаем ее в метод exec():
$conn->exec($sql);
В итоге при успешном создании базы данных мы увидим в браузере сообщение об создании БД: Database has been created
.
Подобным образом можно выполнять запросы на создание таблиц в базе данных. Для создания таблиц применяется SQL-команда CREATE TABLE, после которой указывается имя создаваемой таблицы и в скобках определения столбцов.
Так, возьмем выше созданную базу данных "testdb1". И создадим в ней таблицу, которая описывается следующим кодом:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER);
Здесь создается таблица под названием users
. Она будет хранить условных пользователей. В ней будет три столбца: id, name и age. Столбец id представляет числовой уникальный идентификатор строки - или идентификатор пользователя. Столбец name представляет строку - имя пользователя. А столбец age представляет число - возраст пользователя.
Для создания таблицы определим следующий скрипт php:
try {
// подключаемся к серверу
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
// SQL-выражение для создания таблицы
$sql = "create table users (id integer auto_increment primary key, name varchar(30), age integer);";
// выполняем SQL-выражение
$conn->exec($sql);
echo "Table Users has been created";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
Обратите внимание, что по сравнению с предыдущим примером здесь в строке подключения указана база данных, в которой создается таблица: mysql:host=localhost;dbname=testdb1
.
И после успешного выполнения запрос мы увидим в браузере сообщение об создании таблицы: Table Users has been created
.
Для добавления данных в БД 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:
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
// SQL-выражение для добавления данных
$sql = "INSERT INTO Users (name, age) VALUES ('Tom', 37)";
$affectedRowsNumber = $conn->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
и затем выводим ее значение в браузере. Поэтому при успешном добавлении мы увидим В таблицу Users добавлено строк: 1
.
Также мы можем добавить сразу несколько объектов:
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "INSERT INTO Users (name, age) VALUES
('Sam', 41),
('Bob', 29),
('Alice', 32)";
$affectedRowsNumber = $conn->exec($sql);
echo "В таблицу Users добавлено строк: $affectedRowsNumber";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
Здесь в таблицу добавляется три строки. Соответственно в браузере мы увидим В таблицу Users добавлено строк: 3
.
В большинстве случаев добавляемые данные будут приходить из вне, например, присылаться в запросе пользователя. Рассмотрим добавление данных, отправленных из формы HTML. Для этого определим следующий скрипт:
<?php
if (isset($_POST["username"]) && isset($_POST["userage"])) {
$username = $_POST["username"];
$userage = $_POST["userage"];
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "INSERT INTO Users (name, age) VALUES ('$username', $userage)";
$affectedRowsNumber = $conn->exec($sql);
// если добавлена как минимум одна строка
if($affectedRowsNumber > 0 ){
echo "Data successfully added: name=$username age= $userage";
}
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
}
?>
<h3>Create a new User</h3>
<form method="post">
<p>User Name:
<input type="text" name="username" /></p>
<p>User Age:
<input type="number" name="userage" /></p>
<input type="submit" value="Save">
</form>
Здесь мы проверяем, пришли ли с сервера данные в 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
выполняется.
Перепишем предыдущий пример с использованием параметров:
<?php
if (isset($_POST["username"]) && isset($_POST["userage"])) {
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";
// определяем prepared statement
$stmt = $conn->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();
}
}
?>
<h3>Create a new User</h3>
<form method="post">
<p>User Name:
<input type="text" name="username" /></p>
<p>User Age:
<input type="number" name="userage" /></p>
<input type="submit" value="Save">
</form>
В SQL-выражении теперь применяются параметры:
$sql = "INSERT INTO Users (name, age) VALUES (:username, :userage)";
:username
и :userage
- это названия параметров. Причем они начинаются с символа двоеточия :
.
Само выражение prepared statement
создается с помощью метода prepare()
объекта PDO, в который передается выполняемая sql-команда:
$stmt = $conn->prepare($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()
также передается массив. Первое значение массива привязывается к первому параметру (условно добавляется вместо первого знака вопроса), второе значение привязывается ко второму параметру.
На уровне кода SQL получение данных осуществляется с помощью команды SELECT. Например, получение всех данных из таблицы Users:
SELECT * FROM Users
В библиотеке pdo для получения данных у объекта PDO вызывается метод query()
, в который передается команда SQL. Метод query()
возвращает объект PDOStatement, который представляет набор всех полученных из базы данных строк.
$sql = "SELECT * FROM Users";
$result = $conn->query($sql);
Получив объект PDOStatement, мы можем извлечь данные. В частности, его метод fetch()
при первом обращении первую строку (если в наборе есть строки):
$row = $result->fetch();
При последующих обращениях метод fetch()
возвращает следующие строки, пока в наборе не останется строк. Если строк в наборе больше нет, то метод возвращает false. Поэтому для получения всех строк удобно использовать циклы. Например, цикл while
:
while($row = $result->fetch()){
// обработка строк
}
Таким образом, при каждой итерации цикл while
будет получать новую строку из набора в переменную $row, пока метод $result->fetch()
не возвратит false
- после чего произойдет выход из цикла.
Строка возвращается в виде ассоциативного массива, где отдельные значения - это столбцы строки, а ключи этих значений - названия столбцов таблицы. Например, получение значения столбца name
в переменную:
while($row = $result->fetch()){
$username = $row["name"];
// операции с $username
}
Вместо цикла while можно использовать цикл for
/foreach
. Например:
foreach($result as $row){
$username = $row["name"];
// операции с $username
}
Здесь явным образом не вызывается метод $result->fetch()
. Формально мы просто перебираем переменную $result
как обычный массив, также помещая каждую строку в переменную $row
.
Теперь все объединим и получим данные из таблицы Users из прошлых тем, которая имеет следующее определение:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)
Для этого определим следующий простенький скрипт:
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "SELECT * FROM Users";
$result = $conn->query($sql);
echo "<table><tr><th>Id</th><th>Name</th><th>Age</th></tr>";
while($row = $result->fetch()){
echo "<tr>";
echo "<td>" . $row["id"] . "</td>";
echo "<td>" . $row["name"] . "</td>";
echo "<td>" . $row["age"] . "</td>";
echo "</tr>";
}
echo "</table>";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
В данном случае полученные данные будут выводиться в таблицу, создаваемую элементом <table>
.
Выше применялся метод query()
для получения всех данных из БД. Но что, если нам надо получить не все, а какие-то определенные данные, которые овечают некоторому критерию, иными словами, произвести фильтрацию данных. Например, возьмем использовавшуюся в прошлых темах таблицу Users
:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)
Она имеет столбец id, и мы хотим получить определенный объект по id. На первый взгляд мы могли бы определить следующий код:
$sql = "SELECT * FROM Users WHERE id = 1";
$result = $conn->query($sql);
Для фильтрации команде SELECT
передается выражение WHERE
, которая принимает названия столбцов их значения в качестве критерия фильтрации. То есть, здесь мы получаем строке, где id = 1
.
Однако если данные для фильтрации приходят извне, например, значение для столбца id, то опять же, как и в случае с добавлением, мы сталкиваемся с потенциальной уязвимостью кода. И также, как и при добавлении, в этом случае лучше использовать параметризацию и prepared statements
.
Например, мы хотим получать в GET-запросе значение для id
и по нему получть из базы данных нужные данные. Определим для этого следующий скрипт user.php
:
<?php
if(isset($_GET["id"]))
{
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "SELECT * FROM Users WHERE id = :userid";
$stmt = $conn->prepare($sql);
// привязываем значение параметра :userid к $_GET["id"]
$stmt->bindValue(":userid", $_GET["id"]);
// выполняем выражение и получаем пользователя по id
$stmt->execute();
if($stmt->rowCount() > 0){
foreach ($stmt as $row) {
$username = $row["name"];
$userage = $row["age"];
echo "<div>
<h3>Информация о пользователе</h3>
<p>Имя: $username</p>
<p>Возраст: $userage</p>
</div>";
}
}
else{
echo "Пользователь не найден";
}
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
}
?>
Для выполнения запроса к БД вначале создаем prepared statement
, которое использует параметр userid
, привязанный к значению $_GET["id"]
:
$sql = "SELECT * FROM Users WHERE id = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindValue(":userid", $_GET["id"]);
Далее у полученного объекта PDOStatement вызываем метод execute()
, который выполняет запрос к базе:
$stmt->execute();
После выполнения команды SELECT
этот объект содержит полученные из БД данные, которые мы можем перебрать с помощью цикла:
if($stmt->rowCount() > 0){
foreach ($stmt as $row) {
$username = $row["name"];
$userage = $row["age"];
}
При этом с помощью метода rowCount()
мы можем узнать количество возвращенных строк. Получение данных столбцов строки производится как и было описано выше для простого запроса SELECT
. Получив данные столбцов в переменные, мы можем затем что-то с ними сделать, например, вывести их значения на страницу.
Чтоб было проще обращаться к скрипту user.php
и передавать ему id
, определим скрипт index.php
, который будет выводить список объектов:
<h2>Список пользователей</h2>
<?php
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "SELECT id, name FROM Users";
$result = $conn->query($sql);
echo "<table><tr><th>Имя</th><th></th></tr>";
foreach($result as $row){
echo "<tr>";
echo "<td>" . $row["name"] . "</td>";
echo "<td><a href='user.php?id=" . $row["id"] . "' >Посмотреть</a></td>";
echo "</tr>";
}
echo "</table>";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
?>
Здесь все объекты из базы данных выводятся в таблицу, где второй столбец содержит ссылку на скрипт user.php
, которому передается соответствующее значение id
. В итоге по нажатию на эту ссылку мы перейдем к описанию объекта по id
.
Для обновления применяется sql-команда UPDATE
:
UPDATE Таблица
SET столбец1 = значение1, столбец2 = значение2,...
WHERE столбец = значение
В библиотеке pdo для обновления данных может применяться тот же метод exec()
объекта PDO, который применяется при добавлении. Например, возьмем использованную в прошлых темах таблицу Users со следующим определением:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)
Изменим в этой таблице поле age
для строки, которая имеет id = 1
:
<?php
try {
$conn = new PDO("mysql:host=localhost;dbname=test", "root", "mypassword");
$sql = "UPDATE Users SET age = 22 WHERE id = 1";
$affectedRowsNumber = $conn->exec($sql);
echo "Обновлено строк: $affectedRowsNumber";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
?>
Результат метода $conn->exec()
в данном случае количество обновленных строк.
Однако если данные на обновление приходят извне, то мы опять как и при добавлении сталкиваемся с потенциальной уязвимостью подобного подхода. Поэтому в этом случаае опять же лучше использовать параметризацию и prepared statements
.
Сначала определим файл index.php, который будет выводить список пользователей:
<h2>Список пользователей</h2>
<?php
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "SELECT * FROM Users";
$result = $conn->query($sql);
echo "<table><tr><th>Имя</th><th>Возраст</th><th></th></tr>";
foreach($result as $row){
echo "<tr>";
echo "<td>" . $row["name"] . "</td>";
echo "<td>" . $row["age"] . "</td>";
echo "<td><a href='update.php?id=" . $row["id"] . "'>Обновить</a></td>";
echo "</tr>";
}
echo "</table>";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
?>
Здесь используется команда SELECT
, которая получает всех пользователей из таблицы Users
. В таблице третий столбец хранит ссылку на скрипт update.php, который мы далее создадим и которому передается параметр id
с идентификатором пользователя, которого надо изменить.
Теперь определим файл update.php
для редактирования пользователей:
<?php
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
}
catch (PDOException $e) {
die("Database error: " . $e->getMessage());
}
?>
<?php
// если запрос GET
if($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["id"]))
{
$userid = $_GET["id"];
$sql = "SELECT * FROM Users WHERE id = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindValue(":userid", $userid);
// выполняем выражение и получаем пользователя по id
$stmt->execute();
if($stmt->rowCount() > 0){
foreach ($stmt as $row) {
$username = $row["name"];
$userage = $row["age"];
}
echo "<h3>Обновление пользователя</h3>
<form method='post'>
<input type='hidden' name='id' value='$userid' />
<p>Имя:
<input type='text' name='name' value='$username' /></p>
<p>Возраст:
<input type='number' name='age' value='$userage' /></p>
<input type='submit' value='Сохранить' />
</form>";
}
else{
echo "Пользователь не найден";
}
}
elseif (isset($_POST["id"]) && isset($_POST["name"]) && isset($_POST["age"])) {
$sql = "UPDATE Users SET name = :username, age = :userage WHERE id = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindValue(":userid", $_POST["id"]);
$stmt->bindValue(":username", $_POST["name"]);
$stmt->bindValue(":userage", $_POST["age"]);
$stmt->execute();
header("Location: index.php");
}
else{
echo "Некорректные данные";
}
?>
Весь код обновления структурно делится на две части. В первой части мы обрабатываем запрос GET
. Когда пользователь нажимает на ссылку Обновить
на странице index.php
, то отправляется запрос GET
, в котором передается id
редактируемого пользователя. Поэтому мы сначала смотрим, представляет ли запрос GET-запрос и имеет ли он параметр id
.
if($_SERVER["REQUEST_METHOD"] === "GET" && isset($_GET["id"]))
И если это запрос GET, то нам надо вывести данные редактируемого пользователя в поля формы. Для этого отправляем базе данных запрос:
$sql = "SELECT * FROM Users WHERE id = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindValue(":userid", $userid);
$stmt->execute();
Далее получаем полученные данные и, если они имеются, выводим их в поля формы. Таким образом, пользователь увидит на форме данные редактируемого объекта.
Вторая часть скрипта представляет обработку POST-запроса - когда пользователь нажимает на кнопку на форме, то будет отправляться POST-запрос с отправленными данными. Мы получаем эти данные и отправляем базе данных команду UPDATE
с этими данными, используя при этом параметризацию запроса:
$sql = "UPDATE Users SET name = :username, age = :userage WHERE id = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindValue(":userid", $_POST["id"]);
$stmt->bindValue(":username", $_POST["name"]);
$stmt->bindValue(":userage", $_POST["age"]);
$stmt->execute();
После выполнения запроса к БД перенаправляем пользователя на скрипт index.php с помощью функции:
header("Location: index.php");
Таким образом, пользователь обращается к скрипту index.php, видит таблицу с данными и нажимает на ссылку Обновить
в одной из строк.
После нажатия его перебрасывает на скрипт update.php, который выводит данные редактируемого объекта. Пользователь изменяет данные и нажимает на кнопку.
Данные в запросе POST отправляются этому же скрипту update.php, который сохраняет данные и перенаправляет пользователя обратно на index.php.
Для удаления данных применяется sql-команда DELETE
:
DELETE FROM Таблица
WHERE столбец = значение
Для удаления данных также может применяться метод exec()
объекта PDO. Например, возьмем использованную в прошлых темах таблицу Users со следующим определением:
CREATE TABLE Users (id INTEGER AUTO_INCREMENT PRIMARY KEY, name VARCHAR(30), age INTEGER)
Удалим из этой таблицы строку, где id = 5
:
try {
$conn = new PDO("mysql:host=localhost;dbname=test", "root", "mypassword");
$sql = "DELETE FROM Users WHERE id = 5";
$affectedRowsNumber = $conn->exec($sql);
echo "Удалено строк: $affectedRowsNumber";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
Результат метода $conn->exec()
в данном случае количество удаленых строк. Однако опять же поскольку значение столбца, на основе которого происходит удаление, нередко приходит извне, то в этом случае лучше использовать параметризацию.
Итак, определим для вывода всех объектов из БД скрипт index.php
:
<h2>Список пользователей</h2>
<?php
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "SELECT * FROM Users";
$result = $conn->query($sql);
echo "<table><tr><th>Имя</th><th>Возраст</th><th></th></tr>";
foreach($result as $row){
echo "<tr>";
echo "<td>" . $row["name"] . "</td>";
echo "<td>" . $row["age"] . "</td>";
echo "<td><form action='delete.php' method='post'>
<input type='hidden' name='id' value='" . $row["id"] . "' />
<input type='submit' value='Удалить'>
</form></td>";
echo "</tr>";
}
echo "</table>";
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
?>
В таблицы для каждой строки определена форма, которая посылает данные в POST-запросе скрипту delete.php
. Чтобы передать в delete.php
идентификатор удаляемого объекта, на форме определено скрытое поле для хранения id
объекта.
Обратите внимание, что в данном случае применяется не ссылка для удаления типа
<a href="http://адрес_нашего_сайта/delete.php?id=1">Удалить<a/>
которая оправляет данные в GET-запросе, а именно форма, которая отправляет данные в POST-запросе. Почему? Подобные GET-запросы потенциально небезопасны. Допустим, нам пришло электронное письмо, в которое была внедрена картинка посредством тега:
<img src="http://адрес_нашего_сайта/delete.php?id=1" />
В итоге при открытии письма 1-я запись в таблице может быть удалена. Уязвимость касается не только писем, но может проявляться и в других местах, но смысл один - GET-запрос к скрипту, который удаляет данные, несет потенциальную уязвимость.
Теперь определим сам скрипт delete.php
, который будет выполнять удаление:
if(isset($_POST["id"]))
{
try {
$conn = new PDO("mysql:host=localhost;dbname=testdb1", "root", "mypassword");
$sql = "DELETE FROM Users WHERE id = :userid";
$stmt = $conn->prepare($sql);
$stmt->bindValue(":userid", $_POST["id"]);
$stmt->execute();
header("Location: index.php");
}
catch (PDOException $e) {
echo "Database error: " . $e->getMessage();
}
}
В данном случае скрипт получает через POST-запрос значение id
и по этому идентификатору выполняет удаление. После чего происходит переадресация на скрипт index.php
.