Overenie Username a Emailu či už existujú v Db ANEB Pokus o registráciu!

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

Zdravím…
Takže som dal ako tak dokopy registráciu užívateľa vychádzal som s examples CD-Collection!
prosím všetkých kompetentných o kontrolu a čo by som mal tak asi zmeniť…
Ako mne to podstatne funguje ale tak človek si nie je na 100% istí

Takže môj UserRepository

<?php

class UserRepository extends Nette\Object
{
	/** @var Nette\Database\Connection */
	private $database;

	public function __construct(Nette\Database\Connection $database)
	{
		$this->database = $database;
	}

	public function findAll()
	{
		return $this->database->table('users');
	}

	public function findById($uid)
	{
		return $this->findAll()->get($uid);
	}

	public function insert($values)
	{
		return $this->findAll()->insert($values);
	}

	public function userexists($uname)
	{
		return $this->findAll()->select('uname')->where('uname', $_POST['uname'])->fetch();
		if($this->users->userexists('uname'))
		{
			echo 'Existuje';
		} else {
			echo 'Je Voľné';
		}
		return $this->users->userexists($uname);
	}
	public function usermailexists($umail)
	{
		return $this->findAll()->select('umail')->where('umail', $_POST['umail'])->fetch();
		if($this->users->userexists('umail'))
		{
			echo 'Existuje';
		} else {
			echo 'Je Voľné';
		}
		return $this->users->usermailexists($umail);
	}

}

Môj UserPresenter

<?php
namespace FrontModule;

use Nette\Application\Ui\Form,
    Nette\Utils\Html,
    Country,
    DatePicker,
    UserRepository;

class UserPresenter extends \BasePresenter
{
	/** @var UserRepository */
	private $users;

	public function inject(UserRepository $users)
	{
		$this->users = $users;
	}

	protected function createComponentUserRegisterForm()
	{
		$form = new Form;
		$form->addText('uname', 'Užívateľské meno:')
		     ->setRequired('Prezývka je povinná!');
		$form->addText('umail', 'Emailová adresa:')
		     ->setRequired('Email je povinný!')
		     ->addRule(Form::EMAIL, 'Zadajte prosím, platnú emailovú adresu!');
		$form->addPassword('upass', 'Heslo:')
		     ->setRequired('Heslo je povinné!')
		     ->addRule(Form::MIN_LENGTH, 'Heslo musí obsahovať min. %d znaky', 4);
		$sex = array('m' => 'Muž','f' => 'Žena',);
		$form->addRadioList('ugender', 'Pohlavie:', $sex)
		     ->setRequired()
		     ->getSeparatorPrototype()->setName(NULL);
		$form->addDatePicker('birthDate', 'Dátum Narodenia:')
    		 ->setAttribute('class', 'birthDate')
    		 ->addRule(Form::VALID, 'Entered birth date is not valid!');
		$ucountries = $this->CountryList();
		$prompt = Html::el('option')->setText('Vyberte Krajinu')->class('prompt');
		$form->addSelect('ucountry', 'Krajina:', $ucountries)
		     ->setPrompt($prompt)
		     ->setRequired();
		$form->addCheckBox('uagree', Html::el('span')
			 ->setHtml('Súhlasím s <a href="../docs/Terms" target="_blank">Podmienkamy</a>')) // Html form
		     ->addRule(Form::EQUAL, 'Musíte súhlasiť s podmienkamy!', TRUE);
		$form->addSubmit('uregme', 'Registrovať')
		     ->onClick[] = $this->UserSuccessRegisterSubmitted;
		$form->addProtection();
		return $form;
	}

	public function UserSuccessRegisterSubmitted($button)
	{
		try{
			$values = $button->getForm()->getValues();
			if($this->users->userexists('uname'))
			{
				$this->presenter->flashMessage("Užívateľské meno:" . " | " . $_POST['uname'] . " | " . "už Existuje!");
			} else {
				$this->presenter->flashMessage("Hurá užívateľské meno:" . " | " . $_POST['uname'] . " | " . "je voľné!");
			}
			/******** @return Email Exists */
			if($this->users->usermailexists('umail'))
			{
				$this->presenter->flashMessage("Emailová adresa:" . " | " . $_POST['umail'] . " | " . "je v systéme zaregistrovaná");
			} else {
				$this->presenter->flashMessage("Hurá emailová adresa:" . " | " . $_POST['umail'] . " | " . "nie je v systéme zaregistrovaná");
			}
		} catch(Nette\Security\AuthenticationException $e) {
			 $form->addError($e->getMessage());
		}
	}
}

Viem, že som tam veľa veci dokafral preto Vás prosím o upresnenie čo sa týka Nette Dokumentácie,Planette a Fóra stále to študuje ale rád sa púšta do riešenia sám aby som vydel chyby a precvičoval sa no vy ty SKÚSENEJŠÍ to máte v malíčku pre Vás pozrieť na to a ohodnotiť to nie je žiaden problém…

Všetkým samozrejme vopre ďakujem.

Editoval SontoEremo (25. 3. 2013 21:55)

Draffix
Člen | 146
+
0
-

A funguje ti to? To je podstatná otázka. Nicméně mám dvě výtky:

  1. postovací hodnoty bych určitě nebral způsobem $_POST[‚uname‘] z důvodu validace escapování.
  2. to ověřování emailu a jména v modelu se mi nezdá. Mělo by to být ve smyslu, že pokud existuje záznam, pak vrátím záznam, jinak např. do proměnné uložím že neexistuje. I to bych ale přesunul do presenteru, protože zde by měla probíhat aplikační logika a model by měl sloužit jen jako nástroj pro výběr dat v tomto případě.

Metoda serSuccessRegisterSubmitted je totálně špatně. Doporučuji si přečíst dokumentaci o formulářích

David Matějka
Moderator | 6445
+
0
-
  1. jak pise @Draffix, nikdy nesahej na $_POST (ani $_GET) .. (btw. co kdyby je nette unsetnulo? :D)
  2. nejdriv jsem se lek
public function userexists($uname)
   {
       return $this->findAll()->select('uname')->where('uname', $_POST['uname'])->fetch();
       if($this->users->userexists('uname'))
       {
           echo 'Existuje';
       } else {
           echo 'Je Voľné';
       }
       return $this->users->userexists($uname);
   }

ale on je tam hned na prvnim radku return, tak ten zbytek smaz, at nevystrasis nekoho dalsiho :D (to same v usermailexists)

3. proc tam v tom repository sahas na $_POST, kdyz mas ten email/jmeno v parametru?

4. nenavazuj udalost na

$form->addSubmit('uregme', 'Registrovať')
             ->onClick[] = $this->UserSuccessRegisterSubmitted;

ale na $form->onSuccess[] = ...

5. overeni existence emailu (a jmena) muzes pouzit pres addRule, napr takhle:

$userRepository = $this->userRepository;
$form->addText('email', 'E-mail')->addRule(function($input) use($userRepository) {
	return !$userRepository->usermailexists($input->value);
}, 'Tento email jiz nekdo pouziva!');

6. pokud uz budes neco overovat az v onSuccess metode, tak tu chybu nezobrazuj pres flashMessage, ale pridej ji do formu $form->addError('....')

7. v presenteru nemusis pouzivat $this->presenter->flashMessage(), staci $this->flashMessage()

SontoEremo
Člen | 341
+
0
-

Jaaa to asi vzdám s Nette absolútne tomu nedokážem prísť na rozum :) už sa stým hrám skoro mesiac a ešte som nedokázal vytvoriť ani len obyčajnú registráciu užívateľa dokonca ani login a dokonca ani neviem kam čo mám umiestniť čo kam patrí apod. viem je to na smiech ale fakt sa snažím no aj tu čo mi pred chvíľou odp. matej21

$userRepository = $this->userRepository;
$form->addText('email', 'E-mail')->addRule(function($input) use($userRepository) {
    return !$userRepository->usermailexists($input->value);
}, 'Tento email jiz nekdo pouziva!');

Kam to mám umiestniť? neviem tak som to pacol sem:

$form->addText('umail', 'Emailová adresa:') // umail as email
		     ->addRule(function($input) use($userRepository )
		     {
    			return !$userRepository->usermailexists($input->value);
			 }, 'Tento email jiz nekdo pouziva!')
		     ->setRequired('Email je povinný!')
		     ->addRule(Form::EMAIL, 'Zadajte prosím, platnú emailovú adresu!'); input

Alebo aj toto:

6. pokud uz budes neco overovat az v onSuccess metode, tak tu chybu nezobrazuj pres flashMessage, ale pridej ji do formu $form->addError('')

Tak som to dal takto

public function UserSuccessRegisterSubmitted(Form $form)
	{
		try{

			$values = $form->getValues();
			$this->users->insert($values);

		} catch(Nette\Security\AuthenticationException $e) {
			 $form->addError($e->getMessage());
			return;
		}

	}

Nič žiadne, že email už existuje proste zapíše do DB a hotovo!

Dokumentáciu,fórum a Planette stále dookola čítam a robím podľa nej všetko je ok ale akonáhle niečo sám som ako na opustenom ostrove… :)
Ako tu toto fórum číslo 1 nápomocné a ochotné no nebaví ma sa ustavične pýtať hlúpe veci či to mám dobre ako to a ako hento…
škoda, že nie je viac video tutoriálov napr. Registrácia/Prihlásenie/Odhlásenie atď…
Možno sa to časom naplní ale fakt už neviem či som vekom osprostel :) alebo ja neviem, že nedokážem zachytiť pointu tohto skvelého a asi aj najlepšieho Frameworku…

P.S: Nerobí niekto náhodou za pár € doučovanie v na SK okolie Nitra?
rád by som sa zaúčal :) FAKT!

David Matějka
Moderator | 6445
+
0
-

umisteny je to v podstate dobre, jen to dej jako posledni validacni pravidlo, vyhodnocujou se postupne, takze je zbytecny overovat, zda existuje email, pokud nebyl vyplnen, tedy:

$form->addText('umail', 'Emailová adresa:') // umail as email

             ->setRequired('Email je povinný!')
             ->addRule(Form::EMAIL, 'Zadajte prosím, platnú emailovú adresu!')
             ->addRule(function($input) use($userRepository )
             {
                return !$userRepository->usermailexists($input->value);
             }, 'Tento email jiz nekdo pouziva!');

to ale nevysvetluje, proc dojde k zapisu (zavolani ty metody UserSuccessRegisterSubmitted).. bud je nejaka chyba v modelu (v metode usermailexists) nebo nevim :)

jinak ta metoda pro zpracovani formu staci takhle:

public function UserSuccessRegisterSubmitted(Form $form)
    {
            $values = $form->getValues();
            $this->users->insert($values);
    }

ten try-catch blok tam byl jen v login formu, kde metoda $user->login mohla vyhodit vyjimku AuthenticationException, coz se tady stat nemuze

tak se koukni, jestli je dobre napsana ta metoda v modelu a jestli se treba provede odpovidajici sql dotaz.

jiri.pudil
Nette Blogger | 1032
+
0
-

Nebylo by lepší mít na příslušném sloupci v DB unikátní klíč? Tak se ti o kontrolu duplicity postará databáze a ty jen ve zpracování zachytíš výjimku s příslušným kódem:

public function UserSuccessRegisterSubmitted(Form $form)
{
	try {
		$values = $form->getValues();
		$this->users->insert($values);
		$this->flashMessage(...);
		$this->redirect(...);
	} catch (\PDOException $e) {
		if ($e->getCode() === 23000) {
			// pokud je chyba v duplicitě klíče, přidáme chybu do formu
			$form->addError(...);
		} else {
			// pokud jde o jinou chybu, necháme ji probublat výš
			throw $e;
		}
	}
}

Pak se obejdeš bez vlastního validačního pravidla.

Draffix
Člen | 146
+
0
-

Myslím si, že pokud si člověk neumí udělat ani jednoduchý formulář na registraci/přihlášení, tak něco jako výjimky pro něj budou ještě větší neznámá… Ale tak třeba se mýlím.

SontoEremo
Člen | 341
+
0
-

Ďakujem Vám všetkým za odpovede a za pomoc…
Poskladal som to takto dokopy a funguje zatiaľ ako má!
Prosím Vás mohli by ste to prekontrolovať? Vopred Ďakujem…
Môj UserRepository:
Chyba bola v tom, že za ->where(‚umail‘) som mal ešte dosadiť ,$umail asi takto

return $this->findAll()->select('umail')->where('umail', $umail)->fetch();

Keď som to tam dosadil začalo to vyhadzovať tie hlášky a nekonal sa žiadny zápis až som zmenil mail a potom sa pekne zapísalo do DB a zároveň vykonalo aj redirect

<?php
/**
 * Tabulka user
 */
class UserRepository extends Nette\Object
{
	/** @var Nette\Database\Connection */
	private $database;

	public function __construct(Nette\Database\Connection $database)
	{
		$this->database = $database;
	}

	public function findAll()
	{
		return $this->database->table('users');
	}

	public function findById($uid)
	{
		return $this->findAll()->get($uid);
	}

	public function insert($values)
	{
		return $this->findAll()->insert($values);
	}

	public function userexists($uname)
	{
		return $this->findAll()->select('uname')->where('uname', $uname)->fetch();
	}
	public function usermailexists($umail)
	{
		return $this->findAll()->select('umail')->where('umail', $umail)->fetch();
	}

}

Ešte priložím môj UserPresenter

<?php
namespace FrontModule;

use Nette\Application\Ui\Form,
    Nette\Utils\Html,
    Country,
    DatePicker,
    UserRepository;

class UserPresenter extends \BasePresenter
{
	/** @var UserRepository */
	private $users;

	public function inject(UserRepository $users)
	{
		$this->users = $users;
	}

	protected function createComponentUserRegisterForm()
	{
		$userRepository  = $this->users;

		$form = new Form;

		$form->addText('uname', 'Užívateľské meno:')
		     ->setRequired('Prezývka je povinná!')
		     ->addRule(function($input) use($userRepository)
		     {
		     	return !$userRepository->userexists($input->value);
		     }, 'Toto užívateľské meno je obsadené prosím vyberte si iné!');

		$form->addText('umail', 'Emailová adresa:')
		     ->setRequired('Email je povinný!')
		     ->addRule(Form::EMAIL, 'Zadajte prosím, platnú emailovú adresu!')
		     ->addRule(function($input) use($userRepository)
		     {
    			return !$userRepository->usermailexists($input->value);
			 }, 'Táto emailová adresa je už v systéme zaregistrovaná!');

		$form->addPassword('upass', 'Heslo:')
		     ->setRequired('Heslo je povinné!')
		     ->addRule(Form::MIN_LENGTH, 'Heslo musí obsahovať min. %d znaky', 4);

		$sex = array('m' => 'Muž','f' => 'Žena',);
		$form->addRadioList('ugender', 'Pohlavie:', $sex)
		     ->setRequired()
		     ->getSeparatorPrototype()->setName(NULL);

		$form->addDatePicker('birthDate', 'Dátum Narodenia:')
    		 ->setAttribute('class', 'birthDate')
    		 ->addRule(Form::VALID, 'Entered birth date is not valid!');

		$ucountries = $this->CountryList();
		$prompt = Html::el('option')->setText('Vyberte Krajinu')->class('prompt');
		$form->addSelect('ucountry', 'Krajina:', $ucountries)
		     ->setPrompt($prompt)
		     ->setRequired();

		$form->addCheckBox('uagree', Html::el('span')
			 ->setHtml('Súhlasím s <a href="../docs/Terms" target="_blank">Podmienkamy</a>'))
		     ->addRule(Form::EQUAL, 'Musíte súhlasiť s podmienkamy!', TRUE);

		$form->addSubmit('uregme', 'Registrovať');
		 $form->onSuccess[] = $this->UserSuccessRegisterSubmitted;

		$form->addProtection();

		return $form;
	}

	public function UserSuccessRegisterSubmitted(Form $form)
	{
		//$values = $form->getValues();
		//$this->users->insert($values);
		try {
				$values = $form->getValues();
				$this->users->insert($values);
				$this->flashMessage(....);
				$this->redirect('Index:index');
		} catch (Nette\Security\AuthenticationException $e) {
			if ($e->getCode() === 23000) {
				// pokud je chyba v duplicitě klíče, přidáme chybu do formu
				$form->addError(...);
			} else {
				// pokud jde o jinou chybu, necháme ji probublat výš
			throw $e;
			}
		}
	}
}

Tak to s Nette teda skúsim odznova Možno, že o pár mesiacov ba i týždňov sa budem tomu smiať čo som sa tu pýtal a aké chyby som robil … No nejak sa to naučiť človek musí! Ďakujem Chalani…

jiri.pudil
Nette Blogger | 1032
+
0
-

Teď to try-catch můžeš vyhodit a nechat ve zpracování jen:

$values = $form->getValues();
$this->users->insert($values);
$this->flashMessage(....);
$this->redirect('Index:index');

protože duplicitu si ověřuješ sám.

SontoEremo
Člen | 341
+
0
-

Ešte som sa chcel spýtať ako riešite pri registrácii zabezpečenie a zahashovanie hesla? v presentery? niečo ako calculateHash ? v Sandboxe?

Draffix
Člen | 146
+
0
-

Bezpečnost je kapitola sama o sobě. Nicméně určitě bych to řešil nějakým hashovacím algoritmem, na netu jich najdeš mraky. Jinak opět ze šablony (resp. view) získáš heslo, v presenteru ho zahashuješ podle tebou vybraného kryptu a přes model ho do databáze uložíš. Tedy stejný princip jako máš ty teď, jen přidáš hash navíc. Taková vhodná třída pro ukázku je např. Authenticator, více se o ní dozvíš tady a snad to lépe pochopíš.

David Matějka
Moderator | 6445
+
0
-

k ukladani hesel: http://www.michalspacek.cz/…profit-devel

ke kazdymu heslu pouzij jinej salt, pouzi alespon sha256 (nejlepe vsak bcrypt (resp. crypt)), jak je na tech slajdech

SontoEremo
Člen | 341
+
0
-

Ešte naposledy obnovím túto tému…

Takže vytvoril som si
PassHash

<?php
use Nette\Utils\Strings;

class PassHash extends Nette\Object
{
	public static function passwordHasher($password, $salt = null)
	{
    	if ($salt === null)
    	{
        	$salt = '$2a$07$' . Strings::random(22);
    	}
    	return crypt($password, $salt);
    }
}

A toto mám v UserPresentery

<?php
namespace FrontModule;

use Nette\Application\Ui\Form,
    Nette\Utils\Html,
    Country,
    DatePicker,
    UserRepository,
    PassHash;

class UserPresenter extends \BasePresenter
{
	/** @var UserRepository */
	private $users;
	/** @var PassHash */
	private $salt;

	public function inject(UserRepository $users)
	{
		$this->users = $users;
	}

	public function injectpasswordHasher(PassHash $salt)
	{
		$this->salt = $salt;
	}

	protected function createComponentUserRegisterForm()
	{
		$userRepository  = $this->users;


		$form = new Form;

		$form->addText('uname', 'Užívateľské meno:')
		     ->setRequired('Prezývka je povinná!')
		     ->addRule(function($input) use($userRepository)
		     {
		     	return !$userRepository->userexists($input->value);
		     }, 'Toto užívateľské meno je obsadené prosím vyberte si iné!');

		$form->addText('umail', 'Emailová adresa:')
		     ->setRequired('Email je povinný!')
		     ->addRule(Form::EMAIL, 'Zadajte prosím, platnú emailovú adresu!')
		     ->addRule(function($input) use($userRepository)
		     {
    			return !$userRepository->usermailexists($input->value);
			 }, 'Táto emailová adresa je už v systéme zaregistrovaná!');

		$form->addPassword('password', 'Heslo:')
		     ->setRequired('Heslo je povinné!')
		     ->addRule(Form::MIN_LENGTH, 'Heslo musí obsahovať min. %d znaky', 4);

		$sex = array('m' => 'Muž','f' => 'Žena',);
		$form->addRadioList('ugender', 'Pohlavie:', $sex)
		     ->setRequired() // Rules is gender checked?
		     ->getSeparatorPrototype()->setName(NULL);
		$form->addDatePicker('birthDate', 'Dátum Narodenia:')
    		 ->setAttribute('class', 'birthDate')
    		 ->addRule(Form::VALID, 'Entered birth date is not valid!');

		$ucountries = $this->CountryList();
		$prompt = Html::el('option')->setText('Vyberte Krajinu')->class('prompt');
		$form->addSelect('ucountry', 'Krajina:', $ucountries)
		     ->setPrompt($prompt)
		     ->setRequired();

		$form->addCheckBox('uagree', Html::el('span')
			 ->setHtml('Súhlasím s <a href="../docs/Terms" target="_blank">Podmienkamy</a>'))
		     ->setDefaultValue(TRUE)
		     ->addRule(Form::EQUAL, 'Musíte súhlasiť s podmienkamy!', TRUE);

		$form->addSubmit('uregme', 'Registrovať');
		 $form->onSuccess[] = $this->UserSuccessRegisterSubmitted;

		$form->addProtection();

		return $form;
	}

	public function UserSuccessRegisterSubmitted(Form $form)
	{
		$values = $form->getValues();
		$this->salt->passwordHasher($values->password);
		dump($values);
		//$this->users->insert($values);
		//$this->flashMessage('Čo sa deje?');
		//$this->redirect('Index:index');
		/*if ($e->getCode() === 23000) {
			//pokud je chyba v duplicitě klíče, přidáme chybu do formu
			$form->addError('Chyba');
		} else {
			 //pokud jde o jinou chybu, necháme ji probublat výš
			throw $e;

		}
		*/
	}
}

Všetko funguje ok až na to že nič nehashuje :)
Čo zas ja hlavaMaková robím zle?
Prešiel som 7× Přihlašování uživatelů->Authenticator podľa odkazu od Draffix neprišiel som na to :)
Sorry posledná žiadosť o pomoc s reg.

David Matějka
Moderator | 6445
+
0
-

kde si zjistil ze to nic nehashuje? mam ten kod brat doslovne, ze jsi to zjistil dle dump($values);? v tom bude samozrejme heslo v plaintextu, ten hash je navratova hodnota te fce passwordHasher

jo a kdyz tu funkci passwordHasher pouzivas nestaticky, tak u ni nemej to slovo static :)

Editoval matej21 (27. 3. 2013 0:26)

SontoEremo
Člen | 341
+
0
-

matej21 napsal(a):

kde si zjistil ze to nic nehashuje? mam ten kod brat doslovne, ze jsi to zjistil dle dump($values);? v tom bude samozrejme heslo v plaintextu, ten hash je navratova hodnota te fce passwordHasher

jo a kdyz tu funkci passwordHasher pozivas nestaticky, tak u ni nemej to slovo static :)

Pri zápise do DB stále to bolo len 123456
Nie dump to som iba len skúšal …

David Matějka
Moderator | 6445
+
0
-

no ale ty tam nic nedelas s tim vysledkem s passwordHasher.. treba tohle:

$values->password = $this->salt->passwordHasher($values->password);
SontoEremo
Člen | 341
+
0
-

matej21 napsal(a):

no ale ty tam nic nedelas s tim vysledkem s passwordHasher.. treba tohle:

$values->password = $this->salt->passwordHasher($values->password);

Ježiši ja HlavaDubová…
Opravma! ak som to správne pochopil…

políčko->password sa rovná toto zahashuj pomocou passwordHasera(kde políčko->je password);
Draffix
Člen | 146
+
0
-

Až na to že se to nerovná, ale znamená to, že poli $values do klíče password (viz $values->password) přiřadíš zahashované heslo.

spaze
Generous Backer | 28
+
0
-

SontoEremo napsal(a):

	$salt = '$2a$07$' . Strings::random(22);

Salt začínající na $2a$ nepoužívej. Použij $2y$, pokud máš PHP novější, než 5.3.7 (a to asi máš). A pokud chceš jednodušší hashování a ověřování, tak použij balíček https://github.com/…word_compat/ – dodá funkce password_hash() a password_verify() z PHP 5.5 i do starších verzí.