Lekce 9 - Vylepšení kontaktního formuláře v PHP
V minulé lekci, Kontaktní emailový formulář v PHP, jsme naprogramovali jednoduchý emailový formulář.
V dnešním PHP tutoriálu si kontaktní formulář vylepšíme .
Předvyplnění polí
Když něco špatně vyplníme, skript nám to oznámí, ale formulář je již prázdný. Je to samozřejmě proto, že zobrazujeme již jinou stránku, než do které jsme data zadávali.
Protože zpracováváme data tím samý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. Budete to vypadat, jako by se
formulář ani 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 udělat samozřejmě jen v případě, když v
POST
tyto hodnoty jsou. Pokud ne, dá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 3 proměnné by bylo
nepohodlné. Zvláště, když by formulář obsahoval ještě další pole.
Proto si uvedeme tzv. ternární výraz. Jedná se o zkrácenou
podobu if
... else
. Ternání výraz vždy
vrací nějakou hodnotu, nedá se tedy použít jen místo podmínky.
Skládá se ze tří části, 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í. Za ní uvedeme :
a hodnotu, která se má
vrátit, když 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
tam prázdný textový řetězec, což jsou jednoduše uvozovky, mezi kterými
nic není.
Toto uděláme ještě s emailem 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 tam 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 ?>" />
Pokud chceme 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 bezpečný. Co kdyby nám do textu uživatel 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 tolik nevadilo, ale jsou případy, kde ano. Představte si, že vypisujete 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žil 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 vaš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ří vaši uživatelé tam opravdu zadají své heslo, které se odešle někam útočníkovi. A vy máte 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žijte 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.
Je potřeba při výpisu ošetřovat opravdu každou proměnnou, i ty, které uživatel přímo nezadá. Nikdy totiž nevíte, 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 tom místě, kde proměnnou vypisujeme. Až budete pokročilejší a budete znát objektovou architekturu, dokážete tento proces zautomatizovat, abyste 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áš email</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 odešleme, ukáže se chybová hláška a zároveň zůstane i to, co uživatel vyplnil:
Přesměrování
Formulář má nyní dvě podstatné vady. Pokud zprávu úspěšně odešleme, 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 jej zpracovává ten samý 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 tu samou adresu, na které je formulář.
Díky přesměrování se ovšem ztratí data v poli $_POST
.
Následné obnovení stránky tak 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 = 'Email 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 prohlížeči návštěvníka
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 ovšem ani hlášku o úspěchu. Mělo by vá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 = 'Email byl úspěšně odeslán, brzy vám odpovíme.';
Můžete 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ýkoliv výpis do stránky).
Jakmile se totiž začne něco vypisovat, PHP prohlížeči odešle hlavičku, kde mu říká, že mu posílá HTML soubor. Hlavičku lze samozřejmě odeslat jen jednou, když se pokusíme veprostř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 dělat 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í kterého změní adresu okna. Vypadá 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 4519x (3.13 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP