Przejdź do treści

Logowanie użytkowników i ochrona podstron

  • Użytkownicy i logowanie
  • poziom: średni
  • aktualizacja: 12 lipca 2026

Ten skrypt uzupełnia rejestrację o logowanie oparte na sesjach. Zawiera wszystko, co niezbędne: weryfikację hasła, zabezpieczenie przed przejęciem sesji (odnowienie jej identyfikatora po zalogowaniu), spowolnienie ataków siłowych, wylogowanie i gotową funkcję do ochrony dowolnej podstrony.

PHP 136 linii Pobierz .php
<?php
/**
 * Logowanie użytkowników — skryptyPHP.com
 * Zapisz jako: logowanie.php
 * Wymaga tabeli `uzytkownicy` ze skryptu „Rejestracja użytkowników".
 */

session_start();
require 'baza.php'; // skrypt „Połączenie z bazą (PDO)"

// ── FUNKCJE — możesz je przenieść do wspólnego pliku auth.php ──

function czy_zalogowany(): bool
{
    return isset($_SESSION['uzytkownik_id']);
}

/**
 * Wstaw na początku każdej chronionej podstrony:
 *     require 'auth.php';
 *     wymagaj_logowania();
 */
function wymagaj_logowania(): void
{
    if (!czy_zalogowany()) {
        header('Location: logowanie.php');
        exit;
    }
}

function wyloguj(): void
{
    $_SESSION = [];
    if (ini_get('session.use_cookies')) {
        $p = session_get_cookie_params();
        setcookie(session_name(), '', time() - 3600,
            $p['path'], $p['domain'], $p['secure'], $p['httponly']);
    }
    session_destroy();
}

// ── WYLOGOWANIE ─────────────────────────────────────────────
if (($_GET['akcja'] ?? '') === 'wyloguj') {
    wyloguj();
    header('Location: logowanie.php');
    exit;
}

// ── LOGOWANIE ───────────────────────────────────────────────
$blad = '';

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $email = mb_strtolower(trim($_POST['email'] ?? ''));
    $haslo = $_POST['haslo'] ?? '';

    // Hamulec dla ataków siłowych: rosnące opóźnienie po błędnych próbach
    $proby = $_SESSION['nieudane_proby'] ?? 0;
    if ($proby > 2) {
        sleep(min($proby - 2, 5));
    }

    $pdo  = polacz_z_baza();
    $stmt = $pdo->prepare(
        'SELECT id, imie, haslo_hash FROM uzytkownicy WHERE email = ?'
    );
    $stmt->execute([$email]);
    $uzytkownik = $stmt->fetch();

    if ($uzytkownik && password_verify($haslo, $uzytkownik['haslo_hash'])) {

        // Nowy identyfikator sesji — ochrona przed tzw. session fixation
        session_regenerate_id(true);

        $_SESSION['uzytkownik_id']   = (int) $uzytkownik['id'];
        $_SESSION['uzytkownik_imie'] = $uzytkownik['imie'];
        unset($_SESSION['nieudane_proby']);

        // Okazja do bezkosztowego wzmocnienia starych haszy
        if (password_needs_rehash($uzytkownik['haslo_hash'], PASSWORD_DEFAULT)) {
            $nowy = password_hash($haslo, PASSWORD_DEFAULT);
            $pdo->prepare('UPDATE uzytkownicy SET haslo_hash = ? WHERE id = ?')
                ->execute([$nowy, $uzytkownik['id']]);
        }

        header('Location: panel.php'); // dokąd po zalogowaniu
        exit;
    }

    $_SESSION['nieudane_proby'] = $proby + 1;
    // Jeden komunikat dla obu przypadków — nie zdradzamy, czy konto istnieje
    $blad = 'Nieprawidłowy e-mail lub hasło.';
}
?>
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Logowanie</title>
<style>
    .formularz { max-width: 380px; font-family: sans-serif; margin: 20px auto; }
    .formularz label { display: block; margin: 12px 0 4px; font-weight: bold; }
    .formularz input { width: 100%; padding: 8px; box-sizing: border-box; }
    .formularz button { margin-top: 16px; padding: 10px 24px; cursor: pointer; }
    .blad { color: #b00020; }
</style>
</head>
<body>

<form class="formularz" method="post" action="">
    <h2>Zaloguj się</h2>

    <?php if (czy_zalogowany()): ?>
        <p>Jesteś już zalogowany jako
            <strong><?= htmlspecialchars($_SESSION['uzytkownik_imie']) ?></strong>.
            <a href="?akcja=wyloguj">Wyloguj się</a></p>
    <?php endif; ?>

    <?php if ($blad): ?>
        <p class="blad"><?= htmlspecialchars($blad) ?></p>
    <?php endif; ?>

    <label for="email">E-mail</label>
    <input type="email" id="email" name="email" required>

    <label for="haslo">Hasło</label>
    <input type="password" id="haslo" name="haslo" required
           autocomplete="current-password">

    <button type="submit">Zaloguj się</button>

    <p><a href="rejestracja.php">Nie masz konta? Zarejestruj się</a></p>
</form>

</body>
</html>

Jak użyć tego skryptu

  1. Skorzystaj najpierw ze skryptu „Rejestracja użytkowników" — logowanie używa tej samej tabeli uzytkownicy.
  2. Zapisz kod jako logowanie.php i zmień w nim adres przekierowania po zalogowaniu (panel.php).
  3. Aby zabezpieczyć podstronę, przenieś funkcje do pliku auth.php i na początku chronionej strony wywołaj session_start(), require 'auth.php' oraz wymagaj_logowania();.
  4. Link wylogowania: logowanie.php?akcja=wyloguj.

Warto wiedzieć

  • password_verify() porównuje hasło z haszem w stałym czasie — nie porównuj haszy operatorem ==.
  • session_regenerate_id(true) po zalogowaniu to ważny detal — unieważnia identyfikator sesji sprzed logowania.
  • Komunikat błędu celowo nie mówi, czy istnieje konto z podanym e-mailem — to utrudnia zgadywanie loginów.
  • Na stronie z HTTPS (dziś standard) dodaj w PHP ini_set('session.cookie_secure', '1') oraz session.cookie_httponly = 1, aby ciasteczko sesyjne nie wyciekło.
#logowanie #sesje #password_verify #auth #bezpieczeństwo

Podobne skrypty