Procvič si angličtinu zdarma s naším americkým e-learningem! Learn more
Pouze tento týden sleva až 80 % na celý Java e-learning!

Lekce 5 - NERS - Registrace uživatelů v PHP

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Programujeme neobjektový redakční systém v PHP (NERS), jsme si připravili projekt NERS - NEobjektový Redakční Systém v PHP a rozpracovali jsme skript registrace.php.

Nyní 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 je již v databázi obsažen.';
                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 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 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 Db wrapper 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.

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ě zatěžovali, dáme na počet položek ještě LIMIT 1. 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, 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.

Zkusme si udělat nějakou chybu:

Registrace uživatele do systému v PHP

A nyní se úspěšně zaregistrujte. Skript vás přenese na stránku administrace.php, která ještě neexistuje. Podívejte se v phpMyAdmin do tabulky uzivatele (otevřete tabulku a vyberte z menu nahoře Projít). Vidíme zde nově vloženého uživatele a otisk jeho hesla:

Uložení hesla do MySQL databáze v PHP

Jako heslo jsem zadal "admin", výše vidíte 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 HMTL čá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>
        <div id="centrovac">
                <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.');
                        ?>
                        <h2><a href="editor.php">Editor článků</a></h2>
                        <h2><a href="clanky.php">Seznam článků</a></h2>
                        <h2><a href="administrace.php?odhlasit">Odhlásit</a></h2>
                </section>
                <div class="cistic"></div>
        </div>
</article>
</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 GET parametrem odhlasit.

Nad kód 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:

Administrace článků v PHP

Pokud session neexistuje, přesměrujeme na přihlašovací stránku a zastavíme skript. Pokud je zadaný parametr odhlasit, zničíme session pomocí PHP funkce session_destroy() a opět přesměrujeme na přihlášení.

Budeme pokračovat v příští lekci, NERS - Editor článků v PHP.


 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
34 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
Programujeme neobjektový redakční systém v PHP (NERS)
Všechny články v sekci
Databáze v PHP pro začátečníky
Miniatura
Následující článek
NERS - Editor článků v PHP
Aktivity (5)

 

 

Komentáře
Zobrazit starší komentáře (117)

Avatar
Jaroslav Smrž
Redaktor
Avatar
Jaroslav Smrž:4. dubna 9:22

Tady na první pohled nic nevidím, ale vzhledem k té chybě máš možná někde místo uzivatele_id - uzivatel_id. Zkus tedy všude (včetně databáze), kde je uzivatele_id změnit na uzivatel_id, pak by mělo vše fungovat.

Odpovědět 4. dubna 9:22
I have no idea what it is doing but I´m scared to delete it... xD
Avatar
Tomáš Novotný:4. dubna 9:24

ahoj.. s velkou pravděpodobností máš v DB sloupec 'uzivatel_id' a v SQL dotazu SELECT 'uzivatele_id'
při registraci a přihlášení ho totiž explicitně nepoužíváš (využíváš metody getLastId) - tj. funguje, ale při samostatném přihlášení už ano - tj. nefunguje

Editováno 4. dubna 9:25
Odpovědět 4. dubna 9:24
∞ ... the exact amount of possibilities how to deal with the situation ... so by calm, your solution is one of many
Avatar
Bugy
Člen
Avatar
Bugy:4. dubna 9:29

Zde odkaz na screen databaze screen
Zkusím tedy ještě ty přepisy...

 
Odpovědět 4. dubna 9:29
Avatar
Odpovídá na Bugy
Tomáš Novotný:4. dubna 9:36

Tak třeba je problém dále v souboru administrace.php.. možná máš v nějakém selectu špatně FROM... chyba prostě říká, že v dané tabulce tento sloupec není..

Editováno 4. dubna 9:37
Odpovědět 4. dubna 9:36
∞ ... the exact amount of possibilities how to deal with the situation ... so by calm, your solution is one of many
Avatar
Bugy
Člen
Avatar
Odpovídá na Tomáš Novotný
Bugy:4. dubna 9:39

administrace.php vypada takto:

<?php
session_start();
if (!isset($_SESSION['uzivatel_id']))
{
        header('Location: prihlaseni.php');
        exit();
}

if (isset($_GET['odhlasit']))
{
        session_destroy();
        header('Location: prihlaseni.php');
        exit();
}
?>

<!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>
        <div id="centrovac">
                <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.');
                        ?>
                        <h2><a href="editor.php">Editor článků</a></h2>
                        <h2><a href="clanky.php">Seznam článků</a></h2>
                        <h2><a href="administrace.php?odhlasit">Odhlásit</a></h2>
                </section>
                <div class="cistic"></div>
        </div>
</article>
</body>
</html>
 
Odpovědět 4. dubna 9:39
Avatar
Odpovídá na Bugy
Tomáš Novotný:4. dubna 9:44

Tak tu také nic... tak dej ještě export aaa databáze do sql...

Odpovědět 4. dubna 9:44
∞ ... the exact amount of possibilities how to deal with the situation ... so by calm, your solution is one of many
Avatar
Bugy
Člen
Avatar
Odpovídá na Tomáš Novotný
Bugy:4. dubna 9:55

Zde sql:

-- phpMyAdmin SQL Dump
-- version 4.8.5
-- https://www.phpmyadmin.net/
--
-- Vytvořeno: Čtv 04. dub 2019, 09:51
-- Verze serveru: 5.5.62-0+deb8u1-log
-- Verze PHP: 5.6.40-0+deb8u2

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";


/*!40101 SET @[email protected]@CHARACTER_SET_CLIENT */;
/*!40101 SET @[email protected]@CHARACTER_SET_RESULTS */;
/*!40101 SET @[email protected]@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Databáze: `aaa`
--

-- --------------------------------------------------------

--
-- Struktura tabulky `clanky`
--

CREATE TABLE `clanky` (
  `clanky_id` int(11) NOT NULL,
  `titulek` varchar(255) NOT NULL,
  `obsah` text NOT NULL,
  `url` varchar(255) NOT NULL,
  `popisek` varchar(255) NOT NULL,
  `klicova_slova` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- --------------------------------------------------------

--
-- Struktura tabulky `uzivatele`
--

CREATE TABLE `uzivatele` (
  `id_uzivatele` int(11) NOT NULL,
  `jmeno` varchar(255) NOT NULL,
  `heslo` varchar(255) NOT NULL,
  `admin` int(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Vypisuji data pro tabulku `uzivatele`
--

INSERT INTO `uzivatele` (`id_uzivatele`, `jmeno`, `heslo`, `admin`) VALUES
(0, 'admin', '$2y$10$hCUgpLrX267Vbva2dGAKu.2AMJ1NTnouRM6OTVBPRwnt3eJ4uFydq', 1);
COMMIT;

/*!40101 SET [email protected]_CHARACTER_SET_CLIENT */;
/*!40101 SET [email protected]_CHARACTER_SET_RESULTS */;
/*!40101 SET [email protected]_COLLATION_CONNECTION */;
 
Odpovědět 4. dubna 9:55
Avatar
Odpovídá na Bugy
Tomáš Novotný:4. dubna 9:58

No už je to jasné ;-) sloupec id_uzivatele a v dotazech máš 'SELECT uzivatele_id, admin, heslo'
ono už to bylo vidět i z toho obrázku... ale nevšiml jsem si

Editováno 4. dubna 10:00
Odpovědět  +1 4. dubna 9:58
∞ ... the exact amount of possibilities how to deal with the situation ... so by calm, your solution is one of many
Avatar
Bugy
Člen
Avatar
Odpovídá na Tomáš Novotný
Bugy:4. dubna 10:06

Moc díky ...taková blbinka a tolik nervů :-D Už to funguje :-)

 
Odpovědět  +1 4. dubna 10:06
Avatar
Jaroslav Smrž
Redaktor
Avatar
Odpovídá na Bugy
Jaroslav Smrž:4. dubna 10:40

Přesně, jak jsem ti psal hned v 1. odpověďi:

Chyba není v db.php, ale ve zpracování dotazu. Máš buď špatně pojmenovaný sloupec v databázi nebo input ve formu. Někde budeš mít pravděpodobně jen překlep v uzivatele_id.

Odpovědět  +1 4. dubna 10:40
I have no idea what it is doing but I´m scared to delete it... xD
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 127. Zobrazit vše