Avatar of Crazy Horse
Crazy Horse
Flag for South Africa asked on

password_verify issues

I am trying to log in using the username and password I signed up with but I just keep getting my "no user found" message so it clearly isn't working but I don't know why.

      
$password = $link->real_escape_string($_POST['password']);
		$email = $link->real_escape_string($_POST['email']);
		
		$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
		$result = $link->query($sql);
		if ($result->num_rows == 1) {
		$row = $result->fetch_assoc();
		$db_password = $row["password"];
		if(password_verify($password, $db_password)) {
			
			echo "correct";
			
			} else {
			
			echo "no user found";
			}
		}

Open in new window


I used this to create my password on my register page:

$password = trim(password_hash($password, PASSWORD_BCRYPT, [12]));

Open in new window

PHP

Avatar of undefined
Last Comment
Crazy Horse

8/22/2022 - Mon
Ray Paseur

Have you tried printing out the values in $password and $db_password and checking them manually?  If you can, please post those strings here, using the code snippet.

Also, I can't find any way to tell password_verify() about the parameters used in creating the password_hash() so it may only work with the "vanilla" hash strings.  Might be worth testing that!
Ray Paseur

Hmm... No trouble found here.  Are the character sets consistent across PHP and the database?
https://iconoun.com/demo/temp_blacksulfur.php
<?php // demo/temp_blacksulfur.php
/**
 * https://www.experts-exchange.com/questions/28966548/password-verify-issues.html
 *
 * http://php.net/manual/en/function.password-hash.php
 * http://php.net/manual/en/function.password-verify.php
 */
error_reporting(E_ALL);
echo '<pre>';


$pw = 'gooseball';
$h1 = trim(password_hash($pw, PASSWORD_BCRYPT, [12]));
$h2 = password_hash($pw, PASSWORD_DEFAULT);
var_dump($pw, $h1, $h2);

// TEST
if (password_verify($pw, $h1)) echo PHP_EOL . "$pw == $h1";
if (password_verify($pw, $h2)) echo PHP_EOL . "$pw == $h2";

Open in new window

Crazy Horse

ASKER
Still checking this out... But if I run your code in my page I get:

string(9) "gooseball"
string(60) "$2y$10$iSzAQrbKyYoSFLyc8a9ggOQbRjrgC.XGEBFAIbtKnn4cT4aDYHULi"
string(60) "$2y$10$h8ousnvYyyEKEwOYhdtKremY/GkZ/kzGIYbDS5ZGlUAi9UEJXX/Zy"

gooseball == $2y$10$iSzAQrbKyYoSFLyc8a9ggOQbRjrgC.XGEBFAIbtKnn4cT4aDYHULi
gooseball == $2y$10$h8ousnvYyyEKEwOYhdtKremY/GkZ/kzGIYbDS5ZGlUAi9UEJXX/Zy
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
Ray Paseur

Yes, that is what I see, too.  Seems to suggest that password_verify() can recognize either of the hash values.
Crazy Horse

ASKER
Man, I am getting confused now (for a change). Can I do this to test?

$secret = password_verify($password, $db_password);
echo $secret;

Open in new window


That returns a blank screen.

I am not sure where I should put the var_dump in relation to my code.
Crazy Horse

ASKER
Not sure if this helps in any way, but in my DB all the text columns are utf8_general_ci and my integer columns have no collation even though I selected utf8_general_ci. For some reason they just remain empty.
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Crazy Horse

ASKER
I tried mine with your example and I just get a blank screen as well.

$password = $link->real_escape_string($_POST['password']);
		$email = $link->real_escape_string($_POST['email']);
		
		$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
		$result = $link->query($sql);
		if ($result->num_rows == 1) {
		$row = $result->fetch_assoc();
		$db_password = $row["password"];
			if(password_verify($password, $db_password)) echo PHP_EOL . "$password == $db_password";
			

Open in new window

ASKER CERTIFIED SOLUTION
Ray Paseur

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Crazy Horse

ASKER
Thanks, Ray. I will check that out but I really want to get this to work. I have incorporated your code into mine and it doesn't show a match.

I actually deleted all my data from the database and signed up again using the password "test". Then I tried to login and result is:

string(60) "$2y$10$fwmftAXT/C74/qZrKj488eBbr87Xv9U4fcmX2HfOvgFV1vtTO.PTG"
string(60) "$2y$10$ePzFcO/leSiao2wX8WFrRezgw8wVIXx5Id6FSEOxMWiJQU66EqYt."

I just don't understand why this is. It's driving me crazy!
Crazy Horse

ASKER
Just to double check.. Here is the code above this. Not sure if it might be interfering in any way?

$error = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
	
	
	if (!$_POST['email']) {
		
		$error .= "Email required <br>";
	}
	
	if ($_POST['email'] && filter_var($_POST["email"], FILTER_VALIDATE_EMAIL) === false) {

            $error .= "The email address is invalid.<br>";

        }
	
	if (!$_POST['password']) {
		
		$error .= "Password required";
		
	} else {
		
		$password = $_POST['password'];
		$email = $link->real_escape_string($_POST['email']);
		
		$sql = "SELECT password, userID FROM `users` WHERE email = '$email' LIMIT 1";
		$result = $link->query($sql);
		if ($result->num_rows == 1) {
		$row = $result->fetch_assoc();
                //rest of code here

Open in new window

This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
Crazy Horse

ASKER
And one last thing. Here is my insert code for the register page. It might have something to do with it or not. Worth posting though.

$stmt = $link->prepare("INSERT INTO `users` (email, password, firstName, identifier) VALUES (?, ?, ?, ?)");
			$stmt->bind_param("ssss", $email, $password, $name, $identifier);
			$email = htmlentities($_POST['email'], ENT_QUOTES);
			$password = trim(password_hash($password, PASSWORD_BCRYPT, [12]));
			$name = htmlspecialchars($_POST['name']);
			$identifier = bin2hex($identifier);
			$stmt->execute();
			$stmt->close();

Open in new window

Crazy Horse

ASKER
I figured it out!!!!!!

It was the one line in my register page code.

I changed this:

$password = trim(password_hash($password, PASSWORD_BCRYPT, [12]));

Open in new window


to this:

$password = trim(password_hash($_POST['password'], PASSWORD_BCRYPT, [12]));

Open in new window


Man, Oh man was that painful. Can I give myself points?? :P
Ray Paseur

OK, it looks like string comparison is inadequate for dealing with these hashed passwords; the same password will not always hash into the same output string.  We must use the related PHP functions to compare the values.  Try these three links:
https://iconoun.com/demo/temp_blacksulfur.php?q=secret <-- This one works.
https://iconoun.com/demo/temp_blacksulfur.php?q=foo
https://iconoun.com/demo/temp_blacksulfur.php

Here is the test script.
<?php // demo/temp_blacksulfur.php
/**
 * https://www.experts-exchange.com/questions/28966548/password-verify-issues.html
 *
 * READ THE USER-CONTRIBUTED NOTES CAREFULLY!
 * http://php.net/manual/en/function.password-hash.php
 * http://php.net/manual/en/function.password-verify.php
 *
 * References for PHP and MySQL(i):
 *
 * http://php.net/manual/en/mysqli.overview.php
 * http://php.net/manual/en/class.mysqli.php
 * http://php.net/manual/en/class.mysqli-stmt.php
 * http://php.net/manual/en/class.mysqli-result.php
 * http://php.net/manual/en/class.mysqli-warning.php
 * http://php.net/manual/en/class.mysqli-sql-exception.php <-- DID NOT WORK PHP 5.3+, MySQL 5.1+
 *
 * http://php.net/manual/en/mysqli.construct.php
 * http://php.net/manual/en/mysqli.real-escape-string.php
 * http://php.net/manual/en/mysqli.query.php
 * http://php.net/manual/en/mysqli.errno.php
 * http://php.net/manual/en/mysqli.error.php
 * http://php.net/manual/en/mysqli.insert-id.php
 *
 * http://php.net/manual/en/mysqli-result.num-rows.php
 * http://php.net/manual/en/mysqli-result.fetch-array.php <-- DO NOT USE THIS
 * http://php.net/manual/en/mysqli-result.fetch-object.php
 */
ini_set('display_errors', TRUE);
error_reporting(E_ALL);
echo '<pre>';


// TEST AGAINST THIS PASSWORD
$vwd = 'secret';


// DATABASE CONNECTION AND SELECTION VARIABLES - GET THESE FROM YOUR HOSTING COMPANY
$db_host = "localhost"; // PROBABLY THIS IS OK
$db_name = "??";
$db_user = "??";
$db_word = "??";
require_once('RAY_live_data.php');
// OPEN A CONNECTION TO THE DATA BASE SERVER AND SELECT THE DB
$mysqli = new mysqli($db_host, $db_user, $db_word, $db_name);

// DID THE CONNECT/SELECT WORK OR FAIL?
if ($mysqli->connect_errno)
{
    $err
    = "CONNECT FAIL: "
    . $mysqli->connect_errno
    . ' '
    . $mysqli->connect_error
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW WHAT THE DB CONNECTION OBJECT LOOKS LIKE
// var_dump($mysqli);


// CREATING A TABLE FOR OUR TEST DATA
$sql
=
"
CREATE TEMPORARY TABLE my_table
( id    INT          NOT NULL AUTO_INCREMENT PRIMARY KEY
, pwd   VARCHAR(255) NOT NULL DEFAULT ''
, xwhen TIMESTAMP    NOT NULL
)
"
;

// IF mysqli::query() RETURNS FALSE, LOG AND SHOW THE ERROR
if (!$res = $mysqli->query($sql))
{
    $err
    = 'QUERY FAILURE:'
    . ' ERRNO: '
    . $mysqli->errno
    . ' ERROR: '
    . $mysqli->error
    . ' QUERY: '
    . $sql
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW THE RESULTS OF THE QUERY
// var_dump($res);


// LOADING OUR VERIFICATION DATA INTO THE TABLE
$pwd = password_hash($vwd, PASSWORD_DEFAULT);
$pwd = $mysqli->real_escape_string($pwd);
$sql = "INSERT INTO my_table ( pwd ) VALUES ( '$pwd' )";
$res = $mysqli->query($sql);
if (!$res)
{
    $err
    = 'QUERY FAILURE:'
    . ' ERRNO: '
    . $mysqli->errno
    . ' ERROR: '
    . $mysqli->error
    . ' QUERY: '
    . $sql
    ;
    trigger_error($err, E_USER_ERROR);
}

// ACTIVATE THIS TO SHOW THE QUERY
// echo PHP_EOL . $sql;


// INTERPRET THE URL ARGUMENT AND TRY THE QUERY
$arg = !empty($_GET['q']) ? $_GET['q'] : 'Missing "q=" URL parameter';

$sql = "SELECT id, pwd FROM my_table WHERE id=1 LIMIT 1";
$res = $mysqli->query($sql);
$num = $res->num_rows;
if ($num)
{
    $row = $res->fetch_object();
    if (password_verify($arg, $row->pwd))
    {
        echo PHP_EOL . "Found PW match for <b>$arg</b> in row with id=$row->id";
    }
    else
    {
        echo PHP_EOL . "Found no PW match for <b>$arg</b>";
    }
}

Open in new window

HTH, ~Ray
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Ray Paseur

Regarding this:
https://www.experts-exchange.com/questions/28966548/password-verify-issues.html?anchorAnswerId=41777011#a41777011

I thought you already had assigned $password with this:
$password = $_POST['password'];

But if your script had not made that assignment, you would have gotten a Notice when your script tried to use an undefined variable.

Check AntiPractice #4 here to learn how to visualize undefined variables!
https://www.experts-exchange.com/articles/12293/AntiPHPatterns-and-AntiPHPractices.html

Seriously, you might want to have a look at this article, too.  It contains tested and working code samples you can copy and install right now.
https://www.experts-exchange.com/articles/2391/PHP-Client-Registration-Login-Logout-and-Easy-Access-Control.html

Then once you have that much working, you can go back in and do things like refactor the md5() into hashed passwords instead.
Crazy Horse

ASKER
Thanks, Ray. Yes, I checked out your link to a full solution for client registration, login and logout ( I do intend to use this in future)  which I could just copy and paste but I am trying to do it from scratch on my own to try help me learn and understand better. Unfortunately I get stuck ( a lot) but at least I learn something when I get stuck and really helpful people like you come along and help me out! :)

It would seem I have another problem now which I will ask in a related question.