INF.03 · Aplikacje internetowe PHP

Logowanie i wylogowanie użytkownika

Logowanie ustanawia sesję; wylogowanie ją kończy.

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

Po tej lekcji: Sprawdzisz hasło przez password_verify, zmienisz ID sesji po sukcesie i zakończysz sesję przez POST.

Zrozum mechanizm

Logowanie najpierw wyszukuje konto po emailu przez prepared statement, a następnie password_verify porównuje wpisane hasło z hashem. Nie generuj nowego hasha i nie porównuj go tekstowo z poprzednim. Dla braku konta i złego hasła pokazuj ten sam komunikat; porównanie z przykładowym hashem również przy braku konta ogranicza oczywiste różnice pracy kodu, ale nie jest gwarancją identycznego czasu.

Po sukcesie session_regenerate_id(true) zmienia identyfikator. W sesji zapisujemy ID użytkownika, email i czasy, a nie hasło. Token CSRF też jest odnawiany. Password_needs_rehash pozwala zaktualizować hash po poprawnym logowaniu. Trwały licznik w bazie ogranicza próby z danego IP do 5 na 15 min i nie znika po usunięciu cookie. To prosty model: wspólne IP pracowni współdzieli limit. Publiczne systemy wymagają dokładniejszej ochrony per konto/IP i uwzględnienia zaufanego proxy.

Wylogowanie przyjmuje POST z CSRF, czyści $_SESSION, wygasza cookie z tą samą ścieżką i usuwa stan serwerowy przez session_destroy. Po przekierowaniu ponowne wejście w panel ma znów wymagać logowania. Sam link lub ukrycie panelu w menu nie wystarczy.

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.

Logowanie: wyszukaj konto, sprawdź hasło, odnow sesję

Użytkownik wpisuje hasło, a z bazy odczytujesz hash konta znalezionego po emailu. Ten wycinek opisuje etap po walidacji danych i kontroli liczby prób; uruchamiaj cały projekt, nie sam fragment.

Podstawowa forma: password_verify(wpisane_haslo, hash_z_bazy) → true lub false

login.phpphp
<?php
// Fragment poprawnie obsłużonego POST; konto pochodzi z SELECT:
if ($konto && password_verify($haslo, $konto['haslo_hash'])) {
    session_regenerate_id(true);
    $_SESSION['user_id'] = (int) $konto['id'];
    $_SESSION['email'] = $konto['email'];
}
  1. $konto && ... najpierw sprawdza, czy odczytano konto; && nie wykonuje drugiej części, gdy pierwsza jest fałszywa.
  2. Po poprawnej weryfikacji session_regenerate_id(true) tworzy nowe ID sesji i usuwa stare dane sesji spod starego ID; chroni przed utrwaleniem narzuconego identyfikatora.
  3. W sesji zapisujesz identyfikator konta i potrzebne dane, nigdy jawne hasło. Projekt dodatkowo zapisuje czasy, odświeża CSRF i sprawdza password_needs_rehash.
  4. password_needs_rehash(hash, PASSWORD_DEFAULT) mówi, czy po poprawnej weryfikacji warto zapisać hash z aktualnymi parametrami. Nie zmienia hasła użytkownika.

Wylogowanie: trzy czynności, nie jedno polecenie

Usunięcie klucza user_id nie jest pełnym wylogowaniem. Najpierw sprawdzamy POST i token formularza, potem czyścimy dane oraz identyfikator.

Podstawowa forma: $_SESSION = []; + wygaśnięcie cookie + session_destroy();

logout.phpphp
<?php
// Skrót kolejności; pełne opcje cookie są w wyloguj.php:
wymagajPost();
$_SESSION = [];
$opcje = session_get_cookie_params();
setcookie(session_name(), '', [
    'expires' => time() - 3600,
    'path' => $opcje['path'],
    'domain' => $opcje['domain'],
    'secure' => $opcje['secure'],
    'httponly' => $opcje['httponly'],
    'samesite' => $opcje['samesite'] ?? 'Lax',
]);
session_destroy();
  1. Pusta tablica usuwa dane z bieżącego $_SESSION. session_get_cookie_params odczytuje opcje cookie sesji.
  2. setcookie wysyła nagłówek cookie: ta sama nazwa i ścieżka, pusty tekst, termin expires w przeszłości. time() zwraca aktualny czas w sekundach.
  3. session_destroy usuwa zapis sesji na serwerze. Po tych operacjach pełny plik przekierowuje na logowanie i kończy wykonanie.
  4. Po wylogowaniu wpisz adres panelu ręcznie. Serwer ma odmówić dostępu; samo zniknięcie przycisku nie dowodzi wylogowania.

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")
h($tekst)Nasza funkcja kodująca tekst/atrybut HTML przez htmlspecialchars; nie wykonuje walidacji zakresu ani zabezpieczenia SQL.h($film["tytul"])
wymagajPost()Nasza funkcja: sprawdza metodę POST oraz CSRF; przy błędzie przerywa odpowiedź z405/403.wymagajPost();
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"] ??= [];
-> oraz ::-> wybiera właściwość lub metodę obiektu; :: odnosi się do elementu statycznego klasy. To nie jest zapis dostępu do tablicy.$zapytanie->execute();
bin2hex(random_bytes(32))Najpierw losujemy32 bajty bezpiecznym generatorem, potem zamieniamy je na64 znaki HEX. Token musi być generowany, nie zapisany na stałe.$_SESSION["csrf"] = bin2hex(random_bytes(32));

Sprawdź w działaniu

Logowanie ustanawia sesję; wylogowanie ją kończy — 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

Otwórz pełny plik logowanie.php w paczce. Prześledź: limit→SELECT→password_verify→zmiana ID→zapis sesji→303. Spróbuj złego hasła, nieistniejącego emaila i poprawnego kompletu. Następnie wyloguj przez formularz i otwórz panel bezpośrednio. Próby limitu wykonaj na końcu, aby nie blokować własnych kolejnych testów.

Logowanie: odczyt, weryfikacja i ustanowienie sesji

Fragment wewnątrz pełnego logowanie.php. Wcześniejsza część pliku sprawdza POST, token CSRF i trwały limit prób. Cały plik oraz formularz są w paczce.

public/logowanie.phpphp
        $email = mb_strtolower(trim(pole($_POST, 'email')));
        $haslo = pole($_POST, 'haslo');
        $zapytanie = $polaczenie->prepare('SELECT id, email, haslo_hash FROM Uzytkownicy WHERE email=?');
        $zapytanie->bind_param('s', $email);
        $zapytanie->execute();
        $osoba = $zapytanie->get_result()->fetch_assoc();
        // Stały przykładowy hash do porównania również przy nieistniejącym emailu.
        $hashPozorny = '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2uheWG/igi.';
        $poprawne = password_verify($haslo, $osoba['haslo_hash'] ?? $hashPozorny);
        if ($osoba && $poprawne && strlen($haslo) <= 72) {
            session_regenerate_id(true);
            $_SESSION['user_id'] = (int) $osoba['id'];
            $_SESSION['email'] = $osoba['email'];
            $_SESSION['zalogowano'] = $_SESSION['ostatnia_aktywnosc'] = time();
            $_SESSION['csrf'] = bin2hex(random_bytes(32));
            if (password_needs_rehash($osoba['haslo_hash'], PASSWORD_DEFAULT)) {
                $nowyHash = password_hash($haslo, PASSWORD_DEFAULT);
                $zmiana = $polaczenie->prepare('UPDATE Uzytkownicy SET haslo_hash=? WHERE id=?');
                $zmiana->bind_param('si', $nowyHash, $_SESSION['user_id']);
                $zmiana->execute();
            }
            $reset = $polaczenie->prepare('DELETE FROM ProbyLogowania WHERE klucz=?');
            $reset->bind_param('s', $klucz);
            $reset->execute();
            przekieruj('/panel.php');
        }
        http_response_code(401);
        $komunikat = 'Nieprawidłowy email lub hasło.';
    }
}

Wylogowanie: dane, cookie i sesja

public/wyloguj.phpphp
<?php

require_once dirname(__DIR__).'/src/bootstrap.php';
wymagajPost();
$_SESSION = [];
$parametry = session_get_cookie_params();
setcookie(session_name(), '', [
    'expires' => time() - 3600, 'path' => $parametry['path'],
    'secure' => $parametry['secure'], 'httponly' => true, 'samesite' => 'Lax',
]);
session_destroy();
przekieruj('/logowanie.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

Sprawdź cały cykl: gość→błędne logowanie→poprawne logowanie→panel→wylogowanie→panel.

Oczekiwany rezultat
Niepoprawne dane nie otwierają panelu; po sukcesie ID sesji się zmienia; po wylogowaniu panel znów przekierowuje.
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. Sprawdzisz hasło przez password_verify, zmienisz ID sesji po sukcesie i zakończysz sesję przez POST.
  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