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
<?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'];
}
-
$konto && ...najpierw sprawdza, czy odczytano konto; && nie wykonuje drugiej części, gdy pierwsza jest fałszywa. - Po poprawnej weryfikacji session_regenerate_id(true) tworzy nowe ID sesji i usuwa stare dane sesji spod starego ID; chroni przed utrwaleniem narzuconego identyfikatora.
- 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.
- 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();
<?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();
- Pusta tablica usuwa dane z bieżącego $_SESSION. session_get_cookie_params odczytuje opcje cookie sesji.
- 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.
- session_destroy usuwa zapis sesji na serwerze. Po tych operacjach pełny plik przekierowuje na logowanie i kończy wykonanie.
- 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
| Zapis | Znaczenie | Przykł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 $_POST | Specjalne 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.
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.
$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
<?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.
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ć
- Sprawdzisz hasło przez password_verify, zmienisz ID sesji po sukcesie i zakończysz sesję przez POST.
- Potrafisz wskazać w kodzie przyczynę wyniku i zaplanować próbę błędnych danych.
- 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ę →