Fatal error: Uncaught TypeError: password_verify() expects p

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

UniqueIdeaMan
Forum Contributor
Posts: 197
Joined: Wed Jan 18, 2017 3:43 pm

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by UniqueIdeaMan »

Celeraun,

Thanks! Sorry for the late reply. Was ill. Plus, was having internet connection problem. I will try your code after I wakeup. Way past my bed time now. Someone suggested I raise the "passwords" column size to more than 50 digit and another agreed to him by saying to raise it to the max a hash could be. I want your advice. How many digits should I change it to ? How many digits you usually have for your hash password column ?
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by Celauran »

There's no reason it shouldn't be 255 chars
User avatar
requinix
Spammer :|
Posts: 6617
Joined: Wed Oct 15, 2008 2:35 am
Location: WA, USA

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by requinix »

Starting with PHP 7.2, password hashes with the default algorithm will be almost 100 characters.

Use 255.
UniqueIdeaMan
Forum Contributor
Posts: 197
Joined: Wed Jan 18, 2017 3:43 pm

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by UniqueIdeaMan »

Celeraun,

Thank you for your code suggestions. Making note of it aswell as notes of all other code suggestions in other forums. I try learning as much as I can from every forum without neglecting any.

It seems the issue was the "passwords" column size was too small (50 chars). Switching it to 255 should have made a difference but it did not in my test last night due to me not repopulating the column. Others in another forum suggested I repopulate and I read their suggestion just now and it is working after I repopulated it. Just sharing this knowledge on all forums I opened threads on this issue so it benefits other newbies too. I know this is nothing "learnable" for pros.
http://www.webdeveloper.com/forum/showt ... ost1516863

And so, this code is no longer getting the password_verify to false when I type the correct password.
Code:

Code: Select all

<?php
 
/*
ERROR HANDLING
*/
declare(strict_types=1);
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
 
include 'config.php';
 
// check if user is already logged in
if (is_logged() === true) 
{
	//Redirect user to homepage page after 5 seconds.
	header("refresh:2;url=home.php");
	exit; //
}


if ($_SERVER['REQUEST_METHOD'] == "POST")
{ 
	if (isset($_POST["login_username_or_email"]) && isset($_POST["login_password"]))
	{
		$username_or_email = trim($_POST["login_username_or_email"]); //
		$password = $_POST["login_password"];
		
         
		//Select Username or Email to check against Mysql DB if they are already registered or not.
		$stmt = mysqli_stmt_init($conn);
		
        if(strpos("$username_or_email", "@") === true)
		{
			$email = $username_or_email;
			$username = "";
			
			$query = "SELECT ids, usernames, passwords, emails, accounts_activations_statuses FROM users WHERE emails = ?";
			// i = integer; s = string; d = double; b = blob.
			$stmt = mysqli_prepare($conn, $query);			
			mysqli_stmt_bind_param($stmt, 's', $email);
			mysqli_stmt_execute($stmt);
		    //$result = mysqli_stmt_get_result($stmt); //Use either this line (if you need to get all data of the array without associating them to variables like you do with mysqli_stmt_bind_result), or ...
			//Note from line below that the variables "$db_username", "$db_account_activation_status" are related to the tbl columns selected on $query ("SELECT ids, usernames, accounts_activations_statuses From users .. WHERE).
			$result = mysqli_stmt_bind_result($stmt, $db_id, $db_username, $db_password, $db_email, $db_account_activation_status); // ... this line. But not both.
		}
		else
		{
			$username = $username_or_email;
			$email = "";
			$query = "SELECT ids, usernames, passwords, emails, accounts_activations_statuses FROM users WHERE usernames = ?";
			// i = integer; s = string; d = double; b = blob.
			$stmt = mysqli_prepare($conn, $query);
			mysqli_stmt_bind_param($stmt, 's', $username);
			mysqli_stmt_execute($stmt);
			//$result = mysqli_stmt_get_result($stmt); //Use either this line (if you need to get all data of the array without associating them to variables like you do with mysqli_stmt_bind_result), or ...
			//Note from line below that the variables "$db_email", "$db_account_activation_status" are related to the tbl columns selected on $query ("SELECT ids, emails, accounts_activations_statuses From users .. WHERE).
			$result = mysqli_stmt_bind_result($stmt, $db_id, $db_username, $db_password, $db_email, $db_account_activation_status); // ... this line. But not both.#
		}       	
		
		//$rownums = mysqli_num_rows($result); // To get number of row matches
		//echo "$rownums";
		//Which of the following to do and why that one over others ?
		$row = mysqli_stmt_fetch($stmt);
		//$row = mysqli_fetch_array($query, MYSQLI_ASSOC);
		//$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
		
		mysqli_stmt_close($stmt);
		
		printf("%s (%s)\n",$row["usernames"],$row["passwords"]);
		
		if ($result == false)
		{
			echo "'$result == false' on line 73! IF got triggered on line 73! !<br>";
			exit();
		}
		elseif ($row['accounts_activations_statuses'] == '0')
		{
			{
				echo "You have not activated your account yet! Check your email for instructions on how to activate it. 
				Check your spam folder if you don't find an email from us.";
				exit();
			}
		}
		else
		{
			echo "'$result == true' on line 73! Else got triggered on line 86! <br>";//This ELSE is getting triggered on the test. That means $result = TRUE;
		}
		
		if (password_verify($password, $db_password))		
		{
			echo "IF triggered for password_verify! password_verify ok";
			//If 'Remember Me' check box is checked then set the cookie. 
			//if(!empty($_POST["login_remember"])) // Either use this line ....
			if (isset($_POST['login_remember']) && $_post['login_remember'] == "on") // ...or this line. But not both!
			{
				setcookie("login_username", $username, time()+ (10*365*24*60*60));
			}
			else
			{
				//If Cookie is available then use it to auto log user into his/her account!
				if (isset($_COOKIE['login_username']))
				{
					setcookie("login_username","","");
				}
			}
			$_SESSION["user"] = $username;
			header("location:home.php?user=$username");				
		}
		else
		{
			echo "Else got triggered on line 111: Incorrect User Credentials ! 'password_verify = FALSE';<br>";
			exit();
		}
	}
}
	
?>

<!DOCTYPE html>
<html>
<head>
<title><?php $site_name?> Member Login Page</title>
  <meta charset="utf-8">
</head>
<body>
<div class = "container">
<form method="post" action="">
<center><h3><?php $site_name ?> Member Login Form</h3></center>
<div class="text-danger">
<div class="form-group">
<center><label>Username/Email:</label>
<input type="text" placeholder="Enter Username" name="login_username_or_email" value="<?php if(isset($_COOKIE["login_username_or_email"])) echo $_COOKIE["login_username_or_email"]; ?>"</center>
</div>
<div class="form-group">
<center><label>Password:</label>
<input type="password" placeholder="Enter password" name="login_password" value="<?php if(isset($_COOKIE["login_password"])) echo $_COOKIE["login_password"]; ?>"></center>
</div>
<div class="form-group">
<center><label>Remember Login Details:</label>
<input type="checkbox" name="login_remember" /></center>
</div>
<div class="form-group">
<center><input type="submit" name="login_submit" value="Login" class="button button-success" /></center>
</div>
<div class="form-group">
<center><font color="red" size="3"><b>Forgot your password ?</b><br><a href="login_password_reset.php">Reset it here!</a></font></center>
<center><font color="red" size="3"><b>Not registered ?</b><br><a href="register.php">Register here!</a></font></center>
</form>
</div>
</body>
</html>
I am making a few changes on the above post's mentioned code because I was told in that forum (which I mentioned in my previous post):

1. Checking if $result is true/false is meaningless, as it will always be true if my code is bug-free, and likely always false if not.
2. Similarly, mysqli_stmt_fetch() will return true if it found a result row, otherwise false.
I, instead need to check the value bound to $db_password to see if it's correct. So it might be something like:

Code: Select all

if($row && password_verify($password, $db_password)) {
// good to go...
} 
I have been advised 6 nights ago there on that forum to trim down my code to this:

Code: Select all

if ($_SERVER['REQUEST_METHOD'] == "POST") // not really needed since you're checking $_POST
{
    if (isset($_POST["login_username"]) && isset($_POST["login_password"])) {
        $username = trim($_POST["login_username"]); //
        $password = trim($_POST["login_password"]); //
        $hashed_password = password_hash($_POST["login_password"], PASSWORD_DEFAULT);
        $sql = "
SELECT
  ids,
  usernames, 
  passwords, 
  emails, 
  accounts_activations_statuses 
FROM users 
WHERE usernames = ?
  AND passwords = ?
";
        $stmt = mysqli_prepare($conn, $sql);
        mysqli_stmt_bind_param($stmt, 'ss', $username, $hashed_password);
        mysqli_stmt_execute($stmt);
        if (mysqli_stmt_num_rows($stmt)) {
            // found a match, we're good to go...
        } else {
            // whatever you do when user/password not found...
        }
    }
}
This forum Mod also managed to figure it that I got the column size wrong:
https://www.webmastersun.com/threads/18 ... ging-me-in

Thanks!
Last edited by UniqueIdeaMan on Mon Sep 25, 2017 5:05 pm, edited 5 times in total.
UniqueIdeaMan
Forum Contributor
Posts: 197
Joined: Wed Jan 18, 2017 3:43 pm

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by UniqueIdeaMan »

requinix wrote:Starting with PHP 7.2, password hashes with the default algorithm will be almost 100 characters.

Use 255.
Thank you. Just reading this!
Done this last night!
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by Celauran »

UniqueIdeaMan wrote:I am making a few changes on the above post's mentioned code because I was told in that forum (which I mentioned in my previous post):

1. Checking if $result is true/false is meaningless, as it will always be true if my code is bug-free, and likely always false if not.
What if your code is fine but, for whatever reason, your database server is offline. You probably want to handle that even if it's an unlikely scenario.
UniqueIdeaMan wrote:2. Similarly, mysqli_stmt_fetch() will return true if it found a result row, otherwise false.
I, instead need to check the value bound to $db_password to see if it's correct. So it might be something like:

Code: Select all

if($row && password_verify($password, $db_password)) {
// good to go...
} 
I have been advised 6 nights ago there on that forum to trim down my code to this:

Code: Select all

if ($_SERVER['REQUEST_METHOD'] == "POST") // not really needed since you're checking $_POST
{
    if (isset($_POST["login_username"]) && isset($_POST["login_password"])) {
        $username = trim($_POST["login_username"]); //
        $password = trim($_POST["login_password"]); //
        $hashed_password = password_hash($_POST["login_password"], PASSWORD_DEFAULT);
        $sql = "
SELECT
  ids,
  usernames, 
  passwords, 
  emails, 
  accounts_activations_statuses 
FROM users 
WHERE usernames = ?
  AND passwords = ?
";
        $stmt = mysqli_prepare($conn, $sql);
        mysqli_stmt_bind_param($stmt, 'ss', $username, $hashed_password);
        mysqli_stmt_execute($stmt);
        if (mysqli_stmt_num_rows($stmt)) {
            // found a match, we're good to go...
        } else {
            // whatever you do when user/password not found...
        }
    }
}
I don't know about that. You're re-hashing the passwords before querying, so they aren't going match. Keep it in the select, but don't pass the password in to the query.
UniqueIdeaMan
Forum Contributor
Posts: 197
Joined: Wed Jan 18, 2017 3:43 pm

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by UniqueIdeaMan »

Thanks Celeraun! Continuing this project on a new thread.
How do I mark this thread as resolved ?
UniqueIdeaMan
Forum Contributor
Posts: 197
Joined: Wed Jan 18, 2017 3:43 pm

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by UniqueIdeaMan »

Thanks celeraun,

I am sure your pdo would become handy when I jump into pdo.
As of now, my whole project is in mysli procedural style. Project also finished but need a little polish here and there on the rough edges.
Anyway, the above mysqli procedural code of mine you looked into. Have you noticed that, I created a condition to what should be echoed if the condition is true (password_verify passes) and what should be echoed if verification failed ?
Problem is, when the user inputs an incorrect password, that echo in the condition fails to echo. Why is that ? Instraf the script shows php's default echo (error). It shows:

Fatal error: Uncaught TypeError: password_verify() expects parameter 2 to be string, null given in C:\xampp\htdocs\php\login.php:55 Stack trace: #0 C:\xampp\htdocs\php\login.php(55): password_verify('password123', NULL) #1 {main} thrown in C:\xampp\htdocs\php\login.php on line 55

Why is that ? How to fix this so the conditions' echoes get echoed based on the password verification passing or failing ?
User avatar
Celauran
Moderator
Posts: 6427
Joined: Tue Nov 09, 2010 2:39 pm
Location: Montreal, Canada

Re: Fatal error: Uncaught TypeError: password_verify() expec

Post by Celauran »

Not having any code to look at definitely makes things harder. The error message clearly explains what is happening: you're passing null to password_verify. Why that's happening would require seeing the code.
Post Reply