【问题标题】:PDO select prepared statement does not workPDO 选择准备好的语句不起作用
【发布时间】:2014-08-22 00:03:36
【问题描述】:

这是一个源代码的sn-p代码,我用来练习我的PHP技能。提交登录表单后,我尝试查看用户使用登录表单提交的用户名和密码是否与存储在数据库中的用户名和密码匹配。如果是,则“您的用户名和密码与我的匹配!” (显然这不会是最终的回声,只是看看它会带来两者的回声)。如果我提供正确的凭据(用户/通行证)或不正确的凭据,它会回显“您的用户名和密码与我所拥有的不匹配!”堵塞。我没有看到代码有任何问题,我的想法已经用完了。

config.php 中的部分代码(我已经包含在内)是数据库的设置,带有一个注册表和几个字段,其中用户名和密码字段确实存在因此名称。

user 是用户名的登录表单上的名称标签的值,pass 是密码的登录表单上的名称标签的值。

<?php
  include("config.php");
  if(isset($_POST['submit'])) {
      $stmt = $db->prepare("SELECT * FROM registration WHERE username = :username AND password = :password");
      $stmt->execute(array("username" => $_POST['user'], "password" => $_POST['pass']));
      $result = $stmt->fetch(PDO::FETCH_ASSOC);

      if(($_POST['user'] == $result['username']) && $_POST['pass'] == hash("sha256",$result['password'])) {
          echo "Your username and password matches what I have! <html><br /></html>";
      } else {
          echo "Your username and password DOES NOT matches what I have! <html><br />    </html>";
      }
  }
?>

【问题讨论】:

  • 您正在使用 POST 中的密码进行查询,然后根据结果中的密码哈希检查 POST 中的密码。不能两者兼有。
  • 谢谢不要惊慌。我现在看到了。这只是在结果之前而不是之后做的问题。

标签: php pdo


【解决方案1】:

您有一个密码存储的概念:您的代码将$_POST['pass'] 与数据库中字符串的哈希值进行比较。那么用户需要输入密码的 SHA256 哈希值吗?并且您将明文密码存储在数据库中?我不这么认为。

应该反过来。您允许用户输入他们的密码,然后对他们输入的字符串进行哈希处理。然后将其与数据库中存储的内容进行比较,这也应该是一个散列字符串。

$pass_hash = hash("sha256", $_POST["pass"]);
$stmt = $db->prepare("SELECT * FROM registration WHERE username = :username AND password = :password");
$stmt->execute(array("username" => $_POST['user'], "password" => $pass_hash));

您不必使用if() 来测试结果。只需测试查询是否返回零行。如果它返回任何行,那么您找到了匹配项。

也不要假设fetch() 返回了一行。如果没有行,则返回 NULL,因此将该行用作关联数组将引发错误。在取消引用之前测试该行是否为非空。

if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    // username and password matched a row
    echo "Your username and password matches what I have! <html><br /></html>";
} else {
    // no matching username
    echo "Your username and password DOES NOT matches what I have! <html><br />    </html>";
} 

这是我更喜欢的另一种变体:我只查找与用户名匹配的行,然后返回散列密码字符串。然后我在应用程序代码中进行比较。这样我就可以判断他们是否提供了合法的用户名,但密码错误。您不一定要向用户透露这一点,但您可能希望在您的应用程序中对其进行跟踪,因此如果有人为同一个用户名尝试了数十个错误密码,您可以锁定用户名或为操作员记录警报或东西。

$stmt = $db->prepare("SELECT password FROM registration WHERE username = :username");
$stmt->execute(array("username" => $_POST['user']));
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    $pass_hash = hash("sha256", $_POST["pass"]);
    if ($pass_hash == $row['password']) {
        echo "Your username and password matches what I have! <html><br /></html>";
    } else {
        // username exists, but wrong password
        echo "Your username and password DOES NOT matches what I have! <html><br />    </html>";
    }
} else {
    // no matching username
    echo "Your username and password DOES NOT matches what I have! <html><br />    </html>";
} 

【讨论】:

  • 谢谢,很清楚。另外通过测试查询是否返回一行,它会是这样的吗? if($stmt->prepare("SELECT....")->rowCount() > 0) { //这样做 }
  • 我添加了一个测试示例。您不需要行数,只需测试 fetch() 是否返回 null。
  • 上一个示例和我的代码($row vs $result)之间的唯一区别是我没有将 $result 包裹在 if 语句周围,坦率地说,我认为 if 语句条件应该只是布尔值(返回真或假),但似乎使用 fetch() pdostatement 返回数组,因此我没有用 if 语句环绕 $result。希望这是有道理的。
  • 在重新阅读了您的上一个示例代码之后,我明白了发生了什么。谢谢你。话虽如此,$row 将返回一行,如果返回,则表示用户名存在。
  • 对,因为当结果集中没有更多行时,fetch() 返回 null。如果 fetch() 在 first 调用时返回 null,则表示结果集为空,即没有匹配的行。
猜你喜欢
  • 2018-01-24
  • 2011-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-15
  • 1970-01-01
相关资源
最近更新 更多