Where to put password_verify in login script?
Before you read the code, keep in mind that the Fake Registration
block would not be in your code, but it is necessary to show you this, end-to-end.
<?php
session_start();
// Begin Vault
// credentials from a secure Vault, not hard-coded
$servername="localhost";
$dbname="login_system";
$username="dbUserName";
$password="dbPassword";
// End Vault
// The following two variables would come from your form, naturally
// as $_POST[]
$formEmail="jsmith123@gmail.com";
$ctPassword="¿^?fish╔&®)"; // clear text password
try {
#if(isset($_POST['email'], $_POST['password'])){
#require('../../../private_html/db_connection/connection.php');
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Begin Fake Registration
// fake it that user already had password set (from some registration insert routine)
// the registration routine had SSL/TLS, safely passing bound parameters.
$hp=password_hash($ctPassword,PASSWORD_DEFAULT); // hashed password, using
$conn->query("delete from user_accounts where email='jsmith123@gmail.com'");
$conn->query("insert user_accounts(first_name,last_name,email,password) values ('joe','smith','jsmith123@gmail.com','$hp')");
// we are done assuming we had a registration for somewhere in your system
// End Fake Registration
$query = $conn->prepare("SELECT * FROM user_accounts WHERE email=:email");
$query->bindParam(':email', $formEmail);
$query->execute();
unset($_SESSION['email']);
unset($_SESSION['first_name']);
if(($row = $query->fetch()) && (password_verify($ctPassword,$row['password']))){
$_SESSION['email'] = $row['email'];
$_SESSION['first_name'] = $row['first_name'];
//header("Location: ../../myaccount/myaccount.php");
echo "hurray, you authenticated.<br/>";
}
else {
//header("Location:../../login/login.php ");
echo "invalid login<br/>";
}
#}
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
exit();
}
?>
Browser Output:
hurray, you authenticated.
Note, the password_hash()
function utilizes a random salt, as is evident
if you run it several times, with the hashed password changing with same clearText input, such as these hashed passwords:
$2y$10$KywNHrGiPaK9JaWvOrc8UORdT8UXe60I2Yvj86NGzdUH1uLITJv/q
$2y$10$vgJnAluvhfdwerIX3pAJ0u2UKi3J.pfvd0vIqAwL0Pjr/A0AVwatW
both of which are the result of subsequent hashings, as mentioned, of the same clear text password. The salt
and hash cost
are baked into the hashed password and saved. These call all be read about in links below.
From the Manual password_hash and password_verify.
Schema
create table user_accounts
( id int auto_increment primary key,
first_name varchar(50) not null,
last_name varchar(50) not null,
email varchar(100) not null,
password varchar(255) not null
);
Where to place password_verify() in php when logging in and have the registeration.php in an exernal file
You need to Select id & password without checking for password. Then you check if the pwdHash from db ($row['hashed_p']
) matches the one the user gave via password_verify:
$password = // the password in it's raw form how the user typed it. like $_POST['password'];
//Check username (without password) from database
$query =
"SELECT id, hashed_p FROM `register`
WHERE `username` = '$username'";
$result = mysqli_query($database,$query);
$row = mysqli_fetch_array($result,MYSQLI_ASSOC);
$verified_password = password_verify($password, $row['hashed_p']);
if(mysqli_num_rows($result) && $verified_password){
echo 'start session succesfully';
} else {
echo 'error';
}
BUT please change to a prepared statements (because your version is very unsecure. could easily be hacked. Just seach for 'Bobby Tables'.):
$stmt = mysqli_prepare($database, $query);
mysqli_stmt_bind_param ($stmt, 's', $username);
$success = mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
How to use password verify on the login form php
You can't use the password in the WHERE
clause (so your second approach is correct), as the hash will be different for each time you use it. Furthermore, you should always select the specific number of columns you need, as you need to define each and every one of them with bind_result()
. It can work with SELECT *
, but then you rely on bind_result()
to cover all possible values - which will break if you suddenly add another column to your table.
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();
if ($user && password_verify($_POST['password'], $user['password'])) {
$_SESSION['user_id'] = $user['id'];
header('location: indexclient.php');
exit;
} else {
echo "Invalid login";
}
$stmt->close();
Php login password_verify
<?php
$stmt = $conn->prepare("SELECT username, password FROM users WHERE username = ?");
$stmt->bind_param('s', $username);
$username = $_POST['ulogin'];
$password = $_POST['upassword'];
$stmt->execute();
$stmt->bind_result($username, $password);
$row = $stmt->fetch(); //fetch DB results
if (!empty($row)) { // checks if the user actually exists(true/false returned)
if (password_verify($_POST['upassword'], $row['password'])) {
echo 'success'; // password_verify success!
} else {
echo 'failed';
}
} else {
echo "This user does not exist"; //email entered does not match any in DB
}
$stmt->close();
$conn->close();
You do not necessarilly need to check for number of rows. Also have an else statement if the password is not verified for any reason
Login system with password_verify()
I think I see the problem.
It looks like you're probably fetching the only row from the results before the if
$row = mysqli_fetch_assoc($result);
Then when you fetch again here, there's nothing left to fetch.
if(($result->num_rows > 0))
{
while($row = mysqli_fetch_array($result))
(I'm assuming the query will only return one row since username is unique.)
PHP can not login with correct password using password_hash()/password_verify()
I've created a simple gist where you can see a version of your code which I managed to run correctly and got the correct results:
- a user can signup
- a user can sign in
- a user can sign out
I find that your code was correct, in broad strokes, but I also believe you must have mixed up some of your variables and field names.
In your question you do a var_dump
of $row['pwdUsers']
, a field never seen in the insert statement. You also select the field username
when fetching data to compare to the one submitted for login, but in the insert statement the variable that you insert into that field is named $mailuid
(while a variable $username
sits next to it).
Given that when extracted and applied in a controlled environment your code works, I'd wager your error is due to a possible mix-up caused by the previously mentioned confusing nomenclatures, or due to some other logic hidden from us in the snippets you provided.
Related Topics
Diagnosing Memory Leaks - Allowed Memory Size of # Bytes Exhausted
How to Get Input Field Value Using PHP
Woocommerce, Get Current Product Id
Reading Very Large Files in PHP
Binding Multiple Values in Pdo
SQL Injections in Adodb and General Website Security
How to Retract a Salted Password from the Database and Auth User
Fastest Way to Check If a String Is Json in PHP
How Does Recursiveiteratoriterator Work in PHP
File_Put_Contents - Failed to Open Stream: Permission Denied
PHP: Regex to Ignore Escaped Quotes Within Quotes
How to Filter a Two Dimensional Array by Value
Replacing Accented Characters PHP
Download Multiple Files as a Zip-File Using PHP