Forms\Controls\SelectBox by neměl vracet NULL

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
nAS
Člen | 277
+
0
-

Nette je známé pečlivou validací formulářových prvků a při vytváření SelectBox-u mnoho lidí slepě spoléhá, že Nette vrátí pouze nějakou z jimi definovaných hodnot, což bohužel nemusí být pravda. Pokud útočník upraví SelectBox (např. ve Firebugu) a zvolí jinou hodnotu, tak Nette správně pozná, že hodnota není definována a vráti NULL, což je problém, protože s tím programátor často nepočítá. Proč by také měl, když oficiální cestou uživatel NULL SelectBoxu nemůže vnutit (bavíme se o případu, kdy tam není NULL úmyslně od programátora).

Samozřejmě mohu zavolat ->setRequired() a pak se bude SelectBox chovat dle předpokladů. Ale jádro mé otázky zní: proč není na SelectBoxu nastaveno setRequired() defaultně, když bez hackování nemůže legitimní uživatel zvolit jinou hodnotu? To se opravu počítá s tím, že někdo má měnit hodnotu přes FireBug, aby nastavil nevybranou hodnotu? To asi ne.

Jediné porušení zpětné kompatibility by bylo dle mého názoru v SelectBoxu, který neobsahuje žádné hodnoty. S tím by nyní nešel formulář odeslat. Ale je otázkou, zda vůbec existuje reálný důvod proč podporovat SelectBox bez hodnot, když výrazně správnější by bylo použít např. array(NULL => '- nevybráno -').

To že programátoři opravdu zapomínají používat ->setRequired() mohu ukázat například v oficiálním examplu Nette: Forms, kde se pro nevybranou hodnotu vrací „0“, ale formulář může neočekávaně vrátit i NULL.

A příklad kdy to vadí? Internetové bankovnictví, uživatel spravuje více účtů a chce si prohlédnout historii jednoho. Použijeme SelectBox, pro filtraci kterého, a při skládání SQL dotazu se místo user_id = 123 vytvoří user_id IS NULL což vypíše servisní zásahy.

Jan Endel
Člen | 1016
+
0
-

setRequired na SelectBoxu defaultně? Dám příklad – dotazníkový formulář kde prostě nějaké otázky vyplňovat nemusíš, ano, šla by tam nastavit defaultně hodnota nebo prompt.
Popřípadě k

array(NULL => '- nevybráno -').

co třeba translator? Připadá mi to celé takové nedomyšlené. A přehnané hlídání programátora.

Editoval pilec (20. 8. 2012 16:25)

nAS
Člen | 277
+
0
-

Možná jsem se nevyjádřil úplně přesně, nejde mi o to, aby bylo defaultně zapnuté setRequired(), ale aby základní chování převzalo vlastnost, která se uplatňuje při zapnutém setRequired(). Pokud bude nastaveno setPromt(), tak to už je z hlediska bezpečnosti vybraná položka, s tím už programátor počítá a to lze považovat za regulérně vybranou položku. setRequired() už nad tím pouze zajišťuje business logiku (musí být vybraná specifická položka, nebo lze odeslat s promt hodnotou?) a toho se můj požadavek netýká.

Jaký je problém s translatorem? Toho se to přece nijak netýká.

Přehnané hlídání programátora? Ty někdy potřebuješ, aby uživatel mohl pomocí FireBugu odeslat z formuláře hodnotu, která není na výběr? Pokud ne, tak bys správně měl všude ošetřovat, že nedostáváš NULL. Opravdu to děláš všude? A není to trochu zbytečné, když se o to může starat framework?

Ondřej Mirtes
Člen | 1536
+
0
-

TL;DR příspěvků nade mnou – SelectBox se při úpravě FireBugem vždy chová, jako kdyby měl nastavené setPrompt, což může způsobit problémy.

Nejmenší zlo by asi bylo, kdyby se takto napadený formulář označil za invalidní a nevolala se onSuccess metoda.

nAS
Člen | 277
+
0
-

Ondřej Mirtes: Přesně tak.

David Grudl
Nette Core | 8218
+
0
-

Vím o tom. Proč není na SelectBoxu nastaveno setRequired() defaultně má jediný důvod: nedala by se pak nastavit vlastní chybová zpráva. setRequired totiž ve skutečnosti volá addRule (tedy je to spíš addRequired), což by chtělo změnit, ale tím pádem už nejde o triviální opravu a proto jsem se k tomu nedostal.

nAS
Člen | 277
+
0
-

A je opravdu potřeba nastavovat vlastní chybová zpráva na událost, ke které nemůže dojít jinak, než že se někdo úmyslně snaží hacknout aplikaci? Podle mě by bohatě stačilo, kdyby byla zpráva přepsatelná v $defaultMessages, takže bude společná pro všechny SelectBoxy v aplikaci.

jtousek
Člen | 951
+
0
-

Raději bych viděl nějaké lepší řešení. Např. doplněk řešící datum potřebuje defaultně validátor, že skutečně jde o validní datum – a ouha, jakou chybovou zprávu? Chtělo by to spíše API pro změnu zprávy již přidaného rule.

nAS
Člen | 277
+
0
-

jtousek: Ale tohle není problém, tak v tom případě tu zprávu bude vyžadovat jako parametr konstruktoru a pak ji předá přímo tomu vytvářenému Rule. Ale přijde mi zbytečné chtít po programátorovi, aby u každého SelectBoxu vypisoval nějakou zprávu, která se stejně nebude v žádném regulerním případě vypisovat.

David Grudl
Nette Core | 8218
+
0
-

K takové situaci dojít může. Pokud mám v selectboxu políčko prompt a uživatel jej nechá vybraný nebo pokud nic nevybere v multiselectu, je prvek považován za nevyplněný.

nAS
Člen | 277
+
0
-

Tak to si asi nerozumíme, já nechci aby bylo vždy zapnuté přesné setRequired(), je regulérní požadavek chtít nepovinný SelectBox, kde může zůstat vybraný Prompt (například filtrovací formulář). To co chci je, aby měl programátor vždy zajištěno, že se mu vrátí pouze hodnota, která je v SelectBoxu (nebo NULL, pokud má SelectBox prompt).

Tedy:

new SelectBox('a', array('first', 'second')); // vždy vrátí 0 nebo 1
new SelectBox('b', array('a' => 'first', 'b' => 'second'))->setPrompt(); // vždy vrátí a, nebo b
new SelectBox('c', array('first', 'b' => 'second'))->setPrompt('select'); // vždy vrátí 0, b, nebo NULL
new SelectBox('d', array('first', 'b' => 'second'))->setPrompt('select')->setRequired(); // vždy vrátí 0, nebo b

V současné implementaci je problém, že:

new SelectBox('a', array('first', 'second')); // může vrátit NULL
paranoiq
Člen | 392
+
0
-

nAS: „úmyslně snaží hacknout aplikaci“

selectbox může být generován z dat a ta se mohou během editace uživatelem změnit. takže hodnota, která byla validní v době vytvoření formuláře už nemusí být validní při jeho zpracování. takže nejen kvůli pokusům o hackování se může vrátit nevalidní hodnota

nAS
Člen | 277
+
0
-

Ano, to je pravda, stejně tak může být deploynuta nová verze aplikace před odesláním formuláře. Ale z mého pohledu jsou to natolik řídké jevy, že bych stejně nevymýšlel nějakou speciální hláškou pro každý SelectBox a nechal bych tam defaultní (také co bys tam chtěl vůbec psát?). Ale proti gustu, klidně může přibýt do konstruktoru SelectBoxu nepovinný parametr pro tuto chybovou zprávu, pokud si ji někdo chce měnit pro každý SelectBox zvlášť.

Ale hlavní je, aby to Nette prostě hlídalo. V tom případě, který píšeš se ti vrátí NULL a aplikace někam uloží špatná data.

paranoiq
Člen | 392
+
0
-

data má validovat především model

nAS
Člen | 277
+
0
-

To bezesporu, ale když už formulář nabízí validování, tak by to měl dělat pořádně. Myslím si, že je v pořádku na základě pravidel v modelu vygenerovat formulář a počítat s tím, že data, která mi vrátí jsou validní. Pokud bys chtěl validovat jenom v modelu, tak můžeme celé formuláře zahodit a posílat $_GET , nebo $_POST rovnou do modelu, což určitě nechceme.

Patrik Votoček
Člen | 2221
+
0
-

Rozumím tomu dobře že chceš aby SelectBox který nemá prompt byl automaticky required?

nAS
Člen | 277
+
0
-

Jojo.

A ještě bych popřemýšlel, jestli by nebylo lepší, aby SelectBox, který má Prompt a je odeslán s neplatnou hodnotou nebyl také spíše označený jako invalidní místo toho aby vrátil NULL. Protože tohle se stane např. když uživatel odešle SelectBox a mezitím deployneme novou verzi aplikace se změněným číselníkem a uživatel odešle úplně jinak vyplněný formulář než chtěl. Jako menší zlo by mi připadalo ho nechat odeslat formulář znovu.