5. díl - NERS - Registrace uživatelů v PHP

PHP Databáze pro začátečníky NERS - Registrace uživatelů v PHP American English version English version

ONEbit hosting 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ém dílu našeho seriálu tutoriálů o databázích v PHP pro úplné začátečníky 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
                {
                        Db::query('
                                INSERT INTO uzivatele (jmeno, heslo)
                                VALUES (?, SHA1(?))
                        ', $_POST['jmeno'], $_POST['heslo'] . "t&#ssdf54gh");
                        $_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. Nejprve heslo uživatele vylepšíme a to přidáním tzv. soli (salt). To je úplně náhodný řetězec znaků, který se k heslu připojí kvůli bezpečnosti, nějaký si vymyslete. Uživatelé totiž rádi zadávají např. "heslo", "password", "123456" a podobně. Takto zadaná hesla jsou velmi nebezpečná a lze je jednoduše odhadnout. Po "osolení" z nich vznikne: "heslot&#ssdf54gh", "passwordt&#ssdf54gh­", "123456t&#ssd­f54gh", což prakticky znemožní zpětné uhodnutí onoho hesla. Osolené heslo nevložíme do databáze přímo a to proto, že databázi nám může někdo ukradnout a potom by viděl všechna hesla všech uživatelů.

Heslo uložíme pomocí SQL funkce SHA1(). To je tzv. hashovací funkce, která z daného hesla vypočítá otisk. Nejbezpečnější způsob uchování hesla v databázi je totiž heslo vůbec neuchovat, ale uchovat si pouze jeho otisk. Otisk 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 ze zadaného hesla vypočítáme otisk stejným způsobem a tento otisk porovnáme s uloženým otiskem v databázi. To vše uvidíte až budeme programovat přihlašování.

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 SHA1().

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í.

Příště budeme pokračovat.


 

  Aktivity (1)

Článek pro vás napsal David Čápka
Avatar
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 se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (14 hlasů) :
55555


 



 

 

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

Avatar
Tomáš Huczala:

Problém vyřešen... Odinstaloval jsem XAMPP (7.0.1 (VC14) a nainstaloval jsem znova v jiné verzi (5.6.24.VC11)..
Díky za Váš čas... :-)

 
Odpovědět 7.11.2016 14:48
Avatar
IT Man
Redaktor
Avatar
Odpovídá na Tomáš Huczala
IT Man:

Není zač, hlavně, že se to vyřešilo :)

Odpovědět  +1 7.11.2016 15:15
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
tomgerzicak
Člen
Avatar
tomgerzicak:

Čau, mám takový problém, vždycky, když se zkouším přihlásit se mi vypíší tyto chyba, nemáte s tím někdo zkušenosti, děkuji.
Chyby:
Warning: PDO::prepare(): SQLSTATE[42S22]: Column not found: 1054 Champ 'jmeno' inconnu dans where clause in C:\wamp\www\re­dakcak\Db.php on line 60

Fatal error: Call to a member function execute() on a non-object in C:\wamp\www\re­dakcak\Db.php on line 61

tady je můj zdroják, ale myslím, že bude spíš problém v Db :/

<?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
                {
                        Db::query('
                                INSERT INTO uzivatele (jmeno, heslo)
                                VALUES (?, SHA1(?))
                        ',$_POST['jmeno'], $_POST['heslo'] . "t&#ssdf54gh");
                        $_SESSION['uzivatel_id'] = Db::getLastId();
                        $_SESSION['uzivatel_jmeno'] = $_POST['jmeno'];
                        $_SESSION['uzivatel_admin'] = 0;
                        header('Location: administrace.php');
                        exit();
                }
        }
}
?>


<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Registrace</title>
</head>

<body>
<form method="post">

        <?php if(isset($zprava)){ echo("<p>".$zprava."</p>");} ?>
        <p>Jméno: <input type="text" name="jmeno"></p>
        <p>Heslo: <input type="text" name="heslo"></p>
        <p>Heslo znovu: <input type="text" name="heslo_znovu"></p>
        <p>Aktuální rok: <input type="text" name="rok"></p>
        <input type="submit" value="Registrovat">
</form>
</body>
</html>
Editováno 11. ledna 1:22
 
Odpovědět 11. ledna 1:19
Avatar
IT Man
Redaktor
Avatar
Odpovídá na tomgerzicak
IT Man:

Vždyť tohle je registrace, ne přihlášení. o_O
Jinak jsi si jistý, že máš v databázi sloupec jmeno?

Odpovědět 11. ledna 6:32
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
tomgerzicak
Člen
Avatar
Odpovídá na IT Man
tomgerzicak:

Jo, promiň, už bylo celkem pozdě a seděl jsem nad tím už hodně dlouho, sloupec jméno tam mám, právě, když jsem si stáhl i tu závěrečnou verzi z poslední lekce a ukazuje to uplně stejnou chybu.

 
Odpovědět 11. ledna 7:57
Avatar
IT Man
Redaktor
Avatar
Odpovídá na tomgerzicak
IT Man:

Pokud je tedy přiložený kód registrace a máš problém s přihlášením, hodil by se zdrojový kód přihlášení. Stačí ten kód nahrát např. pomocí zdejšího Dev-Lighteru a odpovědět mi na tento komentář jenom odkazem na zdrojový kód. :)

Odpovědět 11. ledna 15:37
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
tomgerzicak
Člen
Avatar
Odpovídá na IT Man
tomgerzicak:

Tak se omlouvám, problém jsem vyřešil, jsem totiž **** , byla chyba v databázi, místo sloupečku 'jmeno' jsem měl 'jméno' a pak to házelo chyby. Děkuji za pomoc

 
Odpovědět 11. ledna 16:47
Avatar
Doktor
Člen
Avatar
Doktor:

Zdravím,
mám problém s registrací. Konkrétně s tím, že se mi neuloží data do db. Hodí mě to na administraci, vypíše, že jsem přihlášen jako bla bla bla... Ale data v db poté nejsou. Ze zoufalosti jsem to celý zkopíroval i názvy proměnných jsem nechal prostě vše. Tak buď jsem kolosální blbec (nevylučuju to) a nebo nevím.

Když jsem zadal do databáze data "ručně", tak mi to přihlásit jde. Zadat tam to zahashované heslo bylo něco, ale to je fuk. Takže problém je jen v tý registraci. Nějaký nápad?

Díky za rady :-)

 
Odpovědět 19. ledna 0:12
Avatar
IT Man
Redaktor
Avatar
IT Man:

Oprava problému s nezaregistrováním uživatele, ale pouhým přihlášením
Po komunikaci přes soukromé zprávy s Doktor jsme zjistili v čem je chyba - DB si neví rady s nezadanou hodnotou admin. Pokud tedy není tento sloupec nastaven na některou z výchozích hodnot, vyhodí to pouze Warning (jednoduše - nezastaví to běh skriptu, ale ani se nikdo nedozví chybu). Pokud má někdo podobný problém, stačí pouze udělat některou z uvedených možností.

  1. V tabulce nastavit sloupečku admin výchozí hodnotu NULL nebo vlastní - 0.
  2. Opravit SQL dotaz pro registraci na následující podobu:
Db::query('
        INSERT INTO uzivatele (jmeno, heslo, admin)
        VALUES (?, SHA1(?), 0)
', $_POST['jmeno'], $_POST['heslo'] . "t&#ssdf54gh");
Odpovědět 19. ledna 16:57
Když nevíš jak dál, podá ti ruku někdo, od koho by jsi to nečekal. A tu šanci musíš přijmout!
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na IT Man
David Čápka:

Díky, ono MySQL měnilo výchozí chování. Mám to v plánu upravit, v zakládacích skriptech by měla být výchozí hodnota.

Odpovědět  +1 19. ledna 17:27
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
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 78. Zobrazit vše