Předání akce a objektu
Školení, která pořádám
Pro vzájemné propojení souborů doporučuji vyhnout se jednomu centrálnímu skriptu a raději pro každou akci vytvořit vlastní skript. Co když ale aplikace řídící skript vyžaduje (třeba proto, že to má ve svém zadání), jak potom bude vypadat URL?
akce.php?objekt=objekt
(tradiční řešení)
?akce=akce&objekt=objekt
(řídící skript)
?akce=objekt
(řídící skript úsporněji)
Třetí způsob neumožňuje provádět kód jako include basename($_GET["akce"]) . ".inc.php"
, zase ale vytváří elegantnější URL. Při využití mod_rewrite se všechny tři způsoby mohou samozřejmě tvářit třeba jako akce/objekt
, tento modul ale není vždy k dispozici.
Diskuse
>tvářit třeba jako akce/objekt, tento modul ale není vždy k dispozici.
Proč? :D
Tenhle tip bych ocenil někdy před lety. Dneska se snad už takhle nepíše. Akce a controller by měly být součástí URL
Vezměme si projekt, který má běžet všude, musí mít triviální konfiguraci (nejlépe žádnou) a musí být snadno instalovatelný (nejlépe zkopírováním jediného souboru). Pro takové projekty se tento postup hodí.
Takto jednoduchý skript se dá napadnout mnoha útoky, takže mě překvapuje, že u Vás se něco takového najde.
Sice přesně nepopisujete, o jakém skriptu mluvíte, ale mohl byste ty útoky popsat?
Tip: $_SERVER['QUERY_STRING'] ve většině případů obsahuje řetězec za otazníkem. Dále lze projít $_GET pole foreach($_GET as $klic => $hodnota){}, ale nebude tam proměnná GLOBALS a nějak divně to croupe chaos v [] - více viz manuál. ;)
kozotoč:
<?php include basename($_GET["akce"]) . ".inc.php"; ?>
opravte mě jestli se mýlím, ale když někdo podvrhne parametr akce, který se neshoduje s žádným jménem souboru, tak to skončí výpisem chybové hlášky do stránky.
Chybu to samozřejmě způsobí. Jestli se vypíše do stránky, určí direktiva display_errors. Ve skutečném kódu by to nejspíš bylo obalené nějakým <?php if (file_exists()) ?>.
kozotoč:
... to se může stát i když to tam do URL někdo napíše ručně a zmýlí se ve velikosti písmen. To asi není moc košér, takhle lehce připustit, že můžu na stránce vidět chybu PHP?
Zobrazování chyb je lepší vypnout v konfiguraci a některými druhy chyb se nezatěžovat. Co asi způsobí kód <?php htmlspecialchars($_GET["query"]) ?>, když v URL přijde query[]=? Chybu, kterou podle mě nestojí za to ošetřovat.
Přesně tak... protože IsSetit jenom kvůli ošetření prázdného indexu - kdysi jsem tomu podlehl a ošetřoval jsem to - ale je to cesta do pekel...
No jak u čeho. Psal jsem nedávno modul pro registrace předmětů a bez E_NOTICE bych se zbláznil. Prostě spoustu věcí mám v polích a každý překlep nebo neošetřený stav pěkně bolí.
Ano, E_NOTICE jsou ty nejdůležitější chyby v PHP. Během vývoje je měním na Exception a nechávám shodit aplikaci. V ostrém provozu je loguju a pečlivě analyzuju. Potlačování chyb E_NOTICE nebo E_WARNING je projevem amaterismu. Howgh ;)
Potlačování - samo až na ostrém serveru, vypnout si to při ladění; na to bych musel mít opravdu speciální náladu =) Ale co např. prázdný index? (myslím tím právě <?php $x = $_GET["index"]; ?> ), ošetřujete to někdo? (pokud se nepletu, generuje to jen neškodnou NOTICE, která by ale eventuelně škodila na ostrém serveru.
Ondrej Ivanic:
Ja ano, asi takto to zvyknem robit:
$id = Request::getInt('id');
$options = Request::getArray('options');
Request bola staticka trieda so zopar metodami a wrapovala pristup k _GET, _POST, _REQUEST, _COOKIES, _SESSION. Metody getxxx mohli mat validaciu (::setValidator('id', new ValidateIntMinMax($min, $max)) a default hodnotu (::getInt($name [, $default = null]))
Ta trieda sa transparentne starala o vsetok bordel ohladom magic_quotes, ...
a naprosto zbytečná =) Je-li i tak kód dobře interpretován, proč e_warning nebo e_notice (teď nevím) nepotlačit...
Je třeba volit kompromis, dle zkušeností zvažovat, kde je ještě dobré počítat s možnou chybou. Jistě je nutné ošetřovat takové stavy, v nichž skript není schopný dokončit akci správně.
Záleží taky na tom, o jakou část aplikace jde. Pokud je web složen z aplikačního jádra a "modulů", pak se mi osvědčilo zachycovat jádrem veškeré chyby, varování, notices, a potom s nimi dobře naložit (logovat, poslat mailem, ...). Zkrátka použít vlastní error handler - výborná věc. Moduly a jakékoli narychlo psané doplňky už můžou počítat s jakýmsi ideálním stavem a neošetřovat každou prkotinu, protože jádro vše zachytí.
Co se týče velikosti písmen při includování "akčního" skriptu, lze jednoduše název akce převést fcí strtolower() a skripty pojmenovávat malými písmeny. V tom nevidím nic prasáckého.
Lepší je v takovém případě přesměrovat na správné URL, protože vyhledávače a prohlížeče různou velikost písmen v URL považují za různé URL. Nicméně já bych takový případ asi neošetřoval vůbec a zobrazil standardní chybovou stránku.
Ondrej Ivanic:
Mama radsej jeden centralny skript v style
index.php?action=...¶m=...
Kde som najprv zacinal s includovanim suboru ($action.".php") zo spravneho adresaru, potom sa action zmenilo na class.method pripadne /class/method s mod_revrite a potom to uz bol len krok k MVC.
Za ten cas co som pouzival toto riesenie som prisiel na nasledovne vyhody:
- lahsia reorganizacia adresarovej struktury aplikacie, ci uz URL, alebo adresarov
- nuti rozmyslat nad mudularnostou aplikacie. Lepsie je mat viac centralnych skritov ako jeden (aplikacia, admin rozhranie, prepojenie na externe zdroje (XML RPC), ...)
Nevyhody:
- treba vediet zopar veci o bezpecnosti a nie len tak bezhlavo includovat (realpath(), open basedir, ...)
- pokial centralny skript robi aj ine veci ako je forward requestov treba vacsiu koordinaciu developerov
Ja to mam taky takhle raději. Ten hlavní skript připravuje vše pro ostatní skripty (moduly), které většinou spouštím přes output buffer. Když modul vrátí chybu tak jen vypíšu pole error_msgs. Vyjímky nepoužívám.
Jednotlivými skripty se dá udělat něco podobného. Ale hrozně nerad duplikuji kód a i to require a volání stejných funkcí na začátku a na konci by mi vadilo.
> Třetí způsob neumožňuje provádět kód jako include basename($_GET["akce"]) . ".inc.php"
Umožňuje (vím že to víš):
list($akce,$objekt) = each($_GET);
Ovšem jen za předpokladu, že bude dvojice akce=objekt vždy na prvním místě dotazu.
Začal jsem používat čtvrtý způsob, adresa vypadá:
cokoliv.php?nazevScriptu
prostě první parametr v adrese je vždycky název stránky kterou volám, správnost validuji podle arraye, kde klíče jsou názvy které očekávám z get a hodnoty jsou názvy funkcí, cesty ke scriptum, ... z te array taky generuji samotné menu. ale je to vhodné pro malé věci nebo (hlavně) pro administrační rozhraní.
Megaloman:
Já naopak doporučuji se vyhnout NEcentrálnímu řídícímu skriptu... samozřejmě jen, když člověk ví, co dělá, jinak napáchá více škody, než užitku.
A co třeba přístup, který se bude líbit MVC routeru:
index.php?model=produkt&view=html&controller=zobrazit&default_parameter=zahradni_zidle
S dobře nastavenými mod_rewrite rules pak budou odkazy vypadat například takto:
www.example.com/produkt/zobrazit/zahradni_zidle.html
Ve skriptu pak je
<?php
require $controller . '.php';
require $model . '.php';
require $view . '.php';
?>
nebo
<?php
$model = new $model();
$view = new $view();
$controller = new $view($default_parameter, $model, $view);
?>
Diskuse je zrušena z důvodu spamu.