Aktuálně: Postihly zákazy tvou profesi? Poptávka po ajťácích prudce roste, využij halloweenské akce 80% výuky zdarma!
Pouze tento týden sleva až 80 % na e-learning týkající se Pythonu
Halloween BF

Lekce 6 - NERS - Editor článků v PHP

V minulé lekci, NERS - Registrace uživatelů v PHP, jsme si připravili projekt NERS - NEobjektový Redakční Systém v PHP a rozpracovali jsme skript registrace.php.

V dnešním PHP tutoriálu přidáme možnost přihlášení pro NERS.

Přihlašování

Vytvoříme skript prihlaseni.php. 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>Přihlášení do administrace</title>
</head>

<body>
    <article>
        <div id="centrovac">
            <header>
                <h1>Přihlášení do administrace</h1>
            </header>
            <section>
                <?php
                if (isset($zprava))
                    echo('<p>' . $zprava . '</p>');
                ?>

                <form method="post">
                    Jméno<br />
                    <input type="text" name="jmeno" /><br />
                    Heslo<br />
                    <input type="password" name="heslo" /><br />
                    <input type="submit" value="Přihlásit" />
                </form>

                <p>Pokud ještě nemáte účet, <a href="registrace.php">zaregistrujte se</a>.</p>
            </section>
            <div class="cistic"></div>
        </div>
    </article>
</body>
</html>

Vidíme PHP direktivu pro výpis chybové zprávy (pokud existuje) a formulář se jménem a heslem. Kód je téměř totožný s tím u registračního formuláře a měl by být tedy srozumitelný.

Nad HTML vložíme následující PHP blok:

<?php
session_start();
require('Db.php');
Db::connect('127.0.0.1', 'ners_db', 'root', '');

if (isset($_SESSION['uzivatel_id']))
{
    header('Location: administrace.php');
    exit();
}

if ($_POST)
{
    $uzivatel = Db::queryOne('
        SELECT uzivatele_id, admin, heslo
        FROM uzivatele
        WHERE jmeno=?
    ', $_POST['jmeno']);
    if (!$uzivatel || !password_verify($_POST['heslo'], $uzivatel['heslo']))
        $zprava = 'Neplatné uživatelské jméno nebo heslo';
    else
    {
        $_SESSION['uzivatel_id'] = $uzivatel['uzivatele_id'];
        $_SESSION['uzivatel_jmeno'] = $_POST['jmeno'];
        $_SESSION['uzivatel_admin'] = $uzivatel['admin'];
        header('Location: administrace.php');
        exit();
    }
}
?>

První řádky nám zpřístupní session a připojí se k databázi. Pokud je uživatel přihlášený, tak mu přihlašovací stránku zobrazovat nebudeme a přesměrujeme ho rovnou na administraci a skript zastavíme.

Pokud byl odeslán formulář, vybereme z databáze informace o uživateli podle zadaného jména a zkontrolujeme, zda se zadané heslo shoduje s otiskem hesla. Toho docílíme funkcí password_verify(), které zadáme jako parametry heslo a jeho otisk. Funkce nám následně vrátí true/false, podle toho, zda heslo souhlasí, či nikoliv. Pokud uživatele nenajdeme nebo bylo zadáno chybné heslo, uložíme chybovou hlášku. V případě úspěchu uložíme načtené informace o uživateli do session a tím ho přihlásíme. Dále ho přesměrujeme na administraci.

Můžete se zkusit přihlásit. Pokud jste ještě přihlášení z registrace, tak se odhlaste a přihlaste znovu.

Přihlašování uživatelů v PHP

Přidělení role administrátora

Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

V našem systému máme u každého uživatele sloupec admin. Ten bude nabývat hodnoty 0 nebo 1 podle toho, zda je uživatel administrátor. Tuto hodnotu může nastavit nově registrovanému uživateli pouze administrátor webu pomocí phpMyAdmin. Přesuneme se tedy do phpMyAdmin a přepneme hodnotu admin u našeho účtu na 1 (na políčko stačí jen poklikat a hodnotu přepsat).

Administrátorská práva v phpMyAdmin

Nyní se odhlaste a přihlaste.

Editor článků

Přejděme k editoru článků. Vytvořme soubor editor.php a vložme do něj HTML blok:

<!DOCTYPE html>
<html lang="cs-cz">
<head>
    <meta charset="utf-8" />
    <link rel="stylesheet" href="styl.css" type="text/css" />
    <title>Editor článků</title>
</head>

<body>
    <article>
        <div id="centrovac">
            <header>
                <h1>Editor článků</h1>
            </header>
            <section>
                <?php
                if (isset($zprava))
                    echo('<p>' . $zprava . '</p>');
                ?>

                <form method="post">
                    <input type="hidden" name="clanky_id" value="<?= htmlspecialchars($clanek['clanky_id']) ?>" /><br />
                    Titulek<br />
                    <input type="text" name="titulek" value="<?= htmlspecialchars($clanek['titulek']) ?>" /><br />
                    URL<br />
                    <input type="text" name="url" value="<?= htmlspecialchars($clanek['url']) ?>" /><br />
                    Popisek<br />
                    <input type="text" name="popisek" value="<?= htmlspecialchars($clanek['popisek']) ?>" /><br />
                    Klíčová slova<br />
                    <input type="text" name="klicova_slova" value="<?= htmlspecialchars($clanek['klicova_slova']) ?>" /><br />
                    <textarea name="obsah"><?= htmlspecialchars($clanek['obsah']) ?></textarea>
                    <input type="submit" value="Odeslat" />
                </form>
            </section>
            <div class="cistic"></div>
        </div>
    </article>
    <script type="text/javascript" src="//tinymce.cachefly.net/4.0/tinymce.min.js"></script>
    <script type="text/javascript">
        tinymce.init({
            selector: "textarea[name=obsah]",
            plugins: [
                "advlist autolink lists link image charmap print preview anchor",
                "searchreplace visualblocks code fullscreen",
                "insertdatetime media table contextmenu paste"
            ],
            toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
            entities: "160,nbsp",
            entity_encoding: "named",
            entity_encoding: "raw"
        });
    </script>
</body>
</html>

Kód obsahuje opět jen jednoduchý HTML formulář a výpis chybové zprávy. Data se do formulářových polí vypisují z pole $clanek. Formulář má ještě jednu zvláštnost a tou je skryté pole s ID daného článku. Podle tohoto pole poznáme, zda vkládáme nový článek (bude prázdné) nebo zda editujeme existující (bude v něm ID tohoto článku).

Zajímavý je JavaScript na konci souboru, ve které načteme WYSIWYG editor TinyMCE. To je editor vzhledově podobný např. MS Wordu, který nám generuje HTML kód podle toho, co v něm naklikáme.

První skript je odkaz na online úložiště, ze kterého si prohlížeč TinyMCE stáhne. Druhý skript obsahuje nastavení editoru, zvolíme, že editor chceme vytvořit z textarea s názvem obsah. Další řádky nastavují pluginy a vypínají převod české diakritiky na entity, což je jinak poměrně nepříjemná záležitost.

Nad HTML kód dodejme obslužný PHP blok:

<?php
session_start();
if (empty($_SESSION['uzivatel_admin']))
    die('Nedostatecna opravneni');

require('Db.php');
Db::connect('127.0.0.1', 'ners_db', 'root', '');

$clanek = array(
    'clanky_id' => '',
    'titulek' => '',
    'obsah' => '',
    'url' => '',
    'popisek' => '',
    'klicova_slova' => '',
);
if ($_POST)
{
    if (!$_POST['clanky_id'])
    {
        Db::query('
            INSERT INTO clanky (titulek, obsah, url, popisek, klicova_slova)
            VALUES (?, ?, ?, ?, ?)
        ', $_POST['titulek'], $_POST['obsah'], $_POST['url'], $_POST['popisek'], $_POST['klicova_slova']);
    }
    else
    {
        Db::query('
            UPDATE clanky
            SET titulek=?, obsah=?, url=?, popisek=?, klicova_slova=?
            WHERE clanky_id=?
        ', $_POST['titulek'], $_POST['obsah'], $_POST['url'], $_POST['popisek'], $_POST['klicova_slova'], $_POST['clanky_id']);
    }
    header('Location: index.php?clanek=' . $_POST['url']);
    exit();
}
else if (isset($_GET['url']))
{
    $nactenyClanek = Db::queryOne('
        SELECT *
        FROM clanky
        WHERE url=?
    ', $_GET['url']);
    if ($nactenyClanek)
        $clanek = $nactenyClanek;
    else
        $zprava = 'Článek nebyl nalezen';
}

?>

Pokud uživatel není administrátor, zastavíme celý skript s chybovou hláškou. Pro kontrolu přihlášení administrátora nám nestačí isset(), ale musíme použít empty(). V session totiž může existovat klíč 'uzivatel_admin', ale může mít hodnotu 0.

Dále se připojíme k databázi a do proměnné $clanek si připravíme pole s prázdnými hodnotami. To aby se do formuláře nic nevypsalo a zároveň nám PHP neohlásilo chybu s neexistující proměnnou.

Pokud byl odeslán formulář, podíváme se do skrytého pole. Pokud je prázdné, vložíme nový článek do databáze. Pokud je v skrytém poli nějaká hodnota, updatujeme článek s tímto ID. SQL příkaz UPDATE jsme si ještě nepředstavovali, ale je velmi jednoduchý. Pomocí SET jednoduše nastavíme pole která potřebujeme. Co je důležité je nezapomenout na klauzuli WHERE, kde určíme které řádky se mají takto updatovat. Bez ní by se updatovaly všechny články na tyto hodnoty!

Po přidání nebo editaci článku na něj přesměrujeme.

Pokud nebyl odeslaný formulář, podíváme se, zda nemáme v GET url článku. To by znamenalo, že chceme nějaký editovat a proto se do pole $clanek pokusíme nahrát data z článku s tímto URL. Data se potom předvyplní do polí formuláře. Při neúspěchu vypíšeme chybovou hlášku.

Nyní si editor spusťte a vložte si článek s URL "uvod". To bude hlavní stránka našeho webu:

Editor článků TinyMCE v PHP

Článek uložte do databáze.

V další lekci, NERS - Výpis článků v PHP, dokončíme editor článků jednoduchého redakčního systému a vytvoříme úvodní stránku.


 

Předchozí článek
NERS - Registrace uživatelů v PHP
Všechny články v sekci
Databáze v PHP pro začátečníky
Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
19 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 university Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity (8)

 

 

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

Avatar
Honza Motal
Člen
Avatar
Honza Motal:29.9.2019 20:58

Ahoj, mám v databázi tabulku "uzivatele" a sloupec "adresa". Pomocí formuláře chci adresu změnit pro aktuálně přihlášeného uživatele, ale ať to kontroluji jak chci, pořád to nefunguje. Nenapadá někoho čím to může být?

if(isset($_POST['adresa']))
        {
            Db::query('
                UPDATE uzivatele
                SET adresa = ?
                WHERE uzivatel_id = ?',
                $_POST['adresa'], $_SESSION['uzivatel_id']);
        }
 
Odpovědět
29.9.2019 20:58
Avatar
Honza Motal
Člen
Avatar
Odpovídá na Honza Motal
Honza Motal:30.9.2019 21:18

8-) Problem solved

 
Odpovědět
30.9.2019 21:18
Avatar
phpnoob
Člen
Avatar
phpnoob:8.10.2019 7:28

parádička , zapísalo článok do DB , ďakujem ... viem že skoro nič neviem , ale snažím sa to pochopiť a tieto články mi v tom pomáhajú . viac menej idem copy paste ale čítam váš komentár + snažím sa pochopiť kod . dúfam že do týždňa to budem schopný naprogrmaovať sám .

ešte si to pár krát budem opakovať aby sa mi informácie dobre načítali do mozgu :) . a ide sa na dalšiu lekciu .

 
Odpovědět
8.10.2019 7:28
Avatar
Jakub Kondělka:24. března 18:55

Ahoj,
potřeboval bych poradit. Když chci článek uložit do databáze, tak mi to vyhodí tu to chybu.

Warning: PDO::prepare(): SQLSTATE[42S22]: Column not found: 1054 Unknown column 'titulek' in 'field list' in C:\xampp\htdoc­s\Layoty\Db.php on line 61

Fatal error: Uncaught Error: Call to a member function execute() on bool in C:\xampp\htdoc­s\Layoty\Db.php:62 Stack trace: #0 C:\xampp\htdoc­s\Layoty\Db.php(72): Db::executeSta­tement(Array) #1 C:\xampp\htdoc­s\Layoty\editor­.php(45): Db::query('\r\n\t\t­\tINSERT INT...', 'HoBiho web', '<p>sdfsdfsfs­ddf...', 'uvod', '\xC3\x9Avodn\xC3\xAD \xC4\x8Dl\xC3­\xA1n...', '\xC4\x8Dl\xC­3\xA1nek,web,\xC3\xBA­...') #2
{main} thrown in C:\xampp\htdoc­s\Layoty\Db.php on line 62

Netuším co mi tam chybí a nebo kde je chyba.
Díky za rady. Jakub

 
Odpovědět
24. března 18:55
Avatar
Odpovídá na Jakub Kondělka
Jakub Kondělka:24. března 19:32

Už jsem na to přisel :-) chyba vypisuje neznamy řádek. Chybně napsané v databázi.

 
Odpovědět
24. března 19:32
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Václav Vomáčka:29. března 14:33

Ahoj nevím, zda se to tu někde už neřešilo, ale jaký má význam na začátku toho PHP skriptu plnit to pole $clanky? Je to pouze abych měl jistotu, že to pole bude prázdné a nepředvyplní se mi do formuláře daná data? V případě, že budu řešit ošetření odesílaných dat (pole nebylo vyplněně, datum není ve správném formátu, anti-spam je špatně), tak je toto pole pro mě nežádoucí, neboť se mi po "nepovedeném" odeslání formuláře a znovunačtení této stránky celý formulář vymaže. Mám pravdu nebo na to nahlížím špatně?

 
Odpovědět
29. března 14:33
Avatar
Odpovídá na Václav Vomáčka
Martin Kašpar:29. března 16:45

Ahoj, jak na to v rychlosti koukám, určitě bys bez toho pole dostával při tvorbě nového článku nebo při zadání neplatného $_GET['url'] na web a do logu Notice Undefined Index $clanek['clan­ky_id'], titulek, url atd. Tahle část kódu totiž jinak nepočítá s tím, že by pole neexistovalo.

<input type="hidden" name="clanky_id" value="<?= htmlspecialchars($clanek['clanky_id']) ?>" />

I kdybys ho dal pryč, tak se ti při nepodařeném odeslání obsah vymaže. Když se na to podíváš, je to psané tak, že se data z POST requestu uloží do DB a pak jsi pomocí hlavičky location redirectován na volání s GET parametrem url. Tím se celý POST po uložení rovnou ztrácí. Když ti tedy uložení neprojde, vrátí se ti neexistující DB záznam.

U takové konstrukce kódu by bylo nejlepší při selhání validace přepsat výchozí prázdné hodnoty těmi z POST requestu, přidat chybovou zprávu a bez úspěšné kontroly nedělat uložení do DB ani přesměrování.

 
Odpovědět
29. března 16:45
Avatar
Odpovídá na Martin Kašpar
Václav Vomáčka:29. března 21:28

Ahoj, už jsem to pochopil a celý ten script překopal podle tvých rad. Díky V.

 
Odpovědět
29. března 21:28
Avatar
Pavel Buřič:29. září 20:04

zdravím přátelé.
Vím, že j)se podobný dotaz zde objevil několikrát, ale nějak rádná odpověď na problém.
Vše jsem dělal dle postupu, ale při pokusu o přihlášení se nic nestane pouze mi vypíše"Neplatné uživ. jméno nebo heslo".Žádná chyba nic. Může někdo prosím poradit co je špatně. dík moc

<?php
session_start();
require('Db.php');
Db::connect('127.0.0.1', 'users_db', 'root', '');

if (isset($_SESSION['uzivatel_id']))
{
    header('Location: administrace.php');
    exit();
}

if ($_POST)
{
    $uzivatel = Db::queryOne('
        SELECT uzivatele_id, admin, heslo
        FROM uzivatele
        WHERE jmeno=?
    ', $_POST['jmeno']);
    if (!$uzivatel || !password_verify($_POST['heslo'], $uzivatel['heslo']))
        $zprava = 'Neplatné uživatelské jméno nebo heslo';
    else
    {
        $_SESSION['uzivatel_id'] = $uzivatel['uzivatele_id'];
        $_SESSION['uzivatel_jmeno'] = $_POST['jmeno'];
        $_SESSION['uzivatel_admin'] = $uzivatel['admin'];
        header('Location: administrace.php');
        exit();
    }
}
?>
 
Odpovědět
29. září 20:04
Avatar
Odpovídá na Pavel Buřič
Pavel Buřič:29. září 20:45

jediné co mne napadá jestli nemůže byt problém v php.ini. veditoru mam vykřicník s textem

Do not access superglobal $_POST array directly

 
Odpovědět
29. září 20:45
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 106. Zobrazit vše