function hash($pw, $salt = NULL, $cost = self::COST)
{
if ($cost < 4 || $cost > 31) {
user_error(self::E_CostArg, E_USER_ERROR);
}
$len = 22;
if ($salt) {
if (!preg_match('/^[[:alnum:]\\.\\/]{' . $len . ',}$/', $salt)) {
user_error(self::E_SaltArg, E_USER_ERROR);
}
} else {
$raw = 16;
$iv = '';
if (extension_loaded('mcrypt')) {
$iv = mcrypt_create_iv($raw, MCRYPT_DEV_URANDOM);
}
if (!$iv && extension_loaded('openssl')) {
$iv = openssl_random_pseudo_bytes($raw);
}
if (!$iv) {
for ($i = 0; $i < $raw; $i++) {
$iv .= chr(mt_rand(0, 255));
}
}
$salt = str_replace('+', '.', base64_encode($iv));
}
$salt = substr($salt, 0, $len);
$hash = crypt($pw, sprintf('$2y$%02d$', $cost) . $salt);
return strlen($hash) > 13 ? $hash : FALSE;
}