Lekce 5 - NERS - Registrace uživatelů v PHP
V minulé lekci, Programujeme neobjektový redakční systém v PHP (NERS), jsme začali pracovat na slíbeném redakčním systému.
Dnes si připravíme administraci a uděláme registraci uživatele.
Soubor registrace.php
Soubor registrace.php
a úplně nad HTML blok vložíme blok s
PHP obsluhou:
<?php session_start(); require('Db.php'); Db::connect('127.0.0.1', 'ners_db', 'root', ''); if ($_POST) { if ($_POST['rok'] != date('Y')) $zprava = 'Chybně vyplněný antispam.'; else if ($_POST['heslo'] != $_POST['heslo_znovu']) $zprava = 'Hesla nesouhlasí.'; else { $existuje = Db::querySingle(' SELECT COUNT(*) FROM uzivatele WHERE jmeno=? LIMIT 1 ', $_POST['jmeno']); if ($existuje) $zprava = 'Uživatel s touto přezdívkou již existuje.'; else { $heslo = password_hash($_POST['heslo'], PASSWORD_DEFAULT); Db::query(' INSERT INTO uzivatele (jmeno, heslo) VALUES (?, ?) ', $_POST['jmeno'], $heslo); $_SESSION['uzivatel_id'] = Db::getLastId(); $_SESSION['uzivatel_jmeno'] = $_POST['jmeno']; $_SESSION['uzivatel_admin'] = 0; header('Location: administrace.php'); exit(); } } } ?>
Jako první voláme funkci session_start()
. Funkce nám umožní
používat tzv. session (česky relace nebo někdy i sezení), která si
pamatuje data uživatele, se kterým komunikujeme. Tento řádek musí
být na úplném začátku PHP souboru (ne bloku, opravdu souboru), ve kterém
uživatelskou relaci používáme.
Před voláním session_start()
se nesmí nalézat
žádné HTML, ani prázdné řádky, ani mezery, jinak nebude fungovat. To
samé platí pro funkci header()
.
Dále načteme databázový wrapper (soubor Db.php
) a
připojíme se k databázi. Údaje jsou pro localhost, vy již víte, že na
produkci vám je sdělí webhosting. Pokud jste si údaje sami změnili, je
třeba je zde upravit.
Další kód je obsluha HTML formuláře. Pokud zadaný rok nesouhlasí s aktuálním, uložíme si chybovou zprávu. Jinak pokračujeme dále a stejným způsobem ověříme shodu obou zadaných hesel. Dostáváme se k samotné registraci.
Nejprve necháme databázi spočítat, kolik je v ní uživatelů se zadaným
jménem. Slouží k tomu SQL klauzule SELECT COUNT(*)
. Hvězdička
označuje, že do výpočtu zahrnujeme všechny sloupce. Abychom databázi
zbytečně nezatěžovali, dáme na počet položek ještě LIMIT 1
To znamená, že z databáze se vybere maximálně jeden řádek. Stačí nám,
když zjistíme, že je v databázi nějaký uživatel s tímto jménem a dále
se již databáze snažit nemusí. Dotaz zavoláme funkcí
Db::querySingle()
. Ta se používá v případě, když z databáze
čteme pouze jednu hodnotu jednoho řádku. My zde čteme pouze jedno číslo -
počet uživatelů s tímto jménem. Pokud jsme někoho našli, jméno je již
obsazené a uložíme si chybovou hlášku.
SQL kód pro vložení uživatele do databáze je velmi podobný tomu z
minulých lekcí. O něco složitější je zde ukládání hesla. Heslo
nevložíme do databáze přímo a to proto, kdyby došlo k úniku dat, aby
útočník nezískal hesla uživatelů. Použijeme tzv. hashovací funkci
password_hash()
, která z daného hesla vypočítá jeho otisk.
Nejbezpečnější způsob uchování hesla v databázi je totiž heslo vůbec
neuchovat, ale uchovat si pouze jeho hash. Hash je dlouhý řetězec zdánlivě
nesouvisejících znaků a číslic a nelze z něj původní heslo zjistit.
Hashovací funkce je tedy pouze jednosměrná. Když budeme chtít zjistit, zda
uživatel zadal správné heslo, jednoduše z něj znovu spočítáme otisk a
porovnáme, zda se otisky hesel shodují. K tomu následně slouží funkce
password_verify()
, jejíž použití uvidíte dále v kurzu.
Kromě výsledného hashe a otisku, je v návratové hodnotě
funkce uložena také informace o použitém algoritmu. To umožňuje v budoucnu
snadný přechod na nové a bezpečnější algoritmy. Na rozdíl od starších
PHP funkcí hash()
nebo crypt()
,
password_hash()
automaticky k heslu připojuje také tzv. salt. To
je náhodný řetězec znaků, kterým se heslo "přisolí", aby v databázi
nešly poznat často používaná hesla jako např. 123456
nebo
heslo1
a podobně.
Po vložení uživatele do databáze si vytvoříme uživatelskou relaci. V
PHP je podobně jako $_GET
nebo $_POST
také
superglobální pole $_SESSION
. Do tohoto pole si můžeme ukládat
data, které souvisí s tím uživatelem, se kterým právě komunikujeme.
Relace vyprší ve výchozím nastavení PHP za 24 minut nečinnosti nebo po
zavření prohlížeče. Jakmile ji jednou vytvoříme v nějakém skriptu,
zůstanou nám její data přístupná i pro ostatní PHP skripty v aplikaci. My
zde uživatele po registraci rovnou i přihlásíme a to tak, že do relace
uložíme jeho id, jméno a zda je administrátor. Id (primární klíč)
záznamu naposledy vloženého do databáze získáme pomocí funkce
Db::getLastId()
. Nakonec se přesměrujeme funkcí
header()
na stránku administrace.php
a skript
zastavíme. Pokud se něco nepodařilo, skript bude pokračovat a vypíše
chybovou hlášku.
Test chybové hlášky
Zkusme si udělat nějakou chybu, například vyplníme špatný rok:
A nyní se úspěšně zaregistrujme. Skript nás přenese na stránku
administrace.php
, která ještě neexistuje. Podívejme se v
phpMyAdmin do tabulky uzivatele
(otevřeme tabulku a vybereme z
menu nahoře tlačítko Projít). Vidíme zde nově vloženého
uživatele a otisk jeho hesla:
Jako heslo jsem zadal 123456
, výše vidíme otisk, co vrátila
funkce password_hash()
.
Administrace
Vytvořme si nyní skript administrace.php
. Bude to takový
rozcestník, na který aplikace uživatele přenese po zaregistrování nebo po
přihlášení. Jeho HTML část bude následující:
<!DOCTYPE html> <html lang="cs-cz"> <head> <meta charset="utf-8" /> <link rel="stylesheet" href="styl.css" type="text/css" /> <title>Administrace</title> </head> <body> <article> <header> <h1>Administrace</h1> </header> <section> <p>Vítejte v administraci, jste přihlášeni jako <?= htmlspecialchars($_SESSION['uzivatel_jmeno']) ?></p> <?php if (!$_SESSION['uzivatel_admin']) echo('Nemáte administrátorská oprávnění, požádejte administrátora webu, aby vám je přidělil.'); ?> <h3><a href="editor.php">Editor článků</a></h3> <h3><a href="clanky.php">Seznam článků</a></h3> <h3><a href="administrace.php?odhlasit">Odhlásit</a></h3> </section> </article> <footer> Vytvořil © HoBi 2023 pro <a href="https://itnetwork.cz">itnetwork.cz</a> </footer> </body> </html>
Kód obsahuje pouze 3 zajímavé věci:
- Vypisujeme zde jméno přihlášeného uživatele z relace (session).
- Pokud není přihlášený uživatel administrátor, informujeme ho o tom.
- Pro odhlášení uživatele odkážeme na skript
administrace.php
s parametrem GETodhlasit
.
Zase úplně na začátek souboru administrace.php
vložíme
jednoduchý PHP blok:
<?php session_start(); if (!isset($_SESSION['uzivatel_id'])) { header('Location: prihlaseni.php'); exit(); } if (isset($_GET['odhlasit'])) { session_destroy(); header('Location: prihlaseni.php'); exit(); } ?>
Výsledek:
Pokud session neexistuje, přesměrujeme na přihlašovací stránku a
zastavíme skript. Pokud je zadaný parametr GET odhlasit
,
zničíme session pomocí PHP funkce session_destroy()
a opět
přesměrujeme na přihlášení.
V další lekci, NERS - Editor článků v PHP, využijeme editor TinyMCE pro editaci článků.