Roswell Studios

139 Fulton Street, Ste 132
New York, NY 10038

Code: password_verify + Zend Framework 1

— October 22, 2015

Let’s just say you have a Zend Framework project, and you never bothered to update to ZF2 because you spent a lot of time adapting to the ZF1 weirdness, and have a nice system going. But now you want to drop the MD5 style passwords some of your projects may still be using. The solution is a custom Zend_Auth_Adapter_Interface. Here is an example:


class AuthHashVerify implements Zend_Auth_Adapter_Interface {

protected $email;
protected $password;

public function __construct($email, $password) {
$this->email = $email;
$this->password = $password;
}

public function authenticate() {
$dbUser = new Application_Model_DbTable_User();
$user = new Application_Model_User($dbUser->find1ByX('email', $this->email));
//if you want to use the Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS error condition, use fetchAll
if ($user->password) {
if (password_verify($this->password, $user->password)) {
//User OK
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $user);
} else {
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, $user, ['Password mismatch']);
}
} else {
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, $user, ['Email not found']);
}
}
}

Then in your login action:


$auth = Zend_Auth::getInstance();
$myAuth = new AuthHashVerify($this->_getParam('email'), $this->_getParam('password'));
$result = $auth->authenticate($myAuth);

//whenever you want to check authentication:
if (Zend_Auth::getInstance()->hasIdentity()) {
//OK
print_r(Zend_Auth::getInstance()->getStorage()->read());
exit();
} else {
//NOT OK
//Why? ask $result
echo $result->getCode(), ': ';
print_r($result->getMessages());
exit();
}

I put the AuthHashVerify at the top of the LoginController file, so it auto-loads, but you could rename it and call it via the autoloader, or have the controller itself extend Zend_Auth_Adapter_Interface.

You would create a password with

$user->password = password_hash($reset, PASSWORD_DEFAULT);

See Password Hashing for more info on the password_ functions. Fun fact: note that hash has on algorithm, but verify does not. If you upgrade, you might be getting passwords created with a different algorithm, but the old ones will continue to work because the algorithm id is embedded in the hash. That’s why your user.password should be varchar(200), not char(60), even though you will be using 60 characters for now.

There are a few things to note: “$dbUser->find1ByX” is one of those ZF1 convenience hacks that are why I never bothered to upgrade. “$dbUser->fetchRow($dbUser->getAdapter()->quoteInto(’email = ?’, $this->email))” is equivalent. If you don’t have DbTable, just ->query the database.

The “$user = new Application_Model_User(array|row|result)” is another custom feature. You can use the row object directly when doing $user->password, but should should create a limited object to avoid attempting to store database row related junk with the “Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $user);”. Consider “Zend_Auth_Result(Zend_Auth_Result::SUCCESS, {‘id’=>$user->id, ‘is_paid’=>$user->is_paid});” instead. Then, when you need to check the current user’s vital stats or abilities, it is in the Zend_Auth::getInstance()->getStorage()->read() object.

Back to all