Search code examples
phpmysqlibindparam

Errno(0) when attempting log in with OO statement


I am attempting to make a more secure log in system. My registration is working fine so its not a connection issue. Just needing a fresh pair of eyes to see if there are any errors that I may be missing, can anyone help please? Thanks!

login.php

session_start();

if (isset($_POST['submit'])) 
    {

        $user = $_POST['username'];    
        $pass = $_POST['password'];


        if(!($stmt = $mysqli->prepare("SELECT username, password FROM users WHERE username = ?"))){
            echo "Prepare failed: (" . $mysqli->errno . ")" . $mysqli->error;
        }
        if(!$stmt->bind_param('s', $user)){
            echo "Bind failed: (" . $stmt->errno . ")" . $stmt->error;
        }
        if(!$stmt->execute()){
            echo "Execute failed: (" . $stmt->errno .")" . $stmt->error;
        }
        $userdata = $stmt->get_result();
        $row = $userdata->fetch_array(MYSQLI_ASSOC);

        $stmt->bind_result($user, $pass);
        $stmt->store_result();

        if(password_verify($pass, $row['password'])){

            $_SESSION['login_user'] = $_POST['username'];
            header('Location: profile.php');
            exit();
        }

    }
else{
    echo "Login Failed: (" . $stmt->errno .")" . $stmt->error;
}
$stmt->close();

$mysqli->close();

index.php(The login form)

<div id="loginform">

    Log in details<br /><br />

    <form method="post" action="login.php">

        Username:
        <input type="text" name="username" />
        <br /><br>
        Password:
        <input type="password" name="password" />
        <br /><br>
        <input type="submit" name="submit" value="Submit" />
    </form>

 </div>

Solution

  • You shouldn't use $stmt->errno and $stmt->error in the Login Failed error message. That line is in the else clause for if (isset($_POST['submit'])), so it has nothing to do with a MySQL error. I'm not sure why you're ever getting that message, since it should only happen if you go to login.php without submitting the login form on index.php.

    Since you're using $userdata->fetch_array() to fetch the row of results from the database, you shouldn't also use $stmt->bind_result() -- do one or the other. I don't think bind_result() is doing anything, since you never call $stmt->fetch() to get a row into those variables.

    If you decide to go with bind_result(), you need to use a different variable for the password, because $pass contains the password submitted from the form.

    You need to check whether a row was returned by the query -- if the user enters an invalid username, it will not. So the password check should be:

    if ($row && password_verify($pass, $row['password']) {
        ...
    }
    

    You should then have an else clause for this that reports that the username or password was invalid. You should not distinguish whether it was the username or password that was wrong, this would be bad for security (it helps a brute-forcer to know that he guessed the username correctly, and just needs to try different passwords).

    $stmt->close() should be inside the if block.