INF.03 · Aplikacje internetowe PHP

Koszyk zakupowy w sesji

Koszyk: ID i ilość, nie cena z formularza.

  • PHP8.3
  • mysqli · MariaDB
  • Praktyka i diagnoza

Po tej lekcji: Zapiszesz ograniczony koszyk w sesji i obliczysz jego zawartość na podstawie rekordów bazy.

Zrozum mechanizm

W sesji koszyk jest mapą idFilmu=>ilosc. Dodanie i usunięcie to POST z tokenem. Sprawdź istnienie ID w bazie, zakres ilości i liczbę pozycji. W tym modelu maksimum to 20 różnych filmów i 10 sztuk każdego. Count(koszyk) podaje różne pozycje; suma ilości to inne pytanie.

Cena jest odczytywana z bazy. Ukryte pole cena nie jest zaufane — użytkownik może je zmienić. Zamiana ID na produkt z publicznego katalogu jest normalnym wyborem, ale zmiana własności danych czy ceny już nie. Kwoty mnożymy jako grosze. Jeśli rekord zniknie z bazy, podgląd nie powinien powodować błędu, a finalizacja musi ponownie sprawdzić wszystkie pozycje.

Jak uruchamiać krótkie przykłady?

Każdy krótki przykład oznaczony własnym plikiem uruchamiaj osobno, nie doklejaj wszystkich definicji do jednego pliku. W edytorze zapisz go jako .php, a w terminalu tego folderu wpisz np. php for.php. Wtedy pokazane końce wierszy PHP_EOL są widoczne. W odpowiedzi HTML znak końca wiersza sam nie robi nowej linii na ekranie: użyj <br> albo znacznika <pre>. Wyświetl źródło pozwala zobaczyć tekst odpowiedzi.

Przykłady opisane jako fragment projektu wymagają paczki KINO / LAB i wcześniejszej konfiguracji. Nie uruchamiaj ich jako samodzielnych endpointów. Pełny plik niżej pokazuje kontekst. Funkcje h(), pole() i wymagajPost() są nasze; ich definicje wczytuje bootstrap.php.

Koszyk: klucz to ID filmu, wartość to ilość

Najpierw prześledź na zwykłej tablicy, bez bazy. ID 7 i 12 są kluczami; wartości 2 i 1 są liczbami sztuk, nie cenami.

Podstawowa forma: $_SESSION["koszyk"][idFilmu] = ilosc;

cart.phpphp
<?php
$koszyk = [7 => 2, 12 => 1];
$koszyk[7] = ($koszyk[7] ?? 0) + 1;
$sztuki = 0;
foreach ($koszyk as $id => $ilosc) {
    $sztuki += $ilosc;
    echo "$id: $ilosc" . PHP_EOL;
}
echo 'Pozycje: ' . count($koszyk) . ', sztuki: ' . $sztuki;
Wynik
7: 3
12: 1
Pozycje: 2, sztuki: 4
  1. Odczytujemy dotychczasową ilość filmu 7, dodajemy 1 i zapisujemy 3. Dla nowego klucza ?? dałoby 0.
  2. foreach as id=>ilosc oddziela identyfikator od liczby sztuk. += dodaje do dotychczasowej sumy.
  3. count daje 2 różne pozycje, suma ilości daje 4 sztuki. Właśnie dlatego count nie wystarcza do pytania „ile biletów?”.
  4. W pełnym projekcie tablica jest w $_SESSION. ??= [] tworzy pusty koszyk tylko dla braku/null, min(10, wartosc) ogranicza ilość; cenę zawsze odczytuje serwer z bazy.

Jak czytać pozostałe zapisy w pełnym przykładzie

ZapisZnaczeniePrzykład użycia
pole($dane, $nazwa)Nasza funkcja: pobiera wskazany klucz tylko wtedy, gdy ma wartość string; inaczej oddaje pusty napis. isset sprawdza obecność i brak null, is_string typ.pole($_POST, "email")
wymagajPost()Nasza funkcja: sprawdza metodę POST oraz CSRF; przy błędzie przerywa odpowiedź z405/403.wymagajPost();
wymagajLogowania()Nasza funkcja: oddaje int ID konta z sesji lub przekierowuje do logowania. $id = wymagajLogowania();
przekieruj($adres)Nasza funkcja wysyła Location ze statusem303 i kończy wykonanie przez exit. Typ wyniku never oznacza, że nie wraca do dalszej instrukcji.przekieruj("/panel.php");
dirname(__DIR__)dirname daje katalog nadrzędny; __DIR__ to katalog bieżącego pliku. W public prowadzi to do katalogu projektu, a dopisana ścieżka wskazuje src.dirname(__DIR__)."/src/bootstrap.php"
$_SESSION i $_POSTSpecjalne tablice PHP: pierwsza to stan sesji, druga dane formularza POST. Zewnętrzne wartości trzeba sprawdzić, nie ufać samym nazwom kluczy.$_SESSION["user_id"]
?? i ??=a ?? b wybiera b dla braku/null; a ??= b zapisuje b tylko, gdy a nie istnieje lub ma null. Nie reagują na0 ani pusty napis.$_SESSION["koszyk"] ??= [];
===, !==, &&, ||, !Identyczne, nieidentyczne, i, lub, zaprzeczenie. Porównanie ścisłe obejmuje typ; &&/|| nie sprawdzają drugiej części, gdy wynik jest już rozstrzygnięty.$rok === false || $rok < 1888
-> oraz ::-> wybiera właściwość lub metodę obiektu; :: odnosi się do elementu statycznego klasy. To nie jest zapis dostępu do tablicy.$zapytanie->execute();

Sprawdź w działaniu

Koszyk: ID i ilość, nie cena z formularza — sprawdź w modelu

Model w przeglądarce wyjaśnia mechanizm na fikcyjnych danych. Nie wykonuje PHP ani zapytań SQL i nie tworzy kont. Prawdziwe skrypty uruchomisz lokalnie z paczki.

Ta interakcja wymaga włączonego JavaScriptu.

Przewidź rezultat, wykonaj próbę i wyjaśnij, która decyzja po stronie serwera decyduje o wyniku.

Uruchom krok po kroku

Zaloguj się, dodaj Podróż dwa razy i Kosmos raz. Otwórz koszyk: są 2 różne filmy,3 sztuki i 4197 groszy. Usuń jedną pozycję. Porównaj sesję ze źródłem cen w SELECT. Nie wypisuj pełnej sesji z danymi logowania do odpowiedzi.

Zmiana zawartości koszyka przez POST

public/koszyk.phpphp
<?php
require_once dirname(__DIR__).'/src/db.php';
wymagajLogowania();
$_SESSION['koszyk'] ??= [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    wymagajPost();
    $id = filter_var(pole($_POST, 'id'), FILTER_VALIDATE_INT);
    $akcja = pole($_POST, 'akcja');
    if ($id === false || $id < 1 || ! in_array($akcja, ['dodaj', 'usun'], true)) {
        http_response_code(422);
        exit('Nieprawidłowa operacja koszyka.');
    }
    $sprawdz = $polaczenie->prepare('SELECT id FROM Filmy WHERE id=?');
    $sprawdz->bind_param('i', $id);
    $sprawdz->execute();
    if (! $sprawdz->get_result()->fetch_assoc()) {
        http_response_code(404);
        exit('Brak filmu.');
    }
    if ($akcja === 'usun') {
        unset($_SESSION['koszyk'][$id]);
    } else {
        if (count($_SESSION['koszyk']) >= 20 && ! isset($_SESSION['koszyk'][$id])) {
            http_response_code(422);
            exit('Maksymalnie20 różnych filmów.');
        }
        $_SESSION['koszyk'][$id] = min(10, ($_SESSION['koszyk'][$id] ?? 0) + 1);
    }
    unset($_SESSION['zamowienie_klucz']);
    przekieruj('/koszyk.php');
}

Pobierz i odtwórz projekt

W „Źródłach i materiałach” na końcu pobierz KINO / LAB.zip. Rozpakuj całość; instrukcja START.txt opisuje konfigurację. Pierwsze 6 przykładów w public/podstawy działa bez bazy. Dalsze wymagają lokalnej MariaDB 11.4, importu schema.sql i lokalnego konta bazy z minimalnymi prawami. Gotowa paczka pokazuje całość, ale w tej lekcji wykonaj opisane kroki i własne zadanie.

Ćwiczenie z pomocą · samodzielna praca

Twoja próba — podpowiedzi otwieraj po kolei

Dodaj 2×Podróż i 1×Kosmos, usuń Kosmos, potem spróbuj nieistniejącego ID.

Oczekiwany rezultat
Najpierw 4197 groszy, potem 2598; błędny ID daje 404 i nie zmienia koszyka.
Potrzebujesz pomocy? Rozwiązuj krok po kroku.
Krok 1 — pokaż podpowiedź

Odszukaj wskazany plik i zapisz przewidywany rezultat przed zmianą.

Krok 2 — pokaż podpowiedź

Zmień jedną rzecz. Sprawdź metodę żądania, dane i odpowiedź lub wynik programu.

Krok 3 — pokaż podpowiedź

Wykonaj próbę graniczną lub błędną. Porównaj także stan bazy lub sesji, nie tylko komunikat.

Otwórz tylko tyle podpowiedzi, ile potrzebujesz. Po każdym kroku wróć do zadania i sprawdź wynik.

Podsumowanie

Co warto zapamiętać

  1. Zapiszesz ograniczony koszyk w sesji i obliczysz jego zawartość na podstawie rekordów bazy.
  2. Potrafisz wskazać w kodzie przyczynę wyniku i zaplanować próbę błędnych danych.
  3. Nie oddajesz haseł, pliku config.local.php ani wartości cookie.

Dalej na swoim koncie

Rozgrzewki, quiz i zadania są w biurku ucznia.

Teoria jest otwarta dla wszystkich. Żeby rozwiązywać zadania, zapisywać szkice i widzieć swój postęp, zaloguj się.

Zaloguj się →
Źródła i dalsza nauka