Rozszerzamy skrypt z poprzednich zajęć o możliwość dodawania i usuwania rekordów w bazie.
Przypominam, że w poniższym kodzie nie dokonaliśmy jeszcze zabezpieczeń odbieranych z formularza danych.
Należy dokonać dodatkowo walidacji odbieranych danych, która uchroni nas przed atakami SQL Injection, a zapytania do bazy najlepiej opracowywać z wykorzystaniem Prepared Statements, o których trochę niżej.
Do istniejącego formularza dodajemy 2 nowe inputy: Dodai i Usuń, następnie odbieramy dane i dokonujemy na ich podstawie zmian w bazie.
<?php
//ustawiamy dane do bazy
$serwer = "localhost";
$user = "root";
$pass = "";
$base = "operacje_db";
$db = @new mysqli($serwer, $user, $pass, $base);
if ($db->connect_error) {
die('Błąd połączenia z bazą danych: ' . $db->connect_error);
} else {
echo "Połączenie nawiązano<br>";
if (!empty($_POST['przycisk'])) { //sprawdzamy czy kliknięto wyszukaj
$sql = "SELECT * FROM `test` WHERE 1";
if (!empty($_POST['imie'])) $sql .= " && imie='{$_POST['imie']}'";
if (!empty($_POST['nazwisko'])) $sql .= " && nazwisko='{$_POST['nazwisko']}'";
echo $sql . "<br>";
$wynik = $db->query($sql);
foreach ($wynik as $row) {
echo "Witaj {$row['imie']} {$row['nazwisko']}<br>";
}
} elseif (!empty($_POST['add'])) { //sprawdzamy czy kliknięto dodaj
if (!empty($_POST['imie']) && !empty($_POST['nazwisko'])) {
$sql = "INSERT INTO `test`(`imie`, `nazwisko`) VALUES ('{$_POST['imie']}','{$_POST['nazwisko']}')";
$wynik = $db->query($sql);
//echo $db->affected_rows . ' ' . $db->insert_id;
$ar = $db->affected_rows;
if ($ar != 0) echo "Dodano {$_POST['imie']} {$_POST['nazwisko']}";
} else {
echo "Uzupełnij pola.";
}
} elseif (!empty($_POST['del'])) { //sprawdzamy czy kliknięto usuń
if (!empty($_POST['imie']) && !empty($_POST['nazwisko'])) {
$sql = "DELETE FROM `test` WHERE imie='{$_POST['imie']}' && nazwisko='{$_POST['nazwisko']}'";
$wynik = $db->query($sql);
//echo $db->affected_rows . ' ' . $db->insert_id;
$ar = $db->affected_rows;
if ($ar != 0) echo "Usunięto rekordy w ilości: $ar o wartościach: {$_POST['imie']} {$_POST['nazwisko']}";
} else {
echo "Uzupełnij pola.";
}
} else {
echo "Wykonaj akcję.";
}
}
$db->close();
?>
<form action="" method="post">
Imię: <input type="text" name="imie">
Nazwisko: <input type="text" name="nazwisko">
<input type="submit" value="Wyszukaj" name="przycisk">
<input type="submit" value="Dodaj" name="add">
<input type="submit" value="Usuń" name="del">
</form>
Wykorzystanie “bindowania”, czyli parameterized prepared statements – bezpieczeństwo przede wszystkim
Sparametryzowane zapytania pozwalają na wykonywanie kodu SQL zabezpieczonego przed SQL Injection.
Działa to w ten sposób, że najpierw przygotowujemy zapytanie, czyli do bazy wysyłany jest szablon kwerendy, w którym zamiast zmiennych podajemy znaki zapytania – “?”. Na tej podstawie serwer inicjuje swoje wewnętrzne zasoby do późniejszego wykorzystania.
W kolejnym kroku “bindujemy”, czyli wiązemy ze sobą wartości parametrów (każdemu znakowi zapytania przypisujemy zmienną) i wysyłamy je na serwer.
Na koniec zamykamy parametryzację, by zwolnić zasoby.
Ale dlaczego to takie bezpieczne?
Zbindowane zmienne są wysyłane do serwera niezależnie od zapytania, serwer używa tych wartości tylko w momencie wykonania, po przeanalizowaniu szablonu instrukcji. Parametry nigdy nie są bezpośrednio podstawiane w ciągu zapytania. Należy dostarczyć do serwera wskazówkę dotyczącą typu zmiennej powiązanej, aby utworzyć odpowiednią konwersję.
Przykład podstawowego użycia prepare statements
<?php
//ustawiamy dane do bazy
$serwer = 'localhost'; //lub 127.0.0.1 - to jest nazwa serwera
$user = 'root'; //użytkownik bazy danych
$pass = ''; //hasło do bazy
$baza = 'operacje_db'; //nazwa bazy
//łączenie z bazą
$db = @new mysqli($serwer, $user, $pass, $baza); //podejście obiektowe - korzystamy z klasy PHP o nazwie mysqli
//sprawdzamy czy się łączy w podejściu obiektowym
if ($db->connect_error) {
die('Błąd połączenia: ' . $db->connect_error);
} else {
echo 'Połączenie nawiązano<br />';
if (!empty($_POST['add'])) {
$imie = !empty($_POST['imie']) ? $_POST['imie'] : 'nobody';
$nazwisko = !empty($_POST['nazwisko']) ? $_POST['nazwisko'] : 'nobody';
//przygotowujemy zapytanie
$sql = "INSERT INTO `test`(`imie`, `nazwisko`) VALUES (?, ?)";
$stmt = $db->prepare($sql);
//bindujemy parametry
$stmt->bind_param("ss", $imie, $nazwisko); //ss - oznacza string string
//wykonujemy zapytanie
$stmt->execute();
echo "Dodano do bazy: $imie $nazwisko";
} else {
echo "Prześlij formularz.";
}
}
$db->close(); //zamykamy połączenie
?>
<form action="" method="POST">
Imię: <input type="text" name="imie">
Nazwisko: <input type="text" name="nazwisko">
<input type="submit" name="add" value="Dodaj">
</form>
Przykład
<?php
//ustawiamy dane do bazy
$serwer = 'localhost'; //lub 127.0.0.1 - to jest nazwa serwera
$user = 'root'; //użytkownik bazy danych
$pass = ''; //hasło do bazy
$baza = 'operacje_db'; //nazwa bazy
//łączenie z bazą
$db = @new mysqli($serwer, $user, $pass, $baza); //podejście obiektowe - korzystamy z klasy PHP o nazwie mysqli
//sprawdzamy czy się łączy w podejściu obiektowym
if ($db->connect_error) {
die('Błąd połączenia: ' . $db->connect_error);
} else {
$imie = !empty($_POST['imie']) ? htmlspecialchars(stripslashes(trim($_POST['imie']))) : false;
$nazwisko = !empty($_POST['nazwisko']) ? htmlspecialchars(stripslashes(trim($_POST['nazwisko']))) : false;
if (!empty($_POST['add'])) {
if ($imie && $nazwisko) {
//----------------------------------------------------------------
//przygotowujemy zapytanie
$sql = "INSERT INTO `test`(`imie`, `nazwisko`) VALUES (?, ?)";
$stmt = $db->prepare($sql);
//bindujemy parametry
$stmt->bind_param("ss", $imie, $nazwisko); //ss - oznacza string string, drugi parametr musi być zmienną (nie można wpisać bezpośrednio wartości)
//wykonujemy zapytanie
$stmt->execute();
//----------------------------------------------------------------
/*
//tak możemy zobaczyć co jest w środku $stmt
echo '<pre>';
print_r($stmt);
echo '</pre>';
*/
if ($stmt->affected_rows != 0) echo "Dodano do bazy: $imie $nazwisko";
else echo "Nie dodano wiersza";
} else {
echo "Uzupełnij wszystkie pola";
}
} elseif (!empty($_POST['search'])) { //w zależności od uzupełnionego pola w formularzu
if ($imie || $nazwisko) {
$sql = "SELECT * FROM `test` WHERE 1";
//przygotowujemy dane do bindowania
$b_data_types = '';
$b_values = array();
if (!empty($imie)) {
$sql .= " && imie=?";
$b_data_types .= 's';
array_push($b_values, $imie);
}
if (!empty($nazwisko)) {
$sql .= " && nazwisko=?";
$b_data_types .= 's';
array_push($b_values, $nazwisko);
}
//----------------------------------------------------------------
//przygotowujemy zapytanie
$stmt = $db->prepare($sql);
$stmt->bind_param($b_data_types, ...$b_values);
$stmt->execute();
$wynik = $stmt->get_result();
foreach ($wynik as $row) {
echo "Witaj {$row['imie']} {$row['nazwisko']}<br>";
}
} else {
echo "Wypełnij przynajmniej jedno pole";
}
} elseif (!empty($_POST['all'])) { //wyświetl wszystkie
$sql = "SELECT * FROM `test`";
//----------------------------------------------------------------
//przygotowujemy zapytanie
$stmt = $db->prepare($sql);
$stmt->execute();
$wynik = $stmt->get_result();
foreach ($wynik as $row) {
echo "Witaj {$row['imie']} {$row['nazwisko']}<br>";
}
} else {
echo "Prześlij formularz.";
}
}
$db->close(); //zamykamy połączenie
?>
<form action="" method="POST">
Imię: <input type="text" name="imie">
Nazwisko: <input type="text" name="nazwisko">
<input type="submit" name="add" value="Dodaj">
<input type="submit" name="all" value="Wyświetl wszystko">
<input type="submit" name="search" value="Wyszukaj">
</form>