Forms\Controls\SelectBox by neměl vracet NULL
- nAS
- Člen | 277
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
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
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
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.
- David Grudl
- Nette Core | 8218
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
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.
- nAS
- Člen | 277
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
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
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
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
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.
- nAS
- Člen | 277
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
Rozumím tomu dobře že chceš aby SelectBox který nemá prompt byl automaticky required?
- nAS
- Člen | 277
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.