登录页面的准备语句问题

Posted

技术标签:

【中文标题】登录页面的准备语句问题【英文标题】:Problem With Prepared Statements for Login Page 【发布时间】:2020-05-24 13:50:03 【问题描述】:

我正在尝试为我的网站创建登录页面。我从我建立的另一个网站复制并粘贴了这个,登录工作正常。我使用 echo 语句对其进行了测试,但是当我尝试登录时得到的只是登录页面的截断版本。它会在此代码粘贴到 html 代码中的位置截断。我已经看过很多次了,我的眼睛已经变成了对眼,所以我不确定我错过了什么!非常感谢任何帮助!

<?php
                    if($_SERVER['REQUEST_METHOD'] != 'POST') 
                        echo '<form method="post" action="">
                        <p><label for="username">Username:</label><input type="text" name="username" id="username" title="username"></p>
                        <p><label for="password">Password:</label><input type="password" name="password" id="password" title="password"></p>
                        <p><input type="submit" name="login" id="login" value="Login"></p></form>';
                     else 
                        $username = $_POST['username'];
                        $password = $_POST['password'];

                        $mysqli = new mysqli("","","","");
                        if($mysqli->connect_error) 
                            exit('Error connecting to database');
                         else 
                            $sql2 = "SELECT admin_id, admin_username, admin_password FROM adminlogin WHERE admin_username = ?";
                            if(($stmt = $mysqli->prepare($sql2)) === false) 
                                error_log($mysqli->error);
                                error_log("SQL = [$sql2]");
                                die("Database error, contact site admin");
                             else 
                                $stmt->bind_param("s", $username);
                                $stmt->execute();
                                $stmt->store_result();
                                if($stmt->store_result() === false) 
                                    error_log($stmt->error);
                                    die("Database error, contact site admin.");
                                 else 
                                    echo 'No error';
                                // test store
                             // bind param
                         // sql statement
                     // test connection
                    ?>
                </div>
                <div class="col-1-3">
                    <h2>Search Blog</h2><br>
                    <form method="post" action="search.php" name="search" id="search">
                        <p><input type="text" name="searchinput" id="searchinput" title="search"></p>
                        <p><input type="submit" name="search" id="search" value="Search"></p>
                    </form>
                    <br>
                    <h2>About</h2>
                    <p>Hello and welcome to Cooking for Alaska: THM and Healthy Eating on a Budget! It is my prayer that you will find this blog useful in helping your family eat healthy while living on an Alaska-based budget. Groceries in Alaska are expensive, but feeding your family shouldn't be! Please enjoy my blog and feel free to contact me with any questions.</p>
                    <br>
                    <h2>Recent Blog Posts</h2>
                    <?php
                    include('includes/dblogin.php');
                    $sql = "SELECT * FROM recentposts_short ORDER BY post_datetime DESC LIMIT 3";
                    $result = mysqli_query($con, $sql);
                    if($result == false) 
                        $mysql_error = mysqli_error($con);
                        echo '<p>There was an error. Please contact an administrator.</p>';
                     else 
                        while($row=mysqli_fetch_assoc($result)) 
                            echo '<p><bold><a href="blog.php?id='.$row['post_title'].'">'.$row['post_title'].'</a></bold></p>';
                            echo '<p class="smallfont">'.$row['post_datetime'].'</p><br>';
                        
                    
                    ?><br>

【问题讨论】:

也许您的数据库中没有您输入的用户名的行?这将使您的 while($stmt-&gt;fetch()) 循环执行零次,并且似乎没有输出指示未知用户。 顺便说一句,你应该更改你的 mysql 管理员密码,因为你已经将它发布在互联网上。 用户名有一行。我仔细检查了那个。是的,我更改了密码,但感谢您的额外提醒! 此时我的策略是在每个步骤中添加几行代码来调用error_log() 以输出有关已成功完成的操作的信息。然后查看您的 http 服务器错误日志以获取该输出。这是一种常见的 PHP 调试技术。 我得到了绑定结果,然后它退出了工作。我使用了var_dump(),但当我走到那一步时,什么也没显示。 【参考方案1】:

我测试了您的代码,它可以正常工作。没有什么问题。

我建议尽管您说您仔细检查了数据库,但问题是此 PHP 代码连接到的数据库中不存在用户名。也许你检查了错误的数据库。

我按原样测试了您的代码,然后对其进行了一些重构。我想我会告诉你我写这个的方式:

这显示了error_log() 的使用,它输出到 http 错误文件。将技术错误消息输出到您可以阅读的位置是一个好习惯,但会在浏览器输出中呈现更用户友好的错误。您不想让您的用户感到困惑。

$mysqli = new mysqli("localhost","USER","PASSWORD","DB");
if ($mysqli->connect_error)  
    error_log($mysqli->connect_error);
    die('Error connecting to database, contact site administrator');
   

将 SQL 放入变量中,以便在出现问题时将其输出到错误日志中。同样,用户不需要知道技术细节,他们只需要知道失败并且站点管理员需要修复它。

$sql = "
  SELECT admin_id, admin_username, admin_password 
  FROM admin 
  WHERE admin_username = ?";
if (($stmt = $mysqli->prepare($sql)) === false) 
  error_log($mysqli->error);
  error_log("SQL = [$sql]");
  die("Database error, contact site administrator");
   

如果任何步骤出现问题,每个 mysqli 函数都会返回 false。你需要检查一下。

if ($stmt->bind_param("s", $username) === false) 
  error_log($stmt->error);
  die("Database error, contact site administrator");
 
if ($stmt->execute() === false) 
  error_log($stmt->error);
  die("Database error, contact site administrator");
 
if ($stmt->store_result() === false) 
  error_log($stmt->error);
  die("Database error, contact site administrator");

如果有零行,则表示用户名不匹配任何内容。您想在错误日志中了解这一点,但不要将其透露给用户。他们应该只知道用户名或密码错误,而不是哪个错误。

if ($stmt->num_rows == 0) 
  error_log("Username '$username' not found");
  die("Incorrect username or password");
 
if ($stmt->bind_result($id, $user, $pass) === false) 
  error_log($stmt->error);
  die("Database error, contact site administrator");
 

应该只有一行与用户名匹配。因此,如果它没有匹配的密码,请随意 die()。

while ($stmt->fetch()) 
   if (password_verify($password, $pass) === false) 
       error_log("Username '$username' found, but password is wrong");
       die("Incorrect username or password");
   
 
$stmt->close();

最后,最后一步:如果我们走到了这一步,那么它一定是成功的。如果你在每个错误条件下都更早地 die(),那么你就不必担心深度嵌套的代码块。

echo "<p>Welcome! You are logged in, $username</p>";

【讨论】:

我到达store_result() 时遇到了错误。错误日志说:[10-Feb-2020 05:19:00 UTC] Commands out of sync; you can't run this command now [10-Feb-2020 05:19:05 UTC] PHP Notice: session_start(): A session had already been started - ignoring in /home/xk6wgsxybs5t/public_html/CookingForAlaska/includes/dblogin.php on line 7 啊哈——你必须已经在这个 PHP 请求中运行了另一个 SQL 查询,并且它仍在进行中。有关“命令不同步”错误的解释,请参阅我对 ***.com/a/3632320/20860 的回答。 好的。所以我将$sql 更改为$sql2,因为我确实看到我有另一个请求并认为可以解决它。但是,我仍然收到错误[11-Feb-2020 22:30:06 UTC] Commands out of sync; you can't run this command now [11-Feb-2020 22:30:19 UTC] Commands out of sync; you can't run this command now。我还尝试完全从页面中删除整个其他 SQL 查询,但仍然得到相同的错误。我更新了我的原始帖子以显示页面中的整个编码,包括其他 SQL 查询。 您连续两次致电store_result()。这是导致错误的原因吗? 我想我没有看到我在哪里调用它两次,除非 if 语句是什么再次调用它?

以上是关于登录页面的准备语句问题的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序-枯木学习笔记4-欢迎页面

微信小程序-枯木学习笔记4-欢迎页面

VUE项目实战8登录与退出功能开发准备

来自 2 个表的数据未显示在同一页面上

vue实战(7):完整开发登录页面(一)

选择查询的准备语句问题