Jak skasować jednocześnie wiele pól w bazie danych za pomocą pola checkbox?

Treść dodana: 14 marca 2017.

W dzisiejszym poradniku pokażę, w jaki sposób można za pomocą prostego skryptu napisanego w PHP, kasować wiele rekordów w bazie danych. Do połączenia wykorzystamy bazę danych MySQL oraz sterownik PDO. Przykładowa struktura bazy danych poniżej.

CREATE TABLE `users` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`imie` VARCHAR(50) NOT NULL,
	`nazwisko` VARCHAR(150) NOT NULL,
	PRIMARY KEY (`id`)
)
ENGINE=InnoDB;

INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (1, 'Jan', 'Kowalski');
INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (2, 'Anna', 'Kowalska');
INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (3, 'Michał', 'Nowak');
INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (4, 'Jan', 'Turek');
INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (5, 'Ewelina', 'Sosna');
INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (6, 'Piotr', 'Gąsienica');
INSERT INTO `users` (`id`, `imie`, `nazwisko`) VALUES (7, 'Ryszard', 'Topola');

Nasza tabela przedstawia typowe informacje o użytkownikach. Znajdują się w niej rekord `id` będący zarazem kluczem głównym, oraz pola `imie` i `nazwisko`. Oczywiście w środowisku produkcyjnym pól będzie zapewne więcej. Tabelę wypełniamy przy okazji losowymi danymi. Co w tym momencie jest dla nas ważne, to informacja w jaki sposób wyszukiwać kasowane rekordy. Oczywistym kandydatem do rozróżniania rekordów jest pole zawierające klucz główny. Jest ono unikalne, zatem jednoznacznie identyfikuje konkretny rekord. Wykorzystajmy ten fakt przy wyświetlaniu użytkowników (zakładam że zapoznałeś się Czytelniku z podstawami PDO):

<!DOCTYPE HTML>
<html lang="pl-PL">
<head>
    <meta charset="UTF-8">
    <title>Kasowanie użytkowników</title>
</head>
<body>
<?php
    try {
        $dsn = 'mysql:dbname=test;host=127.0.0.1';
        $user = 'root';
        $pass = '';
        $dbh = new PDO($dsn, $user, $pass);
        $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
        $dbh->exec("SET NAMES 'UTF8';");
        $sql = 'SELECT * FROM users';
        $stmt = $dbh->query($sql);
        if ($stmt->rowCount() < 1) {
            echo '<p>Nie istnieje żaden użytkownik</p>';
        } else {
            echo '<form method="POST"><table>';
            echo '<tr><th>Zaznacz</th><th>Id</th><th>Imię</th><th>Nazwisko</th></tr>';
            while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                echo '<tr>';
                echo '<td><input type=checkbox name=ids[] value="'. $row['id'] .'"/></td>';
                echo '<td>', $row['id'], '</td>';
                echo '<td>', $row['imie'], '</td>';
                echo '<td>', $row['nazwisko'], '</td>';
                echo '</tr>';
            }
            echo '<tr><td colspan=4><input type=submit name=submit value="Skasuj zaznaczone"/></td></tr>';
            echo '</table></form>';
        }

    } catch (PDOException $e) {
        echo 'Klasa PDO zwróciła wyjątek: ' . $e->getMessage();
    }
?>
</body>
</html>

Stworzyliśmy prostą stronę listującą wszystkich dostępnych w bazie użytkowników. W przypadku gdy nie ma jeszcze żadnego rekordu, zostanie wyświetlony stosowny komunikat. Cała tabela zawarta jest wewnątrz formularza (wysyłanego metodą POST), a w pierwszej kolumnie znajduje się checkbox którym zaznaczamy kasowane rekordy. Użytkownika i hasło do MySQL należy zmienić według potrzeb. Gdyby nie udało się nawiązać połączenia z bazą, lub wystąpiłby inny błąd sterownika, zostanie wyświetlona informacja o wyjątku.

Pora zająć się kasowaniem rekordów:

if (isset($_POST['submit'])) {
    $ids = isset($_POST['ids']) ? $_POST['ids'] : [];
    if (count($ids) < 1) {
        echo '<p>Zaznacz przynajmniej jedno pole</p>';
    } else {
        // przygotowujemy placeholder na podstawie dynamicznie obliczonej liczby elementów
        // dla 3 wybranych elementów będzie miał postać '?,?,?'
        $placeholder = implode(',', array_fill(0, count($ids), '?'));
        // przygotowujemy zapytanie
        // "DELETE FROM users WHERE `id` IN(?,?,?)" 
        $sql = 'DELETE FROM users WHERE `id` IN('. $placeholder .')';
        $sth = $dbh->prepare($sql);
        foreach ($ids as $k => $id) {
            $sth->bindValue(($k+1), $id, PDO::PARAM_INT);
        }
        if ($sth->execute()) {
            echo '<p>Zaznaczone pola zostały skasowane</p>';
        } else {
            echo '<p>Kasowanie rekordów nie powiodło się</p>';
        }
    }
}

W pierwszej kolejności sprawdzamy czy formularz został wysłany (poprzez pole o nazwie `submit` – name=submit). Do kasowania wykorzystujemy operator MySQL – IN. Jednak żeby poprawnie zabezpieczyć dane musimy przygotować odpowiednią ilość “placeholderów”, czyli uchwytów przechowujących `id` użytkowników. Następnie “bindujemy” wartości wskazując, iż są one typu liczbowego (PARAM_INT). PHP wewnętrznie przekształci je na liczby. Zapytanie takie będzie zabezpieczone przed potencjalnym atakiem SQL Injection.

Gdzie najlepiej wstawić powyższy kod? Kasowanie powinno się odbywać przed wyświetleniem użytkowników, zatem najlepszym miejscem będzie linia:

$dbh->exec("SET NAMES 'UTF8';");
if (isset($_POST['submit'])) { //...

Powyższy kod gotowy jest do produkcyjnego wykorzystania. Jak widać nie jest szczególnie skomplikowany jeżeli znamy podstawy programowania obiektowego. Największą trudność może stanowić kasowanie rekordów, ale stosując prostą sztuczkę poradziliśmy sobie z nim – za pomocą tylko jednego zapytania do bazy.

Komentarze

Nie ma jeszcze żadnych komentarzy do wyświetlenia. Może chcesz zostać pierwszą osobą która podzieli się swoją opinią?

Dodaj komentarz

*
Nazwa zostanie wyświetlona wraz z komentarzem. Możesz też utworzyć nowe konto w serwisie, dzięki czemu uzyskasz dodatkową funkcjonalność.
*
Akceptowana jest ograniczona składnia Textile. Wszystkie tagi HTML zostaną usunięte.