php使用bcrypt算法加密用户密码的函数password_hash()

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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值