我正在尝试使用PDO创建一个PHP登录/注册系统。寄存器部分工作正常,但是,当我尝试登录时,我总是收到一个错误,告诉我密码无效,即使它是正确的密码。
我将在这里添加一些脚本,并在下面进行更多解释。
注册.php:
<?php
require_once 'core/init.php';
$user = new User();
if ($user->isLoggedIn()) {
Redirect::to('index.php');
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Register</title>
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style/global.css">
<script src="js/main.js"></script>
</head>
<body>
<input type="checkbox" id="toggle-left">
<input type="checkbox" id="toggle-right">
<div class="page-wrap">
<?php require_once 'includes/header.php'; ?>
<?php require_once 'includes/navbar.php'; ?>
<?php require_once 'includes/profilebar.php'; ?>
<div class="page-content">
<form action="" method="post">
<h1>Register new account</h1>
<div class="inset">
<?php
if(Input::exists()) {
if (Token::check(Input::get('token'))) {
$validate = new Validate();
$validation = $validate->check($_POST, array(
'username' => array(
'required' => true,
'min' => 3,
'max' => 200,
'first_not_numeric' => true,
'unique' => 'users',
'alias' => 'Username'
),
'password' => array(
'required' => true,
'min' => 6,
'alias' => 'Password'
),
'password_again' => array(
'alias' => 'Password confirmation', // <--- using the alias
'required' => true,
'matches' => 'password'
),
'email' => array(
'required' => true,
'min' => 5,
'max' => 200,
'email' => true,
'unique' => 'users',
'alias' => 'Email'
),
'first_name' => array(
'max' => 100,
'alias' => 'First name'
),
'last_name' => array(
'max' => 100,
'alias' => 'Last name'
),
'gender' => array(
'required' => true,
'alias' => 'Gender'
)
));
if ($validation->passed()) {
$user = new User();
$salt = Hash::salt(100);
$k1 = hash('sha256', Input::get('email'));
$k2 = hash('sha256', mt_rand(10000,99999).time().Input::get('email'));
$k3 = hash('sha256', mt_rand(100000,999999).time().Input::get('username'));
try {
$user->create(array(
'username' => Input::get('username'),
'password' => Hash::make(Input::get('password'), $salt),
'salt' => $salt,
'email' => Input::get('email'),
'email_code' => Input::get('email_code'),
'k1' => $k1,
'k2' => $k2,
'k3' => $k3,
'first_name' => Input::get('first_name'),
'last_name' => Input::get('last_name'),
'gender' => Input::get('gender'),
'avatar' => $user->defaultProfilePic(),
'joined' => date('Y-m-d H:i:s'),
'group' => 1
));
if (!file_exists("users/Input::get('username')")) {
mkdir('users/'.Input::get('username'), 0755);
}
User::sendActivation(Input::get('email'), 'Email verification', 'Hello, '.Input::get('username').',
<br>
Please activate your account!<br>
<a href="http://www.soldiersofwar.esy.es/activate.php?k1='.$k1.'&email_code='.Input::get('email_code').'&k2='.$k2.' &k3='.$k3.'">Click here to activate your account!</a>
<br><br>
Copy and paste this link if the one above doesn't work.<br>
http://www.soldiersofwar.esy.es/activate.php?k1='.$k1.'&email_code='.Input::get('email_code').'&k2='.$k2.' &k3='.$k3.'
<br>
Thank you very much,<br>
Soldiers Of War Staff');
Session::flash('home', 'Please activate your account!');
Redirect::to('index.php');
} catch(Exception $e) {
die($e->getMessage());
}
} else {
foreach ($validation->errors() as $error) {
echo '<i class="fa fa-exclamation-triangle"></i> ', $error, '<br />';
echo '<br />';
}
}
}
}
?>
<!-- Username -->
<div>
<label for="username">USERNAME</label>
<input type="text" name="username" id="username" value="<?php echo escape(Input::get('username')); ?>" required>
</div>
<!-- Password -->
<div>
<label for="password">ENTER A PASSWORD</label>
<input type="password" name="password" id="password" required>
</div>
<!-- Confirm Password -->
<div>
<label for="password_again">CONFIRM PASSWORD</label>
<input type="password" name="password_again" id="password_again" required>
</div>
<!-- Email Address -->
<div>
<label for="email">EMAIL ADDRESS</label>
<input type="email" name="email" id="email" value="<?php echo escape(Input::get('email')); ?>" required>
</div>
<!-- First Name -->
<div>
<label for="first_name">FIRST NAME</label>
<input type="text" name="first_name" id="first_name" value="<?php echo escape(Input::get('first_name')); ?>">
</div>
<!-- Last Name -->
<div>
<label for="last_name">LAST NAME</label>
<input type="text" name="last_name" id="last_name" value="<?php echo escape(Input::get('last_name')); ?>">
</div>
<!-- Gender -->
<div>
<label for="gender">GENDER</label>
<select class="gender" id="gender" name="gender" required>
<option value="">Select Gender:</option>
<option value="Male">Male</option>
<option value="Female">Female</option>
</select>
</div>
</div>
<!-- Token -->
<input type="hidden" name="token" value="<?php echo Token::generate(); ?>">
<!-- Activation -->
<input type="hidden" name="email_code" value="<?php echo md5('username' + microtime()); ?>" />
<!-- Submit button -->
<p class="p-container">
<input type="submit" name="go" id="go" value="Register new account">
</p>
</form>
</div>
<?php require_once 'includes/footer.php'; ?>
</div>
</body>
</html>
登录.php:
<?php
require_once 'core/init.php';
$user = new User();
if ($user->isLoggedIn()) {
Redirect::to('index.php');
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Log in</title>
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="style/global.css">
<script src="js/jQuery.js"></script>
<script src="js/main.js"></script>
</head>
<body>
<input type="checkbox" id="toggle-left">
<input type="checkbox" id="toggle-right">
<div class="page-wrap">
<?php require_once 'includes/header.php'; ?>
<?php require_once 'includes/navbar.php'; ?>
<?php require_once 'includes/profilebar.php'; ?>
<div class="page-content">
<form action="" method="post">
<h1>Log in</h1>
<div class="inset">
<?php
if (Input::exists()) {
if (Token::check(Input::get('token'))) {
$validate = new Validate();
$validation = $validate->check($_POST, array(
'username' => array(
'required' => true,
'alias' => 'Username'
),
'password' => array(
'required' => true,
'alias' => 'Password'
)
));
if ($validation->passed()) {
$user = new User();
$remember = (Input::get('remember') === 'on') ? true : false;
$login = $user->login(Input::get('username'), Input::get('password'), $remember, $validate);
if ($login) {
Redirect::to('index.php');
} else {
foreach ($validation->errors() as $error) {
echo '<i class="fa fa-exclamation-triangle"></i> ', $error, '<br>';
echo '<br />';
//echo '<pre>', print_r($validation->errors()), '</pre>';
}
/*$errors = $validate->errors();
if(count($errors)>0){
var_dump($errors);
}*/
}
} else {
foreach ($validation->errors() as $error) {
echo '<i class="fa fa-exclamation-triangle"></i> ', $error, '<br>';
echo '<br />';
//echo '<pre>', print_r($validation->errors()), '</pre>';
}
/*$errors = $validate->errors();
if(count($errors)>0){
var_dump($errors);
}*/
}
}
}
if(Session::exists('login')) {
echo '<p><i class="fa fa-exclamation-triangle"></i> ' . Session::flash('login') . '</p><br />';
}
?>
<p>
<label for="username">USERNAME</label>
<input type="text" name="username" id="username" value="<?php echo escape(Input::get('username')); ?>">
</p>
<!--<?php
/*if(isset($validation) && !$validation->passed()){
foreach($validation->errors() as $error){
if ($error->alias = 'Username') {
echo '<i class="fa fa-exclamation-triangle"></i> ', $error, '<br>';
echo '<br />';
}
}
}*/
?>-->
<p>
<label for="password">PASSWORD</label>
<input type="password" name="password" id="password">
</p>
<p>
<input type="checkbox" name="remember" id="remember">
<label for="remember">Remember me for 1 month</label>
</p>
</div>
<input type="hidden" name="token" value="<?php echo Token::generate(); ?>">
<p class="p-container">
<span>Forgot password?</span>
<span>Resend activation email</span>
<input type="submit" name="go" id="go" value="Log in">
</p>
</form>
</div>
<?php require_once 'includes/footer.php'; ?>
</div>
</body>
</html>
用户类中的登录功能:
public function login($username = null, $password = null, $remember = false, $validate = null) {
if (!$username && !$password && $this->exists()) {
Session::put($this->_sessionName, $this->data()->id);
} else {
$user = $this->find($username);
if ($user) {
if ($this->data()->password === Hash::make($password, $this->data()->salt)) {
if (1 === intval($this->data()->activated)) {
Session::put($this->_sessionName, $this->data()->id);
if ($remember) {
$hash = Hash::unique();
$hashCheck = $this->_db->get('users_session', array('user_id', '=', $this->data()->id));
if (!$hashCheck->count()) {
$this->_db->insert('users_session', array(
'user_id' => $this->data()->id,
'hash' => $hash
));
} else {
$hash = $hashCheck->first()->hash;
}
Cookie::put($this->_cookieName, $hash, Config::get('remember/cookie_expiry'));
}
return true;
} else {
$validate->addError('You need to activate your account before you login!');
}
} else {
$validate->addError('Invalid password!');
}
} else {
$validate->addError('That username does not exist!');
}
}
return false;
}
哈希类:
<?php
class Hash {
public static function make($string, $salt = '') {
return hash('sha512', $string . $salt);
}
public static function salt($length) {
return mcrypt_create_iv($length);
}
public static function unique() {
return self::make(uniqid());
}
}
所以,现在我将详细解释问题是什么。
当我注册时,我使用 Hash:: make() 函数在将密码和盐存储在数据库中之前对他们的密码进行哈希处理。当他们尝试登录时,在login.php中,我在User类中调用login函数来进行登录。当登录功能检查详细信息是否正确时,它会获取输入的密码和存储在输入用户名下的数据库中的盐,并对其进行哈希处理。然后它获取存储在数据库中的哈希值,并检查新哈希值是否与存储的哈希值相同。如果是,则密码正确,否则不正确。但是由于某种我无法弄清楚的原因,它总是告诉我我输入了无效的密码。
一切都在另一个项目中工作,但由于某种原因我无法让它在这个项目中工作,我确实将旧项目中的代码与这个项目进行了比较。
感谢所有帮助,如果有人需要任何信息才能提供帮助,请告诉我,我会添加它。
提前感谢,
布萨尔纳
让我给你一个替代的例子,使用 password_hash()
和 password_verify()
正如我在上面的评论中所建议的那样。 我想你会看到这可以大大简化你的设计。
首先,让我们谈谈数据库模式。 对于此用例,您只需要一个与保存密码哈希相关的数据库列。在本练习中,假设它是 varchar(255),这是一个很好的推荐列大小。
若要基于输入密码创建哈希,代码如下所示:
// I assume you have sanitized the password at this point
// and stored in this $password variable.
// You should also enforce password length limit of 72 characters.
$password = ...;
$password_hash = password_hash($password, PASSWORD_DEFAULT);
if(false === $password_hash) {
// something went wrong. log error
} else {
// make your SQL insert to single password_hash field
// note that the hash itself contains information on
// the encryption methodology used and the salt
// that was randomly generated to create the hash
}
为了验证密码,代码如下所示:
// I am assuming you have user input password
// you want to verify in variable $password_input
// and that you have already retrieved password hash
// from DB and have that stored in $password_hash
$password_input = ...;
$password_hash = ...;
$passwords_match = password_verify($password_input, $password_hash);
if (false === $passwords_match) {
// password does not match. abort login
} else {
// password match. log user in
}
如您所见,哈希生成和哈希验证各需要一行代码。 没有比这更简单
从你所说的,如果相同的代码在另一个项目中工作。我建议您检查您的数据库。检查hash
列长度,您应该将其设置为足够大以适合整个哈希(它们通常很长)。
当列长短于实际值时,数据库将存储哈希的截断版本,因此密码检查将始终失败。