-1

I built a website with php that contains a sign up and log in system.

Now I want to make users able to change their password.

The code I have for this is inside of 4 files:

  1. A file that shows a page to the users on which you can enter your email adress, click a button and then see a message that you recieved an email with further instructions.

  2. A file that only contains php code, that sends this email to the user(with PHPMailer), containing a link with a token and selector. Also inside this file there is code so the token, selector and an expiry date get inserted in a table inside the database. This is all working fine.

  3. This file will open as a page when you click the link inside the email. In here you can enter a new password and confirm this new password. Also you can see the token and selector (that I also see inside my database) are inside of the URL of this page. When you submit the new password, something is going wrong. Because I see my error message appear: "Error: The row can not be fetched from the database (pwdreset.inc.php line 44)." This error is coming from my last file:

  4. A file that checks if the token from the URL matches the token from the database. If so, the rest of the code should actually update the old password with the new one inside the users table.

I followed a tutorial on YouTube to make this password reset system. I did everything like in the video, I checked my code for typo's like a hundred times and didn't find any. I also read all the comments and I see many other viewers have the same problem. Nobody in the comment section seems to know the answer and the maker of the video did not reply to anyone adressing this problem. Do you see what is causing this problem?

<?php

error_reporting(E_ALL);  ini_set('display_errors', TRUE);

if (isset($_POST["reset-confirm-submit"])) {

    $selector = $_POST["selector"];
    $validator = $_POST["validator"];
    $password = $_POST["resetpwd"];
    $passwordRepeat = $_POST["resetpwdrepeat"];

    if (empty($password) || empty($passwordRepeat)) {
        header("location: ../pwdreset.php?newpwd=empty-input");
        exit();
    } else if ($password != $passwordRepeat) {
        header("location: ../pwdreset.php?newpwd=passwords-do-not-match");
        exit();
    }
    
    $currentDate = date("U");

    require "dbh.inc.php";

    $sql = "SELECT * FROM reset_pwd WHERE pwd_reset_selector=? AND pwd_reset_expires >= ?;";
    $stmt = mysqli_stmt_init($conn);
    if (!mysqli_stmt_prepare($stmt, $sql)) {
        echo "Error: The data can not be selected inside the database (pwdreset.inc.php line 36).";
        exit();
    } else {
        mysqli_stmt_bind_param($stmt, "ss", $selector, $currentDate);
        mysqli_stmt_execute($stmt);
        $result = mysqli_stmt_get_result($stmt);        
        if (!$row = mysqli_fetch_assoc($result)) {
            echo "Error: The row can not be fetched from the database (pwdreset.inc.php line 44).";
            exit();
        } else { 
            $tokenBin = hex2bin($validator);
            $tokenCheck = password_verify($tokenBin, $row["pwd_reset_token"]);

            if ($tokenCheck === false) {    
                echo "Error: There is no token for this user inside the database (pwdreset.inc.php line 52).";
                exit();
            } else if ($tokenCheck === true) {
                $tokenEmail = $row["pwd_rest_email"];

                $sql = "SELECT * FROM users WHERE users_email=?;";
                $stmt = mysqli_stmt_init($conn);
                if(!mysqli_stmt_prepare($stmt, $sql)) {
                    echo "Error: The e-mail adress can not be selected inside the users table (pwdreset.inc.php line 61).";
                    exit();
                } else {
                    mysqli_stmt_bind_param($stmt, "s", $tokenEmail);
                    mysqli_stmt_execute($stmt);

                    $result = mysqli_stmt_get_result($stmt);
                    if (!$row = mysqli_fetch_assoc($result)) {
                        echo "Error: The row can not be fetched from the database (pwdreset.inc.php line 70).";
                        exit();
                    } else { 
                       $sql = "UPDATE users SET users_pwd=? WHERE users_email=?;";
                       $stmt = mysqli_stmt_init($conn);
                        if(!mysqli_stmt_prepare($stmt, $sql)) {
                            echo "Error: the password can not be updated inside the database (pwdreset.inc.php line 77).";
                            exit();
                        } else {
  
                            $newPwdHash = password_hash($password, PASSWORD_DEFAULT);

                            mysqli_stmt_bind_param($stmt, "ss", $newPwdHash, $tokenEmail);
                            mysqli_stmt_execute($stmt);
                       
                            $sql = "DELETE FROM reset_pwd WHERE pwd_rest_email=?;";
                            $stmt = mysqli_stmt_init($conn);
                            if(!mysqli_stmt_prepare($stmt, $sql)) {
                                echo "Error: The token was not deleted from the database (pwdreset.inc.php line 90).";
                                exit();
                            } else {
                                mysqli_stmt_bind_param($stmt, "s", $tokenEmail);
                                mysqli_stmt_execute($stmt);
                                header("location: ../index.php?newpwd=password-reset-success");
                            }
                        }
                    }
                }        
            }
        }
    }
} else {
    header("location: ../pwdreset.php?error=no-access");
}
RobinArt
  • 27
  • 4
  • 3
    Why one parameter and one concatenation ?? `WHERE pwd_reset_selector=? AND pwd_reset_expires >= $currentDate;` – RiggsFolly Aug 31 '23 at 10:41
  • 3
    Why do you have so much redundant code? Have you been following some bad YT tutorial? – Dharman Aug 31 '23 at 10:46
  • If you find a guide with code that doesn't work, why would you not look for a another one? How could you trust it? Do you actually understand the code, or have you just blindly followed the guide? Managing user credentials isn't something you should take lightly, or do without fully understand the how's and the why's. One mistake can compromisse your entire app, _and_ your users credentials (specially since people tend to reuse credentials). – M. Eriksson Aug 31 '23 at 10:56
  • Because that is inside of the video for checking if the date of the token has expired and I yes I unfortunately did follow a tutorial that is not perfect. – RobinArt Aug 31 '23 at 11:07
  • I do understand the code and I know that managing user credentials isn't something you should take lightly. That is why I'm trying to learn about that. Apparently I chose the wrong video. I will delete everything and search for something better. I chose this video, beause I found other video's in which only tokens are used, not selectors and I learned that it's safer to also use selectors. I'm sorry for wasting your time. – RobinArt Aug 31 '23 at 11:13
  • 1
    How far through your code do you get before it goes wrong? Does it get the correct variables into the code? Does your query work if you run it in phpmyadmin with the same variables? – droopsnoot Aug 31 '23 at 11:30
  • I think it stops running somewhere at `$result = mysqli_stmt_get_result($stmt); if (!$row = mysqli_fetch_assoc($result))`. And it does get the correct variables, except the query does not work if I run it. – RobinArt Aug 31 '23 at 11:53
  • What is the value of `pwd_reset_expires` in DB for the key you're trying to reset? `mysqli_fetch_assoc` is false I presume, have you looked at errors? MySQLi has different error operators than PHP. – user3783243 Aug 31 '23 at 12:02
  • @user3783243 The value I see inside my database is 1693468010 for example (it changes everytime I request a link inside an email again). I use `error_reporting(E_ALL); ini_set('display_errors', TRUE);` only for error reporting, I didn't know there is specific error reporting operator for MySQLi. So I guess that is why I don't see errors. – RobinArt Aug 31 '23 at 12:11
  • 1
    @RobinArt See https://www.php.net/manual/en/mysqli.error.php and/or https://stackoverflow.com/a/22662582/3783243 – user3783243 Aug 31 '23 at 12:12
  • 1
    [How to report errors in mysqli](https://phpdelusions.net/mysqli/error_reporting) – ADyson Aug 31 '23 at 14:08

0 Answers0