INF.03 · Aplikacje internetowe PHP

Rejestracja użytkownika (formularz, baza danych, hasło)

Rejestracja bez zapisywania hasła.

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

Po tej lekcji: Utworzysz konto z unikalnym emailem i hashem hasła, rozumiejąc rolę walidacji oraz ograniczenia UNIQUE.

Zrozum mechanizm

Formularz wysyła email, hasło i powtórzenie przez POST. Serwer kontroluje CSRF, kształt danych, format emaila i politykę hasła. W tym projekcie email jest normalizowany do małych liter. Hasła nie przycinamy ani nie zmieniamy. Polityka ćwiczenia: co najmniej 15 znaków i maksymalnie 72 bajty UTF-8 — to świadome ograniczenie zgodności z bcrypt, nie limit 72 liter.

Password_hash z PASSWORD_DEFAULT generuje hash z losową solą; nie dopisuj własnej soli, nie używaj md 5 ani sha 256 jako zamiennika funkcji do haseł. Ten sam tekst zwykle daje różne hashe. Przechowuj wynik w VARCHAR(255), ponieważ domyślny algorytm może się zmienić. Hasła nie szyfrujemy do późniejszego odczytania.

INSERT jest parametryzowany. UNIQUE(email) rozstrzyga również wyścig dwóch rejestracji — wcześniejszy SELECT sam nie gwarantuje unikalności. Błąd 1062 obsługujemy bez wycieku SQL; odpowiedź nie rozróżnia jawnie istnienia adresu. Rejestracja w tym projekcie nie loguje automatycznie. Dodatkowe elementy publicznej aplikacji, np. potwierdzenie email i odzyskiwanie konta, są osobnym wdrożeniem.

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.

Hasło: hash do zapisu, tekst tylko do sprawdzenia

Najpierw zobacz samą operację. To nie jest jeszcze rejestracja: cały formularz, walidacja, CSRF i INSERT są w pełnym pliku niżej.

Podstawowa forma: password_hash(haslo, PASSWORD_DEFAULT) → napis do bazy

hash.phpphp
<?php
$haslo = 'Fikcyjne haslo ucznia 2026';
$hash = password_hash($haslo, PASSWORD_DEFAULT);
echo password_verify($haslo, $hash) ? 'zgodne' : 'błędne';
Wynik
zgodne
  1. password_hash bierze tekst hasła i nazwę algorytmu. PASSWORD_DEFAULT to stała PHP wybierająca domyślny algorytm, nie nazwa hasła.
  2. Funkcja tworzy napis zawierający informacje potrzebne do późniejszej weryfikacji. Ten napis zapisujesz do kolumny haslo_hash typu VARCHAR(255).
  3. password_verify bierze wpisane hasło i zapisany hash, zwraca bool. W przykładzie ?: zamienia true na napis zgodne.
  4. Losowa sól jest generowana automatycznie. Dwa wywołania hash dla tego samego tekstu mogą dać różne napisy; dlatego nie porównujemy nowego hasha ze starym operatorem ===.

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();
tokenFormularza()Nasza funkcja zwraca HTML ukrytego pola csrf z wartością sesji zakodowaną przez h.<?= tokenFormularza() ?>
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");
naglowek($tytul), stopka()Nasze funkcje wypisujące wspólny HTML strony. void oznacza brak zwracanego wyniku do użycia w wyrażeniu.naglowek("Katalog");
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"
try / catch / throwtry obejmuje próbę, catch przechwytuje wyjątek, throw go zgłasza; $blad jest obiektem błędu. W mysqli raportowanie wyjątków trzeba włączyć.try { /* operacja */ } catch (Throwable $blad) { /* obsługa */ }
===, !==, &&, ||, !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

Rejestracja bez zapisywania hasła — 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

Załóż dwa fikcyjne konta z różnymi hasłami. Sprawdź niezgodne powtórzenie, błędny email, za krótkie hasło i powtórzony adres. W phpMyAdmin obejrzyj haslo_hash: nigdy jawne hasło. Nie oddawaj nauczycielowi użytego hasła, wartości cookie ani config.local.php. Do pracy dołącz opis testów i kod bez sekretów.

Plik wzorcowy: public/rejestracja.php

public/rejestracja.phpphp
<?php
require_once dirname(__DIR__).'/src/db.php';
$komunikat = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    wymagajPost();
    $email = mb_strtolower(trim(pole($_POST, 'email')));
    $haslo = pole($_POST, 'haslo'); // Nie usuwaj spacji z hasła.
    $powtorz = pole($_POST, 'powtorz');
    if (strlen($email) > 254 || ! filter_var($email, FILTER_VALIDATE_EMAIL)
        || mb_strlen($haslo) < 15 || strlen($haslo) > 72 || $haslo !== $powtorz) {
        http_response_code(422);
        $komunikat = 'Sprawdź email oraz zgodność haseł: minimum 15 znaków i maksymalnie 72 bajty UTF-8.';
    } else {
        // PASSWORD_DEFAULT może zmienić algorytm. Kolumna ma zapas: VARCHAR(255).
        $hash = password_hash($haslo, PASSWORD_DEFAULT);
        $zapytanie = $polaczenie->prepare('INSERT INTO Uzytkownicy (email, haslo_hash) VALUES (?, ?)');
        $zapytanie->bind_param('ss', $email, $hash);
        try {
            $zapytanie->execute();
        } catch (mysqli_sql_exception $blad) {
            // UNIQUE rozstrzyga również dwa równoczesne zgłoszenia.
            if ($blad->getCode() !== 1062) {
                throw $blad;
            }
        }
        // Nie zdradzamy w odpowiedzi, czy adres był już zajęty.
        przekieruj('/logowanie.php?rejestracja=1');
    }
}
naglowek('Załóż konto do ćwiczeń');
?>
<p><?= h($komunikat) ?></p>
<form method="post" action="/rejestracja.php">
    <?= tokenFormularza() ?>
    <label for="email">Email fikcyjny</label><input id="email" name="email" type="email" maxlength="254" autocomplete="username" required>
    <label for="haslo">Hasło: min. 15 znaków, maks. 72 bajty UTF-8</label><input id="haslo" name="haslo" type="password" autocomplete="new-password" required>
    <label for="powtorz">Powtórz hasło</label><input id="powtorz" name="powtorz" type="password" autocomplete="new-password" required>
    <button>Utwórz konto</button>
</form>
<?php stopka();

Co ma trafić do bazy?

W kolumnie haslo_hash znajduje się wynik password_hash, a nie oryginalny tekst. Dwa hashe tego samego hasła mogą być różne z powodu losowej soli. To poprawne. Password_verify odczytuje informacje z hasha i sprawdza hasło. Nigdy nie wypisuj hasła w odpowiedzi, logu, raporcie ani w SQL do oddania.

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

Wykonaj pięć prób rejestracji: poprawna, niepoprawny email, różne hasła, za krótkie hasło i duplikat.

Oczekiwany rezultat
Powstaje tylko jedno poprawne nowe konto; baza przechowuje hash; brak błędu 500 i surowego SQL.
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. Utworzysz konto z unikalnym emailem i hashem hasła, rozumiejąc rolę walidacji oraz ograniczenia UNIQUE.
  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