<?php
/**
* Squiloople Framework
*
* LICENSE: Feel free to use and redistribute this code.
*
* @author Michael Rushton <michael@squiloople.com>
* @link http://squiloople.com/
* @category Squiloople
* @package Models
* @subpackage Validators
* @version 1.0
* @copyright © 2011 Michael Rushton
*/
// Define the namespace
namespace Models\Validators;
/**
* Password Validator
*
* Hash or validate passwords
*/
final class PasswordValidator
{
/**
* The password
*
* @access private
* @var string $_password
*/
private $_password;
/**
* The salt
*
* @access private
* @var string $_salt
*/
private $_salt;
/**
* The pepper
*
* @access private
* @var string $_pepper
*/
private $_pepper = 'Sz^3X6r[UyvV~2]_0stT}8 uY7RwZx4{q|Q91W5';
/**
* Set the password
*
* @access public
* @param string $password
*/
public function __construct($password = '')
{
$this->_password = $password;
}
/**
* Call the constructor fluently
*
* @access public
* @static
* @param string $password
* @return \Models\Validators\PasswordValidator
*/
public static function setPassword($password)
{
return new self($password);
}
/**
* Return the password
*
* @access public
* @return string
*/
public function getPassword()
{
return $this->_password;
}
/**
* Create a random password
*
* @access public
* @return \Models\Validators\PasswordValidator
*/
public function randomizePassword()
{
// If the password is incorrectly formed then randomize again
if (!$this->isValid($this->_password = substr($this->getSalt(true), 0, 8)))
{
$this->randomizePassword();
}
// Reset the salt
$this->_salt = null;
// Return the object
return $this;
}
/**
* Validate the password
*
* @access public
* @param bool|string $new
* @return bool
*/
public function isValid($new = false)
{
// The password must contain at least one character of each case, one digit, and be between 8 and 39 characters inclusive in length
if (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[\x20-\x7E]{8,39}$/D', $new ?: $this->_password))
{
return false;
}
// Otherwise return true
return true;
}
/**
* Set the salt
*
* @access public
* @param string $salt
* @return \Models\Validators\PasswordValidator
*/
public function setSalt($salt)
{
// Set the salt
$this->_salt = $salt;
// Return itself
return $this;
}
/**
* Generate and return a salt
*
* @access public
* @param bool $reset
* @return string
*/
public function getSalt($reset = false)
{
// If a salt has been set and a reset is not required then return the stored salt
if (!$reset && isset($this->_salt))
{
return $this->_salt;
}
// Reset the salt
$salt = '';
// Generate a random salt of 39 printable ASCII characters
for ($i = 1; $i <= 39; ++$i)
{
$salt .= chr(mt_rand(32, 126));
}
// If the salt does not have the correct syntax then regenerate
if (!$this->isValid($salt))
{
$this->getSalt(true);
}
// Return the random salt
return $this->_salt = $salt;
}
/**
* Return the pepper portion
*
* @access private
* @return string
*/
private function _getPepper()
{
return substr($this->_pepper, 0, 39 - strlen($this->_password));
}
/**
* Hash the password
*
* @access private
* @return string
*/
private function _getHash()
{
return hash('sha384', $this->getSalt() . $this->_password . $this->_getPepper());
}
/**
* Hash the password using an HMAC-inspired hash
*
* @access public
* @return string
*/
public function getHash()
{
return hash('sha512', substr(strrev($this->_pepper), 0, 20) . $this->_getHash());
}
}
Read More
Tags: password, validators