尝试使用 OO 语句登录时出现 Errno(0)

Errno(0) when attempting log in with OO statement

我正在尝试创建一个更安全的登录系统。我的注册工作正常,所以这不是连接问题。只需要一双新的眼睛看看是否有任何我可能遗漏的错误,有人可以帮忙吗?谢谢!

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(登录表单)

<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>

您不应在 Login Failed 错误消息中使用 $stmt->errno$stmt->error。该行位于 if (isset($_POST['submit']))else 子句中,因此它与 MySQL 错误无关。我不确定您为什么会收到该消息,因为只有当您前往 login.php 而未在 index.php 上提交登录表单时才会发生这种情况。

由于您正在使用 $userdata->fetch_array() 从数据库中获取结果行,因此您不应同时使用 $stmt->bind_result() -- 两者兼而有之。我认为 bind_result() 没有做任何事情,因为您永远不会调用 $stmt->fetch() 来获取这些变量的行。

如果您决定使用 bind_result(),您需要为密码使用不同的变量,因为 $pass 包含从表单提交的密码。

您需要检查查询是否返回了一行——如果用户输入了无效的用户名,则不会。所以密码检查应该是:

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

然后您应该有一个 else 子句来报告用户名或密码无效。你不应该区分是用户名还是密码错误,这对安全性是不利的(这有助于暴力破解者知道他猜对了用户名,只需要尝试不同的密码)。

$stmt->close() 应该在 if 块内。