Validácia formulára
V tejto kapitole si ukážeme validáciu (kontrolu) formulára, ktorý sme použili v kapitole o odoslaní mailu (uni 4900). Kód tohto formulára si môžeme skopírovať do súboru page3.php, kód z minulej kapitoly (regulárne výrazy) si zatiaľ zakomentujeme. Validáciou formulára sa myslí kontrola jednotlivých prvkov, či spĺňajú nami očakávané predpisy – formáty hodnôt. Údaje zadané používateľom sa vo väčšine ďalej v kóde spracovávajú alebo niekam ukladajú (databáza, lokálne súbory...), preto je dôležité ich kontrolovať. V prípade nesprávne zadaných hodnôt môže následne funkcionalita s nimi zlyhať, takže týmto spôsobom tomuto zamedzíme. Pri výskyte zlých hodnôt sa to používateľovi zvyčajne dáva najavo a spomenutá funkcionalita sa ani nevykoná.
Na kontrolu jednotlivých hodnôt existujú aj nejaké zabudované funkcie v jazyku, ktoré vedia overiť niektoré používané reťazce znakov. My však už z predchádzajúcej kapitoly vieme, že nám na to slúžia regulárne výrazy. Náš formulár chceme použiť ako kontaktný formulár na stránke. To, kam sa mail odosiela, bude zadané natvrdo v kóde. Je to vo väčšine kontaktný mail majiteľa/prevádzkovateľa webstránky. Preto si našu prvú položku adresát zmeníme na email, ktorý bude značiť email používateľa, ktorý sa snaží skontaktovať mailom. Pred túto položku si ešte pridáme jeden prvok s názvom meno, do ktorého by mal používateľ napísať svoje meno. Súbor page3.php by mal vyzerať takto:
page3.php:
<form action="page3.php" method="post">
<label for="email">Meno a priezvisko</label>
<input type="text" name="name" id="name" value="<?php echo $_POST['name'];?>"><br><br>
<label for="email">Email</label>
<input type="text" name="email" id="email" value="<?php echo $_POST['email'];?>"><br><br>
<label for="subject">Predmet</label>
<input type="text" name="subject" id="subject" value="<?php echo $_POST['subject'];?>"><br><br>
<label for="message">Správa</label>
<textarea name="message" id="message" value="<?php echo $message;?>" placeholder="Zadajte text spravy..."></textarea><br><br>
<input type="submit" value="Odoslat">
</form>
Formulár už máme pripravený, teraz nám ostáva vyriešiť validáciu. Čo to teda pre nás znamená? Našou úlohou je donútiť používateľa, aby zadal korektné informácie. Pokiaľ tak neurobí, funkcionalita sa nevykoná – v tomto prípade odoslanie emailu. V našom kóde si teda musíme skontrolovať, či bol vôbec formulár odoslaný. Následne by sme mali skontrolovať všetky hodnoty, ktoré chceme kontrolovať, či spĺňajú naše požiadavky.
V prípade, že spĺňajú, zobrazíme používateľovi správu o úspešnom odoslaní, v opačnom prípade mu zobrazíme hlášku o zle zadaných údajoch. Povedzme, že nateraz ideme iba kontrolovať správne zadaný email, pretože pri položke predmet a text správy môže v podstate používateľ zadať čokoľvek. Pri položke meno môže zadať tiež čokoľvek, vymyslime si ale situáciu, že to bude akýsi interný nickname (prezývka) stránky a musí to byť reťazec písmen a čísiel o minimálnej dĺžke 5 a maximálnej 10 znakov. Túto úlohu by ste teoreticky mohli zvládnuť, skúste si napísať, ako by ste to urobili. Mohlo by to vyzerať asi takto:
page3.php:
<?php
if($_SERVER['REQUEST_METHOD'] == 'POST' && $_POST['contact_form']){
if(!preg_match('#^[a-zA-Z0-9]{5,10}$#', $_POST['name']) || !preg_match('#^.+@.+\..+$#', $_POST['email'])){
echo '<p>Zadajte prosim korektne udaje</p>';
//naplnenie formulara
$name = $_POST['name'];
$email = $_POST['email'];
$subject = $_POST['subject'];
$message = $_POST['message'];
}else{
//odoslanie emailu
echo '<p>Vasa sprava bola uspesne odoslana.</p>';
$name = '';
$email = '';
$subject = '';
$message = '';
}
}
?>
<form action="page3.php" method="post">
<label for="email">Meno a priezvisko</label>
<input type="text" name="name" id="name" value="<?php echo $name;?>"><br><br>
<label for="email">Email</label>
<input type="text" name="email" id="email" value="<?php echo $email;?>"><br><br>
<label for="subject">Predmet</label>
<input type="text" name="subject" id="subject" value="<?php echo $subject;?>"><br><br>
<label for="message">Správa</label>
<textarea name="message" id="message" placeholder="Zadajte text spravy..."><?php echo $message;?></textarea><br><br>
<input type="submit" name="contact_form" value="Odoslat">
</form>
Pozrite sa najprv na kód formulára. Nastali tam iba tieto zmeny - metóda odosielania by mala byť post, defaultný text správy sme dali ako palceholder, nie ako value a tlačítku submit sme pridali atribút name. Pred formulárom sa nachádza kód jazyka PHP, ktorý rieši odosielanie formulára. Na začiatku máme v podmienke funkciu $_SERVER['REQUEST_METHOD'], ktorá slúži na otestovanie, či bol formulár odoslaný metódou post. Je dobré si zvyknúť používať túto podmienku na akúkoľvek prácu so zachytávaním poslaných dát. Za ňou nasleduje ešte jedna podmienka a to je, či nám prišla hodnota s názvom contact_form, ktorú sme pridali do atribútu name tlačítku v našom formulári. Prečo sme to tak urobili? Predstavte si, že máte na stránke dva rôzne formuláre, ktoré oba odosielate metódou post. Ako by ste rozlíšili, kedy sa poslali dáta z jedného a kedy z druhého? Presne takto sa to dá šikovne zistiť, tlačítko submit má nastavený atribút value stále (je to jeho zobrazovaný text), takže ak sa naň kliklo, táto hodnota nám musí prísť.
Po overovaní, či bol formulár odoslaný metódou, ktorú očakávame a či bol odoslaný ten správny formulár, máme v tele tejto podmienky ďalšiu podmienku, ktorá rozlišuje, či boli údaje vo formulári zadané správne. Ako sme si povedali, predmet a text správy nemáme prečo kontrolovať, ale pre email a meno máme predom určené pravidlá, ktoré musia byť splnené. Preto v tejto podmienke kontrolujeme, že či náhodou nespĺňa nejaká z týchto dvoch zadaných hodnôt náš predpis (regulárny výraz). Ak nespĺňa, hodnota funkcie je 0, máme pred nimi ale výkričník (negácia), takže sa z toho stane 1, resp. pravda a tým pádom, ak aspoň jedna z týchto dvoch nie je splnená (čiže bude jedna z nich pravda), podmienka je splnená a spúšťa sa jej prvá vetva (nie else).
Táto vetva teda rieši prípad, kedy boli údaje zadané zle. Všimnite si, čo v nej vykonávame. Používateľovi zobrazíme hlášku, že údaje boli nesprávne zadané. Okrem toho si do premenných, ktorých názvy predstavujú jednotlivé položky formulára nastavíme hodnoty, ktoré nám prišli. Všimnite si, že tieto premenné máme potom nastavené v atribúte value pri každom prvku formulára. To je preto, aby ak boli zle zadané údaje, boli tieto hodnotu znova zobrazené v inputoch, aby tie správne zadané nemusel používateľ znova zadávať, aby sa nevymazali. Vo vetve else, ktorý rieši správne zadané údaje, tieto hodnoty vynulujeme (priradíme prázdny string) a po zobrazení hlášky používateľovi, že správa bola úspešne odoslaná bude mať formulár vyresetovaný – hodnoty budú vynulované. Samotné odoslanie mailu neriešime, to nateraz nie je podstatné. Môžme si ale predstaviť, že odoslanie mailu by bolo práve na tomto mieste.
Takto nejako by mohla vyzerať jednoduchá validácia nášho formulára, ktorý si v nasledujúcej kapitole naštýlujeme. Vráťme sa ešte k overovaniu správne zadanej emailovej adresy. Ako sme si povedali, náš regulárny výraz nie je úplne správny a ten správny je oveľa zložitejší, existuje však vstavané funkcia v jazyku PHP, ktorá overuje niektoré hodnoty a typy hodnôt. Názov tejto funkcie je filter_var (filter variable – filtruj premennú), kde ako prvý parameter posielame testovanú hodnotu a ako druhý parameter typ preddefinovaných typov hodnôt, ktoré chceme otestovať. Týchto hodnôt je viac, pre overovanie emailovej adresy je to hodnota FILTER_VALIDATE_EMAIL. Táto funkcia v prípade správnosti údajov vráti danú hodnotu, v opačnom prípade hodí false. Takže namiesto testovania regulárneho výrazy môžeme v našej podmienke použiť výraz filter_var($_POST['email'], FILTER_VALIDATE_EMAIL).
Okrem toho môžeme náš formulár vylepšiť ešte o jednu vec. Pri posielaní dát a všeobecne formulárov, kedy sa posielajú dáta, sa môže vyskytnúť nejaký útok od používateľa. Nejdeme si to teraz podrobne vysvetľovať, to sa bude podrobnejšie preberať neskôr, je dobré ale vedieť, že práve pri odosielaní formulára sa to môže stať. Zraniteľné miesto je práve atribút action v tagu form, kde zadávame, kam sa má formulár odosielťa. V prípade, že odosielame formulár na seba samého, čiže na ten istý súbor – tak, ako sme to robili my, je možné špecifikovať tento cieľ inak. Slúži na to prvok premennej $_SERVER s názvom PHP_SELF, čiže výraz $_SERVER["PHP_SELF"] nám hodí názov nášho súboru – seba samého. Práve tento výraz sa dá kadejako zneužiť, aby sa tomu predišlo, obalíme tento výraz funkciou htmlspecialchars(), ktorá konvertuje špeciálne znaky do znakov zrozumiteľných pre jazyk HTML. Práve toto konvertovanie môže v istých prípadoch zamedziť útoku pri odoslaní formulára (pri jeho presmerovaní niekam inam). Náš kód by mohol teda vyzerať takto:
page3.php (iba zmenený kód):
…
f(!preg_match('#^[a-zA-Z0-9]{5,10}$#', $_POST['name']) || !filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){
…
<form action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" method="post">