Internet Info, s.r.o. Lupa Měšec Podnikatel Root Zdroják DigiZone Slunečnice Vitalia TopDrive KupDnes Navrcholu NovýTarif Dobrý web Weblogy Woko Jagg Computer.cz SK: MojeLinky

Hlavní navigace

Nette Framework: Neprůstřelné formuláře II

Validační pravidla formulářů mohou být komplikovaná, pojďme se proto podívat, jak vyždímat z Nette Framework maximum.

Tweetni to Twitter Jaggni to! Jagg Del.icio.us Delicious

minulém díle seriálu o Nette Framework jsme se pustili do tvorby registračního formuláře. Výsledkem byl dobře fungující formulář s validací na straně prohlížeče i serveru, který navíc framework transparentně ochránil před vložením kontrolních znaků nebo neplatných řetězců útočníkem.

Vraťme se k políčku pro zadávání e-mailu. Tomu jsme nastavili validační pravidlo, které zkontroluje, zda je vložená adresa platná:

$form->addText('email', 'E-mail:')
        ->addRule(Form::EMAIL, 'E-mailová adresa není platná'); 

Protože prázdný řetězec pochopitelně není platnou emailovou adresou, tak nevyplnění e-mailu povede k chybové hlášce E-mailová adresa není platná, což není právě uživatelsky přívětivé a bylo by proto vhodné přidat na začátek pravidlo Form::FILLED. Co ale v případě, že chceme e-mailovou adresu mít nepovinnou, tj. kontrolovat její platnost jen v případě, že ji uživatel vyplnil? Tohle lze vyřešit přes tzv. validační podmínky. Ty se zapisují podobně jako pravidla, jen místo addRule použijeme metodu addCondition (chybová hláška se pochopitelně neuvádí):

$form->addText('email', 'E-mail:')
        ->addCondition(Form::FILLED) // podmínka: pokud je e-mail vyplněn
                ->addRule(Form::EMAIL, 'E-mailová adresa není platná'); // pak musí být platný 

Podmínku je možné vázat i na jiný prvek, než ten aktuální. Stačí addCondition nahradit za addConditionOn a jako první parametr uvést odvolávku na jiný prvek. V tomto případě se bude e-mail vyžadovat tehdy, zaškrtne-li se checkbox (tj. jeho logická hodnota bude TRUE):

$form->addCheckbox('promo', 'zasílejte mi reklamu');
$form->addText('email', 'E-mail:')
        ->addConditionOn($form['promo'], Form::EQUAL, TRUE) // podmínka: pokud je checkbox zaškrtnut
                ->addRule(Form::FILLED, 'Zadejte e-mailovou adresu'); // pak musí být e-mail zadaný 

Pravidla a podmínky je možné negovat přidáním ~, tj. addRule(~Form::EMAIL, ...). Také lze z podmínek vytvářet komplexní struktury za pomoci metod elseCondition()endCondition().

Jak vidíte, jazyk pro formulování podmínek a pravidel je velice silný. Výhodou je, že framework podle něj provede nejen validaci na straně serveru, ale vygeneruje i javascriptovou podobu. Disponuje celou řadou předdefinovaných validačních konstant:

Obecné pravidla
Form::EQUAL test rovnosti
Form::IS_IN testuje, zda hodnota spadá do výčtu hodnot
Form::FILLED je prvek vyplněn?
Form::VALID je prvek vyplněn správně?
Pro tlačítka
Form::SUBMITTED bylo tlačítko stisknuto?
Pro textové políčka
Form::MIN_LENGTH minimální délka
Form::MAX_LENGTH maximální délka
Form::LENGTH délka
Form::EMAIL je hodnota platná e-mailová adresa?
Form::URL je hodnota absolutní URL?
Form::REGEXP test oproti regulárnímu výrazu
Form::INTEGER je hodnota celočíselná?
Form::FLOAT je hodnota číslo?
Form::RANGE je hodnota v daném rozsahu?
Nahrávání souborů
Form::MAX_FILE_SIZE maximální velikost souboru
Form::MIME_TYPE ověření MIME type

Nic vám ovšem nebrání přidat si vlastní validátory:

// uživatelský validátor: testuje, zda je hodnota dělitelná argumentemfunction myValidator($item, $arg)
{
        return $item->getValue() % $arg === 0;
}

$form->addText('number', 'Číslo:')
        ->addRule('myValidator', 'Číslo musí být dělitelné %d.', 8); 

Prázdné hodnoty

Někdy se formulářovým políčkům nastavuje výchozí hodnota, která plní čistě vizuální úlohu. Příkladem je třeba vyhledávací formulář s popiskem Vyhledat přímo v textovém políčku. Jiným případem je políčko na zadání e-mailu, kde je předvyplněn zavináč, protože uživatelé mívají problém tento znak na klávesnici napsat.

V obou případech jde o hodnotu, kterou po odeslání formuláře nechceme v získaných datech mít. Vlastně ji musíme odfiltrovat už před validací, protože jinak nemusí proběhnout podle očekávání. Například podmínka Form::FILLED může být vyhodnocena jako splněná, i když prvek obsahuje jen tuto speciální hodnotu.

Nette Framework nabízí řešení v podobě tzv. „prázdné hodnoty“, kterou nastavíme metodou setEmptyValue(). Kompletní kód pro nepovinný zadávací prvek s e-mailovým políčkem a předvyplněným zavináčem bude vypadat takto:

$form->addText('email', 'E-mail:')
        ->setEmptyValue('@') // zavináč bude předvyplněn
        ->addCondition(Form::FILLED) // podmínka: pokud je e-mail vyplněn
                ->addRule(Form::EMAIL, 'E-mailová adresa není platná'); // pak musí být platný 

Pokud uživatel odešle formulář a prvek email bude obsahovat předvyplněný zavináč, v datech získaných metodou getValues() bude prázdný řetězec.

Prázdné hodnoty v select boxech

U select boxů často mívá první položka také speciální význam, slouží jako výzva k akci. V našem formuláři máme povinný prvek country pro uvedení země. Pole hodnot můžeme rozšířit o výzvu:

$countries = array(
        'Zvolte zemi', // <-- výzva k akci
        'Evropa' => array(
                'CZ' => 'Česká republika',
                'FR' => 'Francie',
                'DE' => 'Německo',
                'SK' => 'Slovensko',
                'GB' => 'Velká Británie',
        ),
        'AU' => 'Austrálie',
        'CA' => 'Kanada',
        '?'  => 'jiná',
); 

Aby však validace fungovala podle očekávání, musíme prvku nastavit, že první položka má tento speciální význam a při validaci je potřeba ji přeskakovat. K tomu slouží metoda  skipFirst():

$form->addSelect('country', 'Země:', $countries)
        ->skipFirst()
        ->addRule(Form::FILLED, 'Vyberte zemi'); 

Pokud nyní uživatel odešle formulář a jako země bude vybrána položka „Zvolte zemi“, zobrazí se uživateli chybová hláška „Vyberte zemi.“

Cross-Site Request Forgery

Nette Framework ochrání vaše aplikace před útokem Cross-Site Request Forgery (CSRF). Stačí k tomu vynaložit minimální úsilí:

$form->addProtection('Vypršel ochranný časový limit, odešlete prosím formulář ještě jednou'); 

A v tuto chvíli je váš formulář chráněn proti CSRF. Tedy vedle automatické ochrany proti celé řadě dalších útoků (XSS, UTF-8 attack, …).

Vylepšený zdrojový kód formuláře si můžete opět stáhnout.

Příště se podíváme na možnosti vykreslování formulářů.


Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Vyvíjí open-source knihovny Texy, dibi a Nette Framework a pravidelně pořádá školení pro tvůrce webových aplikací, které od podzimu 2009 nabídne kurz vývoje AJAXových aplikací.

David Grudl

David Grudl

David Grudl je autorem PHP knihoven Nette Framework, databázové vrstvy dibi a formátovače HTML kódu Texy!.

Školení Google+ pro firmy

DW - Školení PPC
  • Jak využít Google+ pro firemní komunikaci a marketing.
  • Čím se liší Google+ od Twitteru a Facebooku z pohledu firemního využití.
  • Jak využít Google+ v souladu s pravidly užívání.
  • Založení Google+ Page (Stránky) krok po kroku, včetně praktických tipů.

Detailní informace o školení Google+ »

Přehled názorů

Form::MIME_TYPE
int 9. 6. 2009 00:59
Nový
└ 
Re: Form::MIME_TYPE
David Grudl 9. 6. 2009 08:33
Nový
kratsi a kratsi
cckar 9. 6. 2009 09:27
Nový
└ 
Re: kratsi a kratsi
Martin Hassman 9. 6. 2009 09:40
Nový
Validacni pravidla
Mat 9. 6. 2009 16:19
Nový
Ach jo
melkor 9. 6. 2009 20:54
Nový
Dotázek
Mastodont 9. 6. 2009 21:28
Nový
└ 
Re: Dotázek
Onanym 10. 6. 2009 00:45
Nový
 
└ 
Re: Dotázek
Mastodont 10. 6. 2009 09:09
Nový
 
 
├ 
Re: Dotázek
Tomáš Kafka 10. 6. 2009 14:02
Nový
 
 
│
└ 
Re: Dotázek
Onanym 10. 6. 2009 15:29
Nový
 
 
└ 
Re: Dotázek
Onanym 10. 6. 2009 15:06
Nový
 
 
 
└ 
Re: Dotázek
Jiří Knesl 15. 6. 2009 20:28
Nový
ochrana před CSRF?
klikač 11. 6. 2009 22:19
Nový
└ 
Re: ochrana před CSRF?
David Grudl 12. 6. 2009 15:44
Nový
Existuje validacia datumu?
MareceK 30. 12. 2009 12:08
Nový
       

Tento text je již více než dva měsíce starý. Chcete-li na něj reagovat v diskusi, pravděpodobně vám již nikdo neodpoví. Pro řešení aktuálních problémů doporučujeme využít naše diskusní fórum.

Zasílat nově přidané příspěvky e-mailem