如何在PHP登录表单中调试密码验证问题?

问题描述 投票:0回答:3

注册表格一切正常,但我无法弄清楚如何填写登录表格。我搜索了很多,但没有运气,我是PHP的新手。请给我提示和解决方案。

if (isset($_POST['username']) && isset($_POST['password']))
{
  $username = $_POST['username'];
  $_SESSION['LoggedIn'] = $username; //store username in session
  $password = $_POST['password'];

  // To protect MySQL injection (more detail about MySQL injection)
  $username = stripslashes($username);
  $password = stripslashes($password);
  // $username = mysql_real_escape_string($username);
  // $password = mysql_real_escape_string($password);
  $hash_password = password_hash($password , PASSWORD_DEFAULT);
  $verify_password = password_verify($_POST['password'] , $hash_password);


  // check login errors
  $check_login_errors = LoginErrors($username , $password);
  if ($check_login_errors)
     {
       //search database
       $query = "SELECT * FROM users WHERE Username='$username' AND Password='$hash_password'";
       $query_result = mysqli_query($connection , $query);

       //check database for username
      if (mysqli_fetch_array($query_result,MYSQLI_NUM > 0))
       {
        //verify password and username
        if($verify_password == $username)
         {
          echo "logged in";
          $_SESSION['LoggedIn'];
          RedirectTo("profile.php");
         }
        else
         {
          echo "wrong password or username";
         }
       }
      else
      {
        echo "error with checking username in database";
      }
    }
  }

 ?> 

我尝试的一切都给了我最后一个错误:

检查数据库中的用户名时出错

注意我在PHP代码的顶部添加了session_start()

php mysqli
3个回答
3
投票

我相信你在这里没有正确使用password_verify - 哈希密码已经存在于数据库中(大概是哈希的重点是什么?)所以你需要将该值与发布的密码进行比较。我修改了代码以使用预处理语句,因为原始代码可能仍然容易受到SQL注入攻击。

此外,在散列/验证密码之前使用stripslashes会在某些情况下破坏密码。例如,这会阻止包含反斜杠(\)的密码起作用,这是一个完全合法的字符密码。

if( isset( $_POST['username'], $_POST['password'] ) ){

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

    $stmt=$connection->prepare(
        'select `username`,`password` from `users` where `username`=?'
    );
    if( $stmt ){

        $stmt->bind_param( 's', $username );
        $result = $stmt->execute();

        if( $result ){
            $stmt->store_result();
            $stmt->bind_result( $uname,$upwd );
            $stmt->fetch();

            $stmt->free_result();
            $stmt->close();

            /* compare POSTed password and HASH from db */
            $verify = password_verify( $password, $upwd );

            if( $verify ){
                $_SESSION['LoggedIn'] = $username;
                header('Location: profile.php' );
            } else {
                /* more bad foo */
                echo "wrong password or username";
            }
        } else {
            echo "bad foo: error with checking username in database";
        }
    } else {
        echo "Failed to prepare sql query";
    }
}

--

来自PHP manual

准备好的语句执行包括两个阶段:准备和执行。在准备阶段,将语句模板发送到数据库服务器。服务器执行语法检查并初始化服务器内部资源以供以后使用。

准备之后是执行。在执行期间,客户端绑定参数值并将它们发送到服务器。服务器从语句模板创建语句,并使用先前创建的内部资源执行绑定值。

所以,要打破它:

$sql='select `username`,`password` from `users` where `username`=?';

sql语句提取两列,但实际上只需要密码。注意使用? - 这是我们将变量绑定到的占位符 - 在本例中是$username。如果prepare方法失败,它将返回false,因此我们可以将其用作逻辑测试来继续或拯救。

$stmt->prepare( $sql );

准备SQL查询,并返回一个语句句柄,用于对语句进行进一步操作。查询必须包含单个SQL语句。 [ Read more about $stmt->prepare() ]

$stmt->bind_param( 's', $username );

此声明必须已在此时成功准备好,因此我们将$username变量绑定到占位符。由于用户名是一个字符串,我们使用s作为类型。可能有四种类型,它们如下:

i   corresponding variable has type integer
d   corresponding variable has type double
s   corresponding variable has type string
b   corresponding variable is a blob and will be sent in packets

[ Read more about $stmt->bind_param() ]

$result = $stmt->execute();

现在语句已准备好并且所有变量都绑定到它们的占位符,提交查询并使用响应进行进一步的逻辑测试,因为这会在成功时返回TRUE,否则返回FALSE。 [ Read more about $stmt->execute() ]

$stmt->store_result();

使我们能够使用返回的记录集 [ Read more about $stmt->store_result() ]

$stmt->bind_result( $uname,$upwd );

将变量绑定到用于结果存储的预准备语句。当查询获取两列时,我们绑定了两个变量 - 它们在此阶段不存在,但在我们fetch实际记录集时将变为可用。 [ Read more about $stmt->bind_result() ]

$stmt->fetch();

将预准备语句的结果提取到绑定变量中。这使得$uname$upwd可用作变量,但我们希望(在合理范围内) [ Read more about $stmt->fetch() ]


0
投票

如果条件如下,你在下面犯了一个小错误: -

if (mysqli_fetch_array($query_result,MYSQLI_NUM > 0))

请改用:

if (mysqli_fetch_array($query_result,MYSQLI_NUM) > 0)

语法: - mysqli_fetch_array(result,resulttype);


0
投票

只是为了理智,可以从接受的答案中使用现实版本的代码。当然,你不会编写一个代码来运行一个单独的查询,是吗?

if( isset( $_POST['username'], $_POST['password'] ) ){
    $sql = 'select `username`,`password` from `users` where `username`=?';
    $stmt = $connection->prepare($sql);
    $stmt->bind_param( 's', $_POST['username'] );
    $stmt->execute();
    $stmt->bind_result( $uname,$upwd );
    if ($stmt->fetch() && password_verify( $_POST['password'], $upwd );
        $_SESSION['LoggedIn'] = $username;
        header('Location: profile.php' );
        exit;
    }
    echo "wrong password or username";
}
© www.soinside.com 2019 - 2024. All rights reserved.