Dotaz na cookies

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

Předem se omlouvám za zřejmě triviální dotaz. Programuju dost nárazově, takže Nette je pro mě ještě stále ne úplně zmapovaná oblast.

Pracuju v Nette poprvé s cookies. Co jsem tak pochopil, tak Nette vyloženě jen obaluje práci s nimi. Představte si hodnocení článků palci nahoru. Chci do cookies uložit pole článků, pro které už uživatel hlasoval.

Mám renderDefault(), který vypíše články, a pak handleHlasuj($id), který zkontroluje cookies, aktualizuje je a případně zapíše hlas do databáze.

Všechno funguje jak má. „Problém“ nastane ve chvíli, kdy si chci cookies dumpnout v renderDefault(). Při prvním načtení stránky mí to vrátí NULL. Pak, když hlasuju pro článek, cookie se vypíše celá. Když přejdu kamkoli, je to zas NULL.

Problém leží nejspíš v mojí neznalosti práce s cookies. Nechápu, proč se do ní nemůžu podívat hned po prvním načtení stránky v renderDefault(). Pro úplnost posílám zdroják, díky za jakékoli rady:

<?php
 public function renderDefault() {

        $request = $this->getHttpRequest();
        $response = $this->getHttpResponse();

        $cookie = json_decode($request->getCookie('hlasovani'), true);
        Debug::dump($this->getHttpRequest()->getCookies());
        Debug::dump($cookie);


    }


    public function handleHlasovat($id) {

        // cookies
        $request = $this->getHttpRequest();
        $response = $this->getHttpResponse();

        $cookie = json_decode($request->getCookie('hlasovani'), true);
        if ($cookie !== null) {
            if (isset($cookie[$id]) && $cookie[$id] == 1) {
                $this->flashMessage('Pro tento clanek už jste hlasoval.');
                $this->redirect('Default:default');
            } else {
                $cookie[$id] = 1;
            }
        } else {
            $cookie = array();
            $cookie[$id] = 1;
        }

        $response->setCookie('hlasovani', json_encode($cookie), 60 * 60 * 24 * 30);

    }
?>
Ondřej Mirtes
Člen | 1536
+
0
-

Na první pohled žádnou chybu nevidím.

Co je ale velká chyba, to je spoléhat se na údaj v cookie. Ten jde samozřejmě podvrhnout/cookie lze smazat, takže uživatel pak může hlasovat donekonečna…

Mně se osvědčila kontrola IP adresy (přidání hlasu a přidružené IP adresy do databáze) a nastavení určité délky expirace toho hlasu (mám nastaven týden). Ano, můžu jedním hlasem odstřihnout hodně lidí, kteří jsou za NATem a jako vnější adresu mají adresu někoho, kdo z té sítě již hlasoval, ale nic spolehlivějšího AFAIK neexistuje. Vlastně jo – povolení hlasování pouze registrovaným (což ale ne všude je žádoucí) a podezřelé registrace blokovat.

Ještě je dobré kontrolovat referer, jestli obsahuje $this->link('//Default:') zamezí to těm situacím, kdy lze hlasování podvrhnout tak, že umístíte link jako obrázek 1×1 na nějaký navštěvovaný web.

Tak mě napadlo, že by se na to dala napsat hezká komponenta :)

Editoval LastHunter (28. 9. 2009 23:14)

Martin Mates
Člen | 179
+
0
-

2LastHunter: Díky za postřehy. To s IP samozřejmě vím. Myšlenka je, dělat to pomocí cookies i podle IP. Možná to nakonec udělám jen podle IP. Nicméně to není až tak důležité. Spíš jsem si chtěl ujasnit některé věci. Proč je ta cookie NULL při načtení stránky? Neměl bych si pro ní už moct sahnout?

David Grudl
Nette Core | 8228
+
0
-

Ona je null, protože ji ukládáš na výstup (tedy do $this->getHttpResponse()) a čteš ze vstupu ($this->getHttpRequest()).

Martin Mates
Člen | 179
+
0
-

David Grudl napsal(a):

Ona je null, protože ji ukládáš na výstup (tedy do $this->getHttpResponse()) a čteš ze vstupu ($this->getHttpRequest()).

Díky Davide. Zeptám se ještě jinak. Proč příkaz Debug::dump($this->getHttpRequest()->getCookie('hlasovani')); vrací NULL v renderDefault ale v handleHlasovat vrátí tu cookie?

Já to moc nechápu. Funkce setCookie a getCookie je jen jedna, jak to můžu volat špatně? Jak to můžu udělat jinak? Jak si pro tu cookie sáhnu v renderDefault? Už si začínám připadat trošku jako negramot :-)

David Grudl
Nette Core | 8228
+
0
-

Funkce getCookie() jsou právěže dvě. Jedna pro vstupní cookies a jedna pro výstupní, obojí na jiném objektu a jiné třídě. Asi by bylo užitečné mít něco jako „aktuální cookies“, tedy mix obojího, ale zatím to neexistuje.

Martin Mates
Člen | 179
+
0
-

David Grudl napsal(a):

Funkce getCookie() jsou právěže dvě. Jedna pro vstupní cookies a jedna pro výstupní, obojí na jiném objektu a jiné třídě. Asi by bylo užitečné mít něco jako „aktuální cookies“, tedy mix obojího, ale zatím to neexistuje.

Já jsem v API zkoušel hledat funkci getCookie(), ale našel jsem jen jednu ve třídě HttpRequest. HttpResponse ji nemá. Která je tedy ta druhá getCookie()?

David Grudl
Nette Core | 8228
+
0
-

Pardon, napsal jsem to blbě, pro výstup je to samozřejmě setCookie(). Klíčové je, že setCookie() na response nesouvisí s getCookie() na requestu.

Martin Mates
Člen | 179
+
0
-

David Grudl napsal(a):

Pardon, napsal jsem to blbě, pro výstup je to samozřejmě setCookie(). Klíčové je, že setCookie() na response nesouvisí s getCookie() na requestu.

Dobře, to chápu, že to spolu nesouvisí a že jsou to úplně jiné objekty. To ale z mého pohledu na věc nevrhá vůbec žádné světlo. Mě není jasné, když mám tu cookie uloženou v prohlížeči už třeba z předchozí návštěvy, proč jí ten příkaz $this->getHttpRequest()->getCookie() nevypíše už v tom renderDefault(). Ta cookie existuje už když se na tu stránku vracím. Možná jsem špatně formuloval ten dotaz na začátku.

Ty jsi mi Davide odpověděl, jako kdyby žádná cookie ještě neexistovala a udělal bych setCookie a pak hned getCookie a divil se, že to vypíše NULL.

Díky moc Davide za reakce. Možná máš pravdu ty, jenom to pořád nevidím.

David Grudl
Nette Core | 8228
+
0
-

Jo aha, chápal jsem to přesně tak – žes udělal setCookie a pak hned getCookie a divil se, že to vypíše NULL ;)

Takže ne? V tom případě bude pes zakopaný někde jinde.

  • pokud používáš coolUri, zkus nastavit v bootstrapu Environment::getHttpResponse()->cookiePath = '/'; respektive cestu k dokument rootu.
  • aby to spolehlivě zafungovalo, bude to chtít smazat všechny cookies v prohlížeči k příslušné doméně.

(ostatně říkám si, že to cookiePath = '/' bych mohl dát jako výchozí… A dám.)

nAS
Člen | 277
+
0
-

David Grudl napsal(a):

(ostatně říkám si, že to cookiePath = '/' bych mohl dát jako výchozí… A dám.)

Nebylo by lepší požít jako výchozí hodnotu Environment::getVariable('baseUri')?

Martin Mates
Člen | 179
+
0
-

David Grudl napsal(a):

Jo aha, chápal jsem to přesně tak – žes udělal setCookie a pak hned getCookie a divil se, že to vypíše NULL ;)

Takže ne? V tom případě bude pes zakopaný někde jinde.

  • pokud používáš coolUri, zkus nastavit v bootstrapu Environment::getHttpResponse()->cookiePath = '/'; respektive cestu k dokument rootu.
  • aby to spolehlivě zafungovalo, bude to chtít smazat všechny cookies v prohlížeči k příslušné doméně.

(ostatně říkám si, že to cookiePath = '/' bych mohl dát jako výchozí… A dám.)

Dostal jsem se k tomu až teď. Díky Davide, funguje to!!!! To by mě nenapadlo.