You cannot serialize or unserialize PDO instances
- Reka
- Member | 19
Hello,
I am unable to understand what is something wrong with my authentification script.
I have followed this documentation,
but it returns the same error whatever I do, for the line
$user->login($username, $password);
.
The error is : “PDOException – You cannot serialize or unserialize PDO
instances”
Here is my whole code :
<?php
namespace App\Presenters;
use Nette,
App\Forms\SignFormFactory,
App\Presenters\Passwords,
Nette\Application\UI\Form,
Nette\Database\Connection,
Nette\Security as NS;
class ConnexionPresenter extends BasePresenter
{
/** @var User */
public $user;
/** @var SignFormFactory @inject */
public $factory;
/** @var Nette\Database\Context */
private $database;
public function __construct(Nette\Database\Context $database)
{
$this->database = $database;
}
/* public function __construct(Nette\Database\Context $database, User $user)
{
$this->database = $database;
$this->user = $user;
}
*/
protected function createComponentConnexionFormulaire()
{
$form = new Form;
$form->addText('identifiant', 'Identifiant :')
->setRequired('Type your nickname or email address.')
->setAttribute('placeholder', 'Pseudonyme ou E-mail');
$form->addPassword('password', 'Mot de passe :')
->setRequired('Type your password.')
->setAttribute('placeholder', 'Mot de passe');
$form->addSubmit('send', 'Connexion');
$form->onSuccess[] = array($this, 'connexionFormulaireSucces');
$renderer = $form->getRenderer();
$renderer->wrappers['controls']['container'] = NULL;
$renderer->wrappers['pair']['container'] = NULL;
$renderer->wrappers['label']['container'] = NULL;
$renderer->wrappers['control']['container'] = NULL;
return $form;
}
public function connexionFormulaireSucces($form, $values)
{
$identifiant = strip_tags(trim($values->identifiant));
$mdp = trim($values->password);
$is_membre = $this->database->table('membres')->where('nick = ? OR email = ?', $identifiant, $identifiant)->fetch();
$user = $this->getUser() ;
dump($user->login($identifiant, $mdp)); // PDO exception
echo $user->isLoggedIn() ? 'yes' : 'no';
die(dump($is_membre->isLoggedIn() ? 'yes' : 'no'));
if($is_membre !== FALSE) {
if($is_membre->activation === 1) {
if(!NS\Passwords::verify($mdp, $is_membre->password)) {
$this->flashMessage('Nickname or password is wrong.', 'failure');
} else {
$this->flashMessage('OK.', 'success');
$user = $this->getUser();
$user->login($is_membre->nick, $mdp); // PDO exception
echo $user->isLoggedIn() ? 'yes' : 'no';
}
} else {
$this->flashMessage('A mail was sent to you to confirm your subscription, please check your inbox.', 'failure');
}
} else {
$this->flashMessage('You are not subscribed', 'failure');
}
}
}
Furthermore, I changed the table name and column name under app/model/UserManager (adaptation to my DB reality), but it still go wrong.
Initially, I did all the work by myself (the reason why my code seems """a little bit""" redundant), but if I want to use Oauth and social network connexion it will be complicated. I try to understand the simple way suggested by Nette, but it is more difficult than I thought.
Could you help me, please ?
Thanks in advance.
Last edited by Reka (2015-12-06 21:38)
- Reka
- Member | 19
Hello Greeny,
Where? which line is concerned?
Like this? :/ (completely unsure to understand you…) :
if(!NS\Passwords::verify($mdp, $is_membre->password)) {
$this->flashMessage('Vos identifiant et mot de passe ne coïncident pas.', 'failure');
} else {
$this->flashMessage('YOUPI.', 'success');
$user = $this->getUser();
$user = iterator_to_array($user); // Greeny tip ?
$user->login($is_membre->pseudo, $mdp);
echo $user->isLoggedIn() ? 'yes' : 'no';
}
Result : Recoverable Error – Argument 1 passed to iterator_to_array() must implement interface Traversable, instance of Nette\Security\User given
I didn't read that kind of code in other examples :
Garry
or Paolo
- Reka
- Member | 19
But where is Authentizator file? Do you mean IAuthenticator?
<?php
/**
* This file is part of the Nette Framework (http://nette.org)
* Copyright (c) 2004 David Grudl (http://davidgrudl.com)
*/
namespace Nette\Security;
/**
* Performs authentication.
*/
interface IAuthenticator
{
/** Credential key */
const USERNAME = 0,
PASSWORD = 1;
/** Exception error code */
const IDENTITY_NOT_FOUND = 1,
INVALID_CREDENTIAL = 2,
FAILURE = 3,
NOT_APPROVED = 4;
/**
* Performs an authentication against e.g. database.
* and returns IIdentity on success or throws AuthenticationException
* @return IIdentity
* @throws AuthenticationException
*/
function authenticate(array $credentials);
}
Or do you want my UserManager under App/Model/ (which implements IAuthenticator) ?
<?php
namespace App\Model;
use Nette;
use Nette\Security\Passwords;
/**
* Users management.
*/
class UserManager extends Nette\Object implements Nette\Security\IAuthenticator
{
const
TABLE_NAME = 'membres',
COLUMN_ID = 'id',
COLUMN_NAME = 'pseudo', // changed my column since first message (nick->pseudo)
COLUMN_PASSWORD_HASH = 'password',
COLUMN_ROLE = 'role';
/** @var Nette\Database\Context */
private $database;
public function __construct(Nette\Database\Context $database)
{
$this->database = $database;
}
/**
* Performs an authentication.
* @return Nette\Security\Identity
* @throws Nette\Security\AuthenticationException
*/
public function authenticate(array $credentials)
{
list($username, $password) = $credentials;
$row = $this->database->table(self::TABLE_NAME)->where(self::COLUMN_NAME, $username)->fetch();
if (!$row) {
throw new Nette\Security\AuthenticationException('Le pseudo est incorrect.', self::IDENTITY_NOT_FOUND);
} elseif (!Passwords::verify($password, $row[self::COLUMN_PASSWORD_HASH])) {
throw new Nette\Security\AuthenticationException('Le mot de passe est incorrect.', self::INVALID_CREDENTIAL);
} elseif (Passwords::needsRehash($row[self::COLUMN_PASSWORD_HASH])) {
$row->update(array(
self::COLUMN_PASSWORD_HASH => Passwords::hash($password),
));
}
$arr = $row->toArray();
unset($arr[self::COLUMN_PASSWORD_HASH]);
return new Nette\Security\Identity($row[self::COLUMN_ID], $row[self::COLUMN_ROLE], $arr);
}
/**
* Adds new user.
* @param string
* @param string
* @return void
*/
public function add($username, $password)
{
try {
$this->database->table(self::TABLE_NAME)->insert(array(
self::COLUMN_NAME => $username,
self::COLUMN_PASSWORD_HASH => Passwords::hash($password),
));
} catch (Nette\Database\UniqueConstraintViolationException $e) {
throw new DuplicateNameException;
}
}
}
class DuplicateNameException extends \Exception
{}
Hope I made a good guess…
- Reka
- Member | 19
I haven't touched a thing somewhere else (views, controllers, the first lines in the model UserManager are the only files I modify)…
About the exception : when I browse the folder, I find
vendor/security/src/security/AuthentificationException.
This file contents :
namespace Nette\Security;
/**
* Authentication exception.
*/
class AuthenticationException extends \Exception
{
}
And I don't find \Exception anywhere…
Where is it supposed to be?
I will generate another Nette project and test its behaviour + see if its
structure is the same.
It was not the case between the first (20/11/2015) and second project
(02/12/2015) I created with composer…
Last edited by Reka (2015-12-09 18:50)
- esorimer
- Member | 114
It seems to me that you have put PDO instance into session somewhere (or object with PDO instance reference …). So the problem is not in the code shown here and will not be possible to find out from the tracy “scary red page”.
You should look for a code, where you are playing with session.
- Reka
- Member | 19
greeny wrote:
I did not mean the exception file, but the error page one. You can find it in log/**, probably the latest one. You can open it in browser (its HTML), but also copy-paste to some service like jsfiddle. Please do so, we can then more deeply investigate the problem :)
Ok, ok… Hum.
So. Under /log/** I have 2 files : .htaccess and web.config.
No HTML file in that folder. A good start, is it so?
Here is the code beyond the error page : https://pastee.org/m8c33
It seems that Esorimer is right about sessions, but I don't know where
I use sessions… I have only 2 controllers at this stage of the project, and
I haven't used that in my controllers or views.
Furthermore, the only model I have is UserManager (see above).
Is it possible that the sessions come from a vendor I have loaded… ?
Thanks again for your perseverance in helping me.
Last edited by Reka (2015-12-09 20:40)
- greeny
- Member | 405
That paste helped, thanks.
Error is in your Authenticator on last lane of authenticate method
(return new Nette\Security\Identity($row[self::COLUMN_ID], $row[self::COLUMN_ROLE], $arr);
)
First and last arguments are ok, but the middle one is not just value. You
are using table roles
, so in $row[self::COLUMN_ROLE]
is ActiveRow
. Possible fix is, that you replace
$row[self::COLUMN_ROLE]
with
$row[self::COLUMN_ROLE]->name
(instead of name
use
the name of column in table roles
where is name for
that role).
<ot> @esorimer it was exactly what I thought </ot>