if(!function_exists('password_hash')){
/*
*
*password_hash() 使用足够强度的单向散列算法创建密码的散列(hash)
*@param string $password 用户密码
*@param int $algo 指示算法的密码算法常量,就是指定一个算法,这里可以填写PASSWORD_DEFAULT和PASSWORD_BCRYPT,其它不行因为指定了bcrypt
*@param array $options 一个包含有选项的关联数组,如果省略将使用随机字符与默认cost
*@return mixed 返回散列后的密码
*@link https://secure.php.net/password_hash
*
*/
function password_hash($password,$algo,array $options=array())
{
static $func_overload;
isset($func_overload) or $func_overload=(extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
if($algo!==1)
{
trigger_error('password_hash(): 未知的希哈算法:'.(int)$algo,E_USER_WARNING);
return null;
}
//两位 cost 参数是循环次数以 2 为底的对数,它的范围是 04-31,超出这个范围将导致 crypt() 失败。
if(isset($options['cost']) && ($options['cost'] < 4 or $options['cost'] > 31))
{
trigger_error('password_hash(): 指定的bcrypt cost 参数值无效: '.(int)$options['cost'],E_USER_WARNING);
return null;
}
//我找到的所有资源都说,盐的长度为22,并且它与算法,成本和结果字符串中的实际哈希值一起存储.
//在PHP函数中,不推荐使用手动哈希的password_hash.相反,我们鼓励人们自动设置password_hash,因为它会更安心
if(isset($options['salt']) && ($saltlen=($func_overload ? mb_strlen($options['salt'],'8bit') : strlen($options['salt'])))<22){
trigger_error('password_hash(): 提供的salt 太短: '.$saltlen.' expecting 22,应该是22位',E_USER_WARNING);
return null;
}
elseif(!isset($options['salt']))
{
if(function_exists('random_bytes'))
{
try{
//生成适合于加密使用的任意长度的加密随机字节字符串,例如在生成salt、密钥或初始化向量时,
//一般配合bin2hex()使用,如果bin2hex(random_bytes(16))
$options['salt']=random_bytes(16);
}
catch(Exception $e)
{
log_message('error','compat/password: 尝试用random_bytes()但发生错误: '.$e->getMessage());
return false;
}
}
elseif(defined('MCRYPT_DEV_URANDOM'))
{
//string mcrypt_create_iv ( int$size [, int$source = MCRYPT_DEV_URANDOM ] )
//使用 Mcrypt进行数据加密。解密之前,首先要创建一个初始化向量(简称 iv)。创建初始化向量需要两个参数:size 指定了iv的大小source为iv的源source可以取如下值:
//MCRYPT_DEV_URANDOM:读取目录/dev/urandom中的数据(UNIX系统)。
$options['salt']=mcrypt_create_iv(16,MCRYPT_DEV_URANDOM);
}
//is_readable()判断给定文件名是否可读
elseif(DIRECTORY_SEPARATOR==='/' && (is_readable($dev='/dev/arandom') or is_readable($dev='dev/urandom')))
{
if(($fp=fopen($dev,'rb'))===false)
{
log_message('error','compat/password: 不能打开:'.$dev.' 读取失败。');
return false;
}
//设置资源流区块大小
stream_set_chunk_size($fp,16);
$options['salt']='';
for($read=0;$read<16;$read=($func_overload) ? mb_string($options['salt'],'8bit') : strlen($options['salt']))
{
if(($read=fread($fp,16-$read))===false)
{
log_message('error','compat/password: 读取时发生错误:'.$dev.' ');
return false;
}
$options['salt'] .= $read;
}
fclose($fp);
}
elseif(function_exists('openssl_random_pseudo_bytes'))
{
$is_secure=null;
//openssl_random_pseudo_bytes()生成一个伪随机字节串由length参数指定,需要开启openssl扩展
//第二个参数是自动为true,很少为false,除非是老系统
$options['salt']=openssl_random_pseudo_bytes(16,$is_secure);
if($is_secure!==true)
{
log_message('error','compat/password: openssl_random_pseudo_bytes() 将$cryto_strong标志设置为false');
return false;
}
}
else
{
log_message('error','compat/password: 没有可用的CSPRNG');
return false;
}
//对以上在某种方式下产生的$options['salt']结果进行base64_encode编码
//编码是为了使二进制数据可以通过非纯8-bit的传输层传输
$options['salt']=str_replace('+','.',rtrim(base64_encode($options['salt']),'='));
}
//#^[a-zA-Z0-9./]+$#D以字母数字,点和斜线为开头的字符,D只是限制$末尾字符
elseif(! preg_match('#^[a-zA-Z0-9./]+$#D',$options['salt']))
{
$options['salt']=str_replace('+','.',rtrim(base64_encode($options['salt']),'='));
}
isset($options['cost']) or $options['cost']=10;
return (strlen($password=crypt($password,sprintf('$2y$%02d%s',$options['cost'],$options['salt']))) === 60)
? $password
: false;
}
}
$options=[
'cost'=>12,
];
$pass=password_hash('123456',PASSWORD_BCRYPT,$options);
$info=password_get_info($pass);
echo $pass."<br>";
var_dump($info);
php使用bcrypt算法加密用户密码的函数password_hash()
最新推荐文章于 2025-03-09 00:14:12 发布