NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 10 - Vylepšení kontaktního formuláře v PHP

V minulé lekci, Kontaktní e-mailový formulář v PHP, jsme naprogramovali jednoduchý e-mailový formulář.

V dnešním PHP tutoriálu si kontaktní formulář vylepšíme.

Předvyplnění polí

Když jako uživatel něco špatně vyplníme, skript nám to sice oznámí, ale formulář je již prázdný. To se samozřejmě děje, protože zobrazujeme již jinou stránku, než do které jsme data zadávali.

Protože zpracováváme data týmž skriptem, ve kterém je formulář, můžeme do formuláře jednoduše vložit hodnoty z POST v případě, že byly nějaké odeslány. Bude to vypadat, jako by se formulář nevymazal.

V PHP bloku těsně před formulářem si naplníme proměnné $jmeno, $email a $zprava hodnotami z $_POST. To můžeme samozřejmě udělat jen v případě, pokud v POST tyto hodnoty jsou. Pokud ne, vložíme do proměnných prázdné řetězce.

V této chvíli bychom kód napsali asi takto:

if (isset($_POST['jmeno']))
    $jmeno = $_POST['jmeno'];
else
    $jmeno = '';

Kód je poměrně dlouhý a psát ho pro všechny tři proměnné by bylo nepohodlné, natož pokud by formulář obsahoval ještě další pole. Proto si uvedeme tzv. ternární výraz. Jedná se o zkrácenou podobu konstrukce ifelse. Ternární výraz vždy vrací nějakou hodnotu, nedá se tedy použít jen místo podmínky. Skládá se ze tří částí, což by nás podle jeho názvu nemělo překvapit :) V první části uvedeme podmínku, dále znak ? a poté hodnotu, kterou má výraz vrátit, pokud podmínka platí. Pak uvedeme : a hodnotu, která se má vrátit, pokud podmínka neplatí.

Proměnnou bychom pomocí ternárního výrazu naplnili takto:

$jmeno = (isset($_POST['jmeno'])) ? $_POST['jmeno'] : '';

Ještě malá rekapitulace. Pokud v POST existuje daný klíč, vložíme tuto hodnotu do proměnné $jmeno. Pokud ne, vložíme do proměnné prázdný textový řetězec, což jsou jednoduše uvozovky, mezi kterými nic není.

Toto uděláme ještě s e-mailem a zprávou.

Formulář dále upravíme tak, aby se do jeho polí vkládaly hodnoty z těchto proměnných. Pokud nebyl formulář odeslán, vloží se do polí prázdné řetězce, jinak se tam vloží to, co uživatel vyplnil.

Do formulářového pole bychom mohli hodnotu vložit takto:

<input name="jmeno" type="text" value="<?php echo $jmeno ?>" />

Chceme-li v PHP sekvenci pouze vypsat obsah proměnné, použijeme k tomu zkrácenou direktivu <?=. Stejného výstupu tedy můžeme dosáhnout i kratším zápisem:

<input name="jmeno" type="text" value="<?= $jmeno ?>" />

Stále to však není ono. Jelikož text v proměnné $jmeno pochází od uživatele, nemůžeme si být jistí, že je text bezpečný. Co kdyby nám uživatel do textu vložil nějaký HTML kód? Vložil by se poté normálně do naší stránky.

V našem případě by to příliš nevadilo, ale existují případy, kde ano. Představme si, že vypisujeme na stránce zprávy od uživatelů, třeba komentáře k nějakému článku. A jeden uživatel místo textu zprávy vloží HTML kód s formulářem, který je nasměrovaný na jeho obslužný skript na jiném webu a ve kterém požaduje od našich uživatelů heslo. Při vypisování zprávy se tento kód vypíše do stránky a zobrazí se jeho formulář. Někteří naši uživatelé tam opravdu zadají své heslo, které se odešle útočníkovi. A my máme problém.

Tomuto typu útoku se říká XSS (jako Cross-site Scripting). Obrana je velmi jednoduchá, před vypsáním obsahu kterékoli proměnné do HTML kódu stránky použijeme funkci htmlspecialchars(). Ta převede špičaté HTML závorky a pár dalších znaků na tzv. HTML entity. Případný škodlivý kód je potom braný jen jako obyčejný text a prohlížeč ho nezpracuje jako HTML kód.

Při výpisu je potřeba ošetřovat opravdu každou proměnnou, i ty, které uživatel přímo nezadá. Nikdy totiž nevíme, jestli se obsah proměnné neskládá z něčeho, co uživatel zadal, a jednoduše se to nedá ohlídat. Proto se ošetří vše, a to přímo na místě, kde proměnnou vypisujeme. Až budete pokročilejší a budete znát objektovou architekturu, dokážeme tento proces zautomatizovat, abychom funkci nemuseli ručně psát.

Ukažme si konečně upravený HTML kód formuláře i s direktivou nad ním:

<?php
    if ($hlaska)
        echo('<p>' . htmlspecialchars($hlaska) . '</p>');

    $jmeno = (isset($_POST['jmeno'])) ? $_POST['jmeno'] : '';
    $email = (isset($_POST['email'])) ? $_POST['email'] : '';
    $zprava = (isset($_POST['zprava'])) ? $_POST['zprava'] : '';
?>

<form method="POST">
    <table>
        <tr>
            <td>Vaše jméno</td>
            <td><input name="jmeno" type="text" value="<?= htmlspecialchars($jmeno) ?>"/></td>
        </tr>
        <tr>
            <td>Váš e-mail</td>
            <td><input name="email" type="email" value="<?= htmlspecialchars($email) ?>"/></td>
        </tr>
        <tr>
            <td>Aktuální rok</td>
            <td><input name="rok" type="number" /></td>
        </tr>
    </table>
    <textarea name="zprava"><?= htmlspecialchars($zprava) ?></textarea>
    <br />

    <input type="submit" value="Odeslat" />
</form>

Formulář si vyzkoušejme. Ponechme nějaké pole prázdné a formulář odešleme. Ukáže se chybová hláška, ale zároveň zůstane vyplněné i to, co uživatel zadal:

Kontaktní formulář
localhost/mail­form.php

Přesměrování

Formulář má nyní dvě podstatné vady. Pokud zprávu úspěšně odešleme, formulář stejně zůstane předvyplněný. A hlavně: pokud po odeslání stiskneme F5, formulář se odešle znovu. Tímto neduhem trpí všechny formuláře, pokud je zpracovává tentýž soubor, ve kterém je formulář vložený (což je většinou nutné).

Pokud je zpracování formuláře dokončeno, měli bychom provést přesměrování. Přesměrujeme na tutéž adresu, na které je formulář. Díky přesměrování se však ztratí data v poli $_POST, a následné obnovení stránky tedy již nic neodešle.

Přesměrování provedeme pomocí funkce header(). Ta odešle tzv. hlavičku prohlížeči. Právě hlavička může obsahovat informaci o přesměrování, a to pomocí slova Location.

Po uložení úspěšné hlášky tedy formulář přesměrujeme:

if ($uspech) {
    $hlaska = 'E-mail byl úspěšně odeslán, brzy vám odpovíme.';
    header('Location: mailform.php');
    exit;
}

Funkcí exit() ukončíme běh skriptu, jelikož samotné přesměrování ho nezastaví, jen pošle návštěvníkovu prohlížeči informaci o tom, že se má přesunout na jinou lokaci.

Formulář již netrpí opětovným odesláním při obnovení stránky. Nezobrazuje však ani hlášku o úspěchu. Mělo by nám být jasné proč. Když přesměrujeme na jinou stránku, obsah proměnných na stránce stávající se ztratí a tím i ten v $hlaska. Řešení je několik. Tím nejjednodušším je předat pomocí GET parametru stránce nějakou proměnnou. Podle toho stránka pozná, že na ní bylo přesměrováno po úspěšném odeslání, a zobrazí o tom zprávu. Kód změníme na následující podobu:

header('Location: mailform.php?uspech=ano');
exit;

Přesuneme se na začátek skriptu, kde hlášku nastavujeme na prázdný string. Podíváme se, zda nám nepřišel v adrese parametr uspech. Pokud ano, nastavíme hlášku na text, který se má při úspěchu uživateli vypsat. Již víme, že parametry z URL adresy přicházejí na rozdíl od parametrů z formuláře v poli $_GET:

$hlaska = '';
if (isset($_GET['uspech']))
    $hlaska = 'E-mail byl úspěšně odeslán, brzy vám odpovíme.';

Můžeme si vychutnat dobře fungující formulář.

POZOR! Přesměrovat můžeme pouze v případě, že jsme ještě nevypsali žádné HTML (jakýkoli výpis do stránky).

Jakmile se totiž začne něco vypisovat, PHP odešle prohlížeči hlavičku, kde mu říká, že mu posílá HTML soubor. Hlavičku lze samozřejmě odeslat jen jednou. Když se pokusíme uprostřed souboru přesměrovat, dostaneme chybovou hlášku "Headers already sent" a k přesměrování nedojde. To by se stalo třeba v tomto případě:

<html lang="cs">
    <body>
        <?php
            // Tento kód je špatně
            header('Location: index.php');
            exit;
        ?>
    </body>
</html>

Dávejte si pozor i na tento případ, ve kterém chyba není na první pohled vidět:

-- Zde je prázdná řádka --
<?php

    header('Location: index.php');

?>
<html lang="cs">
    <body>
    </body>
</html>

Na začátku souboru je odřádkování. I to je znak, který odstartuje výstup, a PHP ho odesílá prohlížeči spolu s hlavičkou. Podobný problém bývá s mezerou. Pokud ukládáte UTF-8 soubory s tzv. BOM, může způsobovat právě tyto problémy. Pokud však používáte kvalitní IDE, tak se vám to nestane.

Pozn.: Někteří začátečníci přesměrovávají tak, že vyechují JavaScript, pomocí nějž změní adresu okna. Vypadá to asi takto:

// Tento kód je špatně
echo('<script type="text/javascript">
    window.location = "index.php"
</script>');

Tento způsob je však nespolehlivý a někdy i nebezpečný. Nepoužívejte ho.

Formulář si můžete nastylovat, aby vypadal lépe. Hlášku dát do nějaké bubliny a podobně. To ale již není předmětem tohoto PHP kurzu, stylování se probírá v jiném on-line kurzu :) Kompletní formulář je ke stažení níže.

V následujícím kvízu, Kvíz - Podmínky, boolean, switch a formuláře v PHP, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 4574x (1.86 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

Předchozí článek
Kontaktní e-mailový formulář v PHP
Všechny články v sekci
Základní konstrukce jazyka PHP
Přeskočit článek
(nedoporučujeme)
Kvíz - Podmínky, boolean, switch a formuláře v PHP
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
283 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity