php mysql crud

Podstawy CRUD (Create, Read, Update, Delete) w PHP i MySQL

Nie od dziś wiemy, że w teraźniejszym, cyfrowym świecie, zarządzanie danymi to klucz do sukcesu wielu aplikacji webowych. W artykule dowiecie się, czym jest CRUD, jak z niego korzystać, jak przydatnym „zlepkiem narzędzi” jest ten akronim.

PHP i MySQL są potężnym duetem, który umożliwia tworzenie dynamicznych i interaktywnych stron internetowych z zaawansowanym zarządzaniem danymi. Owszem, i zgodzę się z tym, że znajdą się zwolennicy używania PHP i MySQL do tworzenia dynamicznych stron WWW tak samo jak przeciwnicy, którzy uważają, że są znacznie wydajniejsze technologie, a tak w ogóle to PHP to nie programowanie 🙂 Ale nie o tym tu i teraz.

Tu przyjrzymy się, jak można zaimplementować operacje CRUD (Create, Read, Update, Delete) w PHP 8 i MySQL, tworząc prostą bazę danych i interfejs użytkownika do zarządzania danymi.

Czym jest CRUD?

CRUD to akronim od angielskich słów Create, Read, Update, Delete, które odnoszą się do czterech podstawowych funkcji zarządzania danymi w bazach danych.

  • Create – tworzenie nowych rekordów;
  • Read – odczytywanie istniejących rekordów;
  • Update – aktualizowanie istniejących rekordów;
  • Delete – usuwanie istniejących rekordów.

Na tych 4 elementach skupimy się w tym artykule, tworząc przykładową bazę danych i ją za pomocą CRUD edytując.

Utworzenie bazy danych i tabeli

Pierwszym krokiem jest utworzenie bazy danych MySQL, która będzie przechowywać nasze dane. Użyjemy do tego MySQL Workbench, phpMyAdmin lub innego narzędzia do zarządzania bazą danych.

CREATE DATABASE blogData;
USE blogData;

CREATE TABLE articles (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(50) NOT NULL,
content TEXT,
publication_date TIMESTAMP
);

Kolejno, żebyśmy tak na prawdę mieli na czym wstępnie ćwiczyć, wstawimy kilka przykładowych rekordów, aby móc na nich pracować:

INSERT INTO articles (title, content, publication_date) VALUES
('Pierwszy artykuł', 'To jest treść pierwszego artykułu.', NOW()),
('Drugi artykuł', 'To jest treść drugiego artykułu.', NOW());

Implementacja CRUD w PHP 8

Teraz, kiedy mamy bazę danych i tabelę, przejdźmy do implementacji funkcji CRUD w PHP. Poniżej znajduje się przykładowy kod pokazujący, jak te operacje mogą być wykonane.

Połączenie z bazą danych

Utworzymy plik db.php, który będzie odpowiedzialny za nawiązanie połączenia z bazą danych. Dobrą praktyką jest trzymanie w oddzielnym pliku danych konfiguracyjnych, związanych z połączeniem z bazą, podobnie jak trzymanie wszystkich funkcji w 1 pliku, odseparowywanie stałych elementów widoku stron do oddzielnych plików, czy tworzenie plików ze stylami, np. style.css w którym trzymane są wszystkie nasze kaskadowe arkusze styli, klasy, identyfikatory. Jest to o tyle ważne, by w chwili konieczności dokonania zmiany, która ma zadziałać globalnie, dokonywać ją tylko w 1 pliku, include’owanym do wszystkich widoków naszej strony/serwisu, którego dotyczy.

Zawartość pliku db.php

<?php
$servername = "localhost";
$username = "username";
$password = "password";
$dbname = "blogData";

// Utworzenie połączenia
$conn = new mysqli($servername, $username, $password, $dbname);

// Sprawdzenie połączenia
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
?>

Create – Dodawanie nowych rekordów

Utworzymy prosty formularz HTML, aby użytkownik mógł dodać nowy artykuł, oraz skrypt PHP, który przetworzy formularz i doda rekord do bazy danych.

Formularz (create.html)

<form action="create.php" method="post">
Tytuł: <input type="text" name="title"><br>
Treść: <textarea name="content"></textarea><br>
<input type="submit">
</form>

Skrypt PHP (create.php)

<?php
include 'db.php';

$title = $_POST['title'];
$content = $_POST['content'];

$sql = "INSERT INTO articles (title, content, publication_date) VALUES (?, ?, NOW())";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ss", $title, $content);
$stmt->execute();

echo "Artykuł dodany pomyślnie";
$stmt->close();
$conn->close();
?>

Read – Odczytywanie rekordów

Aby wyświetlić artykuły, użyjemy poniższego skryptu PHP:

Skrypt PHP (read.php)

<?php
include 'db.php';

$sql = "SELECT id, title, content, publication_date FROM articles";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - Tytuł: " . $row["title"]. " - Treść: " . $row["content"]. "<br>";
}
} else {
echo "0 results";
}
$conn->close();
?>

Update i Delete

Aby zająć się tymi dwoma mechanizmami, czyli mechaniką Update, aktualizacji danych poszczególnego rekordu w bazie oraz Delete, czyli możliwością usunięcia rekordu z poziomu PHP, stworzony zostanie plik index.php, w którym wyświetlona zostanie tabela, zawierająca wszystkie rekordy z tabeli, z naszego przykładu. W tabeli zawarte będą też akcje, w postaci linków dynamicznych, kierujące do plików edit.php oraz delete.php. Te jak to nazwałem „akcje” muszą jednak posługiwać się konkretnym identyfikatorem, żeby skrypt wiedział, który rekord w bazie chcemy usunąć lub wyedytować. Przejdźmy więc do realizacji tego problemu:

Plik index.php wyświetli wszystkie rekordy z tabeli articles wraz z przyciskami do edycji i usuwania.

Skrypt PHP (index.php)

<?php
include 'db.php';

$sql = "SELECT id, title, publication_date FROM articles";
$result = $conn->query($sql);
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Lista Artykułów</title>
</head>
<body>
<h2>Lista Artykułów</h2>
<table>
<tr>
<th>Tytuł</th>
<th>Data Dodania</th>
<th>Akcje</th>
</tr>
<?php if ($result->num_rows > 0): ?>
<?php while($row = $result->fetch_assoc()): ?>
<tr>
<td><?php echo $row["title"]; ?></td>
<td><?php echo $row["publication_date"]; ?></td>
<td>
<a href="edit.php?id=<?php echo $row["id"]; ?>">Edytuj</a>
<a href="delete.php?id=<?php echo $row["id"]; ?>" onclick="return confirm('Czy na pewno chcesz usunąć ten rekord?');">Usuń</a>
</td>
</tr>
<?php endwhile; ?>
<?php else: ?>
<tr><td colspan="3">Brak artykułów</td></tr>
<?php endif; ?>
</table>
</body>
</html>
<?php
$conn->close();
?>

Skrypt PHP (edit.php)

Strona edit.php wyświetla formularz do edycji wybranego rekordu.

<?php
include 'db.php';

// Pobieranie danych rekordu na podstawie przekazanego ID
if(isset($_GET['id'])) {
$id = $_GET['id'];
$sql = "SELECT * FROM articles WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $id);
$stmt->execute();
$result = $stmt->get_result();
if($result->num_rows == 1) {
$row = $result->fetch_assoc();
$title = $row['title'];
$content = $row['content'];
} else {
echo "Nie znaleziono artykułu.";
exit;
}
} else {
echo "Nieprawidłowe ID.";
exit;
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<title>Edycja Artykułu</title>
</head>
<body>
<h2>Edycja Artykułu</h2>
<form action="update.php" method="post">
<input type="hidden" name="id" value="<?php echo $id; ?>">
Tytuł: <input type="text" name="title" value="<?php echo $title; ?>"><br>
Treść: <textarea name="content"><?php echo $content; ?></textarea><br>
<input type="submit" value="Zaktualizuj">
</form>
</body>
</html>

Skrypt PHP (update.php)

Plik update.php przetwarza żądanie aktualizacji rekordu.

<?php
include 'db.php';

if(isset($_POST['id']) && isset($_POST['title']) && isset($_POST['content'])) {
$id = $_POST['id'];
$title = $_POST['title'];
$content = $_POST['content'];

$sql = "UPDATE articles SET title = ?, content = ? WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ssi", $title, $content, $id);

if($stmt->execute()) {
echo "Artykuł zaktualizowany pomyślnie.";
} else {
echo "Błąd podczas aktualizacji artykułu.";
}
$stmt->close();
} else {
echo "Wszystkie pola są wymagane.";
}

$conn->close();
?>

Skrypt PHP (delete.php)

Plik delete.php odpowiada za usunięcie rekordu.

<?php
include 'db.php';

if(isset($_GET['id'])) {
$id = $_GET['id'];

$sql = "DELETE FROM articles WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("i", $id);

if($stmt->execute()) {
echo "Artykuł usunięty pomyślnie.";
} else {
echo "Błąd podczas usuwania artykułu.";
}
$stmt->close();
} else {
echo "Nieprawidłowe ID.";
}

$conn->close();
?>

Komentarz

Na koniec, kilka słów komentarza. Otóż pamiętaj, że dla każdego z powyższych skryptów trzeba dostosować dane dostępu do bazy danych w pliku db.php. Jeśli przenosisz swój skrypt, np, ze szkoły do domu, chcesz nad nim nadal pracować, zacznij od sprawdzenia czy dane dostępowe do Twojej bazy w pliku db.php są poprawne na stanowisku, na którym aktualnie pracujesz. Każdy plik php, omówiony w przykładzie posiada na początku include 'db.php'; który to właśnie „include-uje/załącza kod zawarty w db.php tak, by plik docelowy, np. delete.php mógł z niego korzystać.

Omówmy jeszcze kilka zawartych w przykładzie elementów:

Czym jest $stmt->bind_param(„i”, $id);?

Metoda $stmt->bind_param() w PHP jest używana do przypisania zmiennych do odpowiednich miejsc zastępczych (placeholderów) w zapytaniu SQL przygotowanym przez metodę prepare(). Pozwala to na bezpieczne przekazywanie zmiennych do zapytania SQL, pomagając zapobiegać atakom SQL Injection poprzez oddzielenie instrukcji SQL od danych wejściowych użytkownika. Metoda bind_param() jest częścią rozszerzenia mysqli, które umożliwia interakcję z bazami danych MySQL.

W wywołaniu metody bind_param("i", $id); w kontekście pliku delete.php, który dotyczy usuwania rekordu:

  • "i" – określa typ danych, który zostanie przekazany. W tym przypadku "i" oznacza, że przekazany argument będzie traktowany jako liczba całkowita (integer). Jest to ważne, ponieważ informuje bazę danych o typie danych, które są przekazywane, co może być istotne dla poprawnego przetwarzania zapytania. Dostępne typy to:
    • i – integer (liczba całkowita),
    • d – double (liczba zmiennoprzecinkowa),
    • s – string (łańcuch znaków),
    • b – blob (dane binarne).
  • $id – to zmienna zawierająca wartość, która zostanie przekazana do zapytania w miejscu zastępczym. W kontekście usuwania rekordu jest to identyfikator (ID) rekordu, który ma zostać usunięty.

Przykład użycia metody bind_param("i", $id); w zapytaniu do usunięcia rekordu gwarantuje, że do zapytania zostanie przekazany bezpiecznie identyfikator rekordu, unikając ryzyka wstrzyknięcia szkodliwego kodu SQL. To sprawia, że przygotowane zapytania są rekomendowanym sposobem na interakcję z bazą danych w aplikacjach PHP.

Czym jest $row = $result->fetch_assoc();?

Metoda $result->fetch_assoc() w PHP jest używana do pobrania pojedynczego wiersza z zestawu wyników zapytania do bazy danych jako tablicę asocjacyjną. W tablicy asocjacyjnej klucze odpowiadają nazwom kolumn w wynikowym wierszu z bazy danych. Metoda ta jest częścią rozszerzenia MySQLi i PDO, służącego do interakcji z bazami danych MySQL.

Kiedy wykonujesz zapytanie do bazy danych za pomocą metod takich jak mysqli_query() lub przygotowanego zapytania za pomocą mysqli_prepare(), wynik zwracany przez bazę danych jest reprezentowany przez obiekt klasy mysqli_result (w przypadku rozszerzenia MySQLi). Aby przetworzyć wyniki zapytania, możesz użyć różnych metod. Jedną z nich jest właśnie fetch_assoc(), która pozwala na iteracyjne przetwarzanie każdego wiersza wynikowego.

Przykładowo, jeśli masz zapytanie, które zwraca wyniki z tabeli użytkowników, każde wywołanie metody fetch_assoc() zwróci następny dostępny wiersz wyników jako tablicę asocjacyjną, gdzie klucze tablicy będą nazwami kolumn, a wartości – odpowiadającymi im danymi użytkownika z tego wiersza. Jeśli w tabeli byłyby kolumny id, name, i email, każde wywołanie fetch_assoc() zwróciłoby coś w stylu:

[
'id' => '1',
'name' => 'Jan Kowalski',
'email' => 'jan.kowalski@example.com'
]

Zastosowanie $row = $result->fetch_assoc(); w pętli pozwala iterować przez wszystkie wiersze zwrócone przez zapytanie. Na przykład:

while($row = $result->fetch_assoc()) {
echo $row["name"] . " - " . $row["email"];
}

W tym kodzie dla każdego wiersza wynikowego tworzona jest tablica asocjacyjna $row, a następnie dane są wyświetlane. Gdy wszystkie wiersze zostaną przetworzone, fetch_assoc() zwróci null, co zakończy pętlę while.

Czym jest zapis $stmt->bind_param(„ssi”, $title, $content, $id); ?

Metoda $stmt->bind_param() jest częścią rozszerzenia MySQLi w PHP, używaną w kontekście przygotowanych zapytań (prepared statements) do bezpiecznego przekazywania zmiennych do zapytania SQL. Służy do powiązania zmiennych PHP z odpowiednimi parametrami w zapytaniu SQL, które są oznaczone jako miejsca zastępcze znakami zapytania ?. Dzięki temu mechanizmowi można uniknąć wielu problemów związanych z bezpieczeństwem, takich jak SQL Injection, ponieważ dane przekazywane do bazy danych są automatycznie sanitowane.

Wywołanie $stmt->bind_param("ssi", $title, $content, $id); wskazuje na kilka rzeczy:

  1. „ssi” – Ciąg znaków określający typy danych przekazywanych zmiennych. Każda litera w tym ciągu odpowiada jednej zmiennej, która zostanie przekazana do zapytania, a jej pozycja w ciągu odpowiada kolejności miejsca zastępczego w zapytaniu SQL. W tym przypadku:
    • s – oznacza string (łańcuch znaków). Pierwsza s odpowiada zmiennej $title, a druga s zmiennej $content.
    • i – oznacza integer (liczba całkowita), co odpowiada zmiennej $id.
  2. $title, $content, $id – Są to zmienne PHP, które zostają przekazane do zapytania. Ich wartości zostaną użyte w miejscach zastępczych zapytania SQL w kolejności, w jakiej są podane w bind_param().

Przykład użycia może wyglądać tak:

$sql = "UPDATE articles SET title = ?, content = ? WHERE id = ?";
$stmt = $conn->prepare($sql);
$stmt->bind_param("ssi", $title, $content, $id);

W tym przykładzie $title i $content są typu string, natomiast $id jest typu integer. Przygotowane zapytanie aktualizuje rekord w tabeli articles, ustawiając nowe wartości dla kolumn title i content dla rekordu o określonym id.

Użycie przygotowanych zapytań i powiązanie zmiennych z parametrami zapytania w ten sposób jest zalecaną praktyką, ponieważ znacznie zwiększa bezpieczeństwo aplikacji poprzez eliminację ryzyka wstrzyknięcia SQL.