2

I am new to PHP and am trying to check whether a password provided by a user (login page) matches a hashed password stored in the db. The password in the db was hashed through $pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); (the same approach I use for the user's input) and is stored in a VARCHAR(255) column.

I now tried using password_verify to compare this with the user input but am getting the below error which is caused by the else part.

Can someone tell me what I am doing wrong here ? I tried removing "== true" as well but that didn't work either.

My PHP:

$email = $_POST["email"];
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 

$stmt = $conn->prepare("SELECT email, pw FROM Users WHERE email = ?");
$stmt->bind_param('s', $email);
$stmt->execute();
$result = $stmt->get_result();
if(mysqli_num_rows($result) == 0){
    echo "Email has not been registered yet";
}else{
    if(password_verify($pw, $result["pw"]) == true){
        echo "Password correct";
    }else{
        echo "Password incorrect";
    }   
};

The error:

"Fatal error: Cannot use object of type mysqli_result as array..."

Update:
To me this is different to the other question referred to as possible duplicate as in my case I either get the above error or (when following Bing's approach below) the result is always "Password incorrect" - independent of the input.

Many thanks in advance.

7
  • 1
    print_r($result) dump your result , it is object , it can be retrieve via $result->pw Commented Jun 24, 2015 at 6:04
  • 1
    $pw contains a hash of the user input password. So when you do password_veryify(), your actually checking a hash of the password against a hash in the database. You should be checking the raw password provided by the user against the hash in the database. Commented Jun 24, 2015 at 6:04
  • 1
    First rule with PHP errors: search for the error message with Google. Commented Jun 24, 2015 at 6:05
  • @Jeemusu The error has nothing to do with password_hash() and everything to do with mysqli Commented Jun 24, 2015 at 6:06
  • Thats right Hobo, but once that is solved you will notice there is infact a problem with password_verify(). Commented Jun 24, 2015 at 6:07

4 Answers 4

2

There are two issues with your code.

The first is as explained in the error message. Your returning your results as an object, not an array. You should access those values as an object:

$result->pw

The second issue is with your password_verify() function. $pw contains a hash of the user input password. So when you do password_veryify(), your actually checking a hash of the password against a hash in the database. You should be checking the raw password provided by the user against the hash in the database

Sign up to request clarification or add additional context in comments.

Comments

1

Your $result variable contains a mysqli_result object, not an array as you expect. Check out the Return Values section in the documentation, here: http://php.net/manual/en/mysqli.query.php

To convert it, simply call mysqli_fetch_array (which takes the mysqli_result as a parameter) and build your result. Here is what your code would look like:

$result_object = $stmt->get_result();
$result_array = array();
while($result_item = mysqli_fetch_array($result_object)) {
    array_push($result_array, $result_item);
}

if(count($result_array) == 0){
    echo "Email has not been registered yet";
}else{
    $single_entry = array_pop($result_array);
    if(isset($single_entry["pw"]) && password_verify($single_entry["pw"], $pw)){
        echo "Password correct";
    }else{
        echo "Password incorrect";
    }   
}

Several notes:

  1. You did not need the ; at the end of your final }
  2. You will be getting a two-dimensional array in $result_array, which is why I added the array_pop(), assuming you only have one email record.
  3. Your parameters were in the wrong order with your password_verify() call, you'll notice I switched them.
  4. I did NOT test this, but it should get you well on your way.

10 Comments

Just one final question on this: Do I even need the "== true" here ? It looks like on php.net they leave this out.
Glad to help. Beware note #2. Understanding multidimensional arrays is important. More good reading: w3schools.com/php/php_arrays_multi.asp
Yes, you can leave out == true literally anywhere. Note that that's two = signs. Three is a different question: stackoverflow.com/questions/80646
No, you do not need a ; after a } anywhere in PHP. The } is like ending a paragraph, then adding the ; is like an extra period. Switch statements probably want break; (which does end with ;) between cases (so they do not all run in order, starting with the first match), but that's a separate operation.
|
1

You're actually doing 2 things wrong.

Verifying the hash Note that password_hash() returns the algorithm, cost and salt as part of the returned hash. Therefore, all information that's needed to verify the hash is included in it. This allows the verify function to verify the hash without needing separate storage for the salt or algorithm information. ..from php.net

Retrieving the password from the database The mysqli_num_rows function doesn't return a password hash. Try to fetch this column.

But you're using the prepare statment, so you'll have to do it like shown here. So you would do something like:

//Remove
$pw = password_hash($_POST["pw"], PASSWORD_BCRYPT); 
$result = $stmt->get_result();

//Add
$stmt->bind_result($pw);
$stmt->fetch();

//Replace
if(mysqli_num_rows($result) == 0){
...
if(password_verify($pw, $result["pw"]) == true){
//With
if(empty($pw)){
...
if(password_verify($_POST["pw"], $pw) == true){

6 Comments

Thanks for this ! Can you explain what I should do to cover the second part of your answer ?
@TaneMahuta what is inside $conn are you using mysqli or pdo? Depending on what you're using I can give a more detailed answer.
Thanks - I use mysqli: $conn = new mysqli($dbServer, $dbUser, $dbPass, $dbName); $conn->set_charset("utf8");
Just to add here: This is not resolved yet. I was trying the other approach posted here but this doesn't detect the password as correct (yet).
@TaneMahuta Updated my answer check if this works for you.
|
1

I went through all the answers provided so far but either couldn't get them to work fully or couldn't get them to return me the correct results.

Since I am new to PHP this might be due to my lack of understanding of some parts of the provided comments and I apologise for that but I found a solution that works as intended for me.

I am sure this is not a perfect approach and I am happy to improve this further based on feedback and suggestions received - for the start it was important for me to have something running since I need to work on other parts that depend on this.

Here is the (working) solution I have so far:

$email = $_POST["email"];
$pw = $_POST["pw"]; 

$stmt = $conn->prepare("SELECT email FROM Users WHERE email = ?");
$stmt->bind_param('s', $email);
$stmt->execute();
$result = $stmt->get_result();
if(mysqli_num_rows($result) == 0){
    echo "Email has not been registered yet";
}else{
    $stmt = $conn->prepare("SELECT pw FROM Users WHERE email = ? LIMIT 1");
    $stmt->bind_param('s', $email);
    $stmt->execute();
    $result = $stmt->get_result();
    $pwHashed = $result->fetch_assoc();
    if(password_verify($pw, $pwHashed["pw"])){
        echo "Password correct";
    }else{
        echo "Password incorrect";
    }   
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.