Jak byste na to šli? (login form – komponenta?)
- Martin Mates
- Člen | 179
Zdravím. Chci se zeptat na docela obecnou věc. Už nějakou dobu se v Nette šťourám, ale jak dělám ještě X jiných věcí, tak postupuju dost pomalu.
Jedná se o to, že bych chtěl mít na stránce vždy nahoře login formulář (nebo místo něj napsáno „jste přihlášen jako…“) a to ve všech možných presenterech či views. Do teď jsem to dělal tak, že jsem měl na login extra presenter a action. Jak byste na to šli?
První, co mě napadlo, bylo, že jsem do BasePresenteru ze kterého všechny ostatní dědí přidal do startup() onen formulář. To funguje tak napůl, jakmile chci vytvořit instanci Identity, tak to hodí chybu
Cannot regenerate session ID after HTTP headers have been sent
Možná je chyba jinde, nevím.
Tak či tak, nevyplatilo by se udělat pro ten login komponentu?
- pmg
- Člen | 372
Cannot regenerate session ID after HTTP headers have been sent
Nejspíš bude problém v mezerách před značkou <?php
v některém ze souborů index.php
, bootstrap.php
nebo v souborech s presentery. Také je možné, že máš někde zapomenuté
dumpovací echo
. Před otevřením session se totiž nesmí
posílat žádný výstup do prohlížeče. Můžeš zkusit
header('MyHeader: test');
aby ses dozvěděl, kde výstup
začíná.
Nevím, jestli už jsem to někde nepsal, ale myslím, že ta hláška by
měla znít after HTTP headers were sent
, protože je to
časová věta.
Tak či tak, nevyplatilo by se udělat pro ten login komponentu?
Deklarovat formulář v BasePresenter
je vcelku legitimní. Ale
z koncepčního hlediska se může stát, že ho nebudeš chtít zobrazit
úplně na každé stránce a deklaraci radši přesuneš jinam. Pak by asi bylo
správnější použít komponentu.
- pmg
- Člen | 372
Vsadíme se? :-)
A nevolal jsi session poprvé až po render fázi, popř. v render
fázi nějaké komponenty? Také je možné, že jsi v některé
z předešlých fází zapomněl dumpovací echo
. :-)
V případech, kdy se k session poprvé přistoupí až při vykreslování, je asi nejjednodušším řešením dát do startupu
$session = Environment::getSession();
if (!$session->isStarted()) {
$session->start();
}
Nicméně ta CSRF protekce nebo Captcha (které session vyžadují) session vytvoří už při definici formuláře, takže Martinův problém toto nevyřeší.
- Martin Mates
- Člen | 179
Šlo mi spíš o to, že jsem formulář vždy definoval v actionLogin a ten to vykreslil na extra stránku. jenže, když to chci mít všude a vykreslovat to v @layout, tak nevím, kam to mám dát. action metoda má svou url a svou šablonu pokud se nepletu. Zkusil jsem form definovat ve startup() v basePresenteru, je to správně? V beforeRender už je asi pozdě ne?
Hází to pořád tu chybu. Žádnou mezeru před PHP znackou nemam.
UZ TO FUNGUJE!! Bylo to mezerou na řádku 33 v jednom presenteru.. normální mezera mezi 2 metodama :-/ Díky kucííí!
Editoval Martin Mates (11. 4. 2009 11:54)
- Martin Mates
- Člen | 179
pmg napsal(a):
BeforeRender
by mělo stačit a je asi lepší. Použil bych to v kombinaci screateComponent
.normální mezera mezi 2 metodama :-/
A nebylo v té mezeře nějaké zapomenuté dumpovací
echo
? :-D Jinak bych si myslel, že je to vtip.
Žádné dumpovací echo tam nebylo, to bych si vsim :-) Je to hodně divný. Píšu v NetBeans 6.5
- Martin Mates
- Člen | 179
Juan napsal(a):
Žádné dumpovací echo tam nebylo, to bych si vsim :-) Je to hodně divný. Píšu v NetBeans 6.5
Jseš si jistej, že to bylo tou mezerou? Pokud to je mezera uvnitř PHP kódu, tak to prostě neni možný :) Nehodil bys sem ten kousek kódu, kde to podle tebe bylo?
<?php
/**
* Users authenticator.
*/
class Auth extends Object implements IAuthenticator
{
/**
* Performs an authentication
* @param array
* @return void
* @throws AuthenticationException
*/
public function authenticate(array $credentials)
{
$username = strtolower($credentials[self::USERNAME]);
$password = strtolower($credentials[self::PASSWORD]);
$row = dibi::select('*')->from('users')->where('login=%s', $username)->fetch();
if (!$row) {
throw new AuthenticationException("Uživatel '$username' nenalezen.", self::IDENTITY_NOT_FOUND);
}
if ($row->heslo !== md5($credentials[self::PASSWORD] . strtolower($credentials[self::USERNAME]))) {
throw new AuthenticationException("Špatné heslo.", self::INVALID_CREDENTIAL);
}
if ($row->potvrzen != 1) {
throw new AuthenticationException("Účet ještě nebyl potvrzen.");
}
unset($row->heslo);
return new Identity($row->login, NULL, $row);
}
/* TADY JSEM ODSTRANIL MEZERU A ZACALO TO FUNGOVAT */
}
?>
Nic jiného jsem neměnil. Když tam tu mezeru dám zpět, tak to jde bez problémů. Debug hlásil Output started at line 33 (nyní už je to 37).. na té řádce nebylo nic, jen tahle mezera (konec řádku), dal jsem to pryč a viola!
- Jan Jakeš
- Člen | 177
Nic jiného jsem neměnil. Když tam tu mezeru dám zpět, tak to jde bez problémů. Debug hlásil Output started at line 33 (nyní už je to 37).. na té řádce nebylo nic, jen tahle mezera (konec řádku), dal jsem to pryč a viola!
No tak že by to bylo mezerou uvnitř PHP kódu, to je vážně nesmysl a i kdyby tam byl nějakej neviditelněj znak, tak se nemůže bez echa vypsat, to by nahlásil chybu syntaxe interpret… Neni možný že si třeba upravil víc věcí a nevšim sis přesně, kdy to začalo fungovat? Ono by to vypsalo tu samou chybu, kdyby např. ten řádek s dibi obsahoval login=%s a řádek s Identity např. $row->username, klidně si to zkus. Např takto:
$row = dibi::select(‚*‘)->from(‚users‘)->where(‚login=%s‘, $username)->fetch();
return new Identity($row->username, NULL, $row);
Protože u $row->username ti nějaká funkce vypíše chybu, že username není definováno (protože výše bylo uvedeno uveden akorát název login), no a výpis té chyby způsobí, že nelze regenerovat session, protože už bylo cosi vypsáno… Ten výpis ty ale nejspíš nevidíš, protože je pohlcen laděnkou. Např. ve Firebugu ho ale vidět můžeš…