【问题标题】:Checking if row exists under criteria (PDO, prepare???)检查条件下是否存在行(PDO,准备???)
【发布时间】:2012-10-31 21:43:20
【问题描述】:

下面的代码表明我尝试根据代码中给出的条件来找出是否存在一行。它默认为 else 语句,正确,但如果 if 语句似乎为真(没有电子邮件为 ashfjks@sdhja.com),则不能与“if”语句一起使用,并且相反,代码继续。这段代码的后半部分主要是对情况进行扩展。该行只能存在或不存在,所以我不明白为什么它不严格执行其中一个。我正在转换为站点安全的 PDO,这就是为什么不是所有的都在 PDO 中。如果这个问题过于本地化,我很抱歉?

$stmt = $pdo->prepare("SELECT * FROM table WHERE email = ?");
$stmt->execute(array("$email"));
$row3 = $stmt->fetch(PDO::FETCH_ASSOC);

while($row = $stmt->fetch()) {

  if ( ! $row3) {
    // Row3 doesn't exist -- this means no one in the database has this email, allow the person to join
    $query = "INSERT INTO table (username, email, password, join_date) VALUES ('$username', '$email', SHA('$password1'), NOW())";
    mysqli_query($dbc, $query); 
    $query = "SELECT * FROM table WHERE username = '$username'";
    $data2 = mysqli_query($dbc, $query);
  while ($row = mysqli_fetch_array($data2)) {

  $recipent = '' . $row['user_id'] . '';

    $query = "INSERT INTO messages (recipent, MsgTit, MsgR, MsgA, sender, time, readb, reada, MsgCon) VALUES ('$recipent', '$MsgTit', '$MsgR', '$MsgA', '$sender', NOW(), '$readb', '$reada', '$MsgCon')";
    mysqli_query($dbc, $query);

    // Aftermath.
    echo '<p>Your new account has been successfully created. You\'re now ready to <a href="game2.php" target="_blank">log in</a>. After this you should implement basic character-details on your users profile to begin the game.</p>';

    mysqli_close($dbc);
    exit();
  } }  
  else {
    // An account already exists for this email, so display an error message
    echo '<p class="error">An account already exists for this e-mail.</p>';
    $email = "";
  }
}

【问题讨论】:

  • errr,如果$stmt-&gt;fetch() 返回false,则while 循环已经退出,因此如果该行不存在,您将永远不会进入if 语句..,在@ 之前使用987654326@ 循环类似if($row-&gt;rowCount() &gt; 0)
  • 混合 PDO 和 MySQLi 有什么特殊原因吗?
  • 他说他正在努力将其转换为 PDO 逐个查询。我想他不想一下子把它全部打破。他在这里似乎还有另一个大问题,所以混合可能不是大问题。
  • 宇智波斑:我是 PDO 的新手,在学了一点 mysql 之后(轻轻松松)学了 mysqli。网上的朋友和评论告诉我,学习mysqli有点浪费时间,因为PDO似乎要好得多(以及未来..),所以我正在尝试使用PDO。

标签: php pdo mysqli


【解决方案1】:

您的if 语句将永远不会被执行。您需要检查返回的行数。这就是你想要的:

注意:我最初使用$stmt-&gt;rowCount(),但 OP 说这对他不起作用。但我很确定该错误的原因来自其他地方。

if (!($stmt = $pdo->prepare("SELECT * FROM table WHERE email = ?"))) {
   //error
}

if (!$stmt->execute(array("$email"))) {
    //error
}
//The $row3 var you had was useless. Deleted that.

$count = 0;

while ($row = $stmt->fetch()) {
    $count++;
}

//The query returned 0 rows, so you know the email doesn't exist in the DB
if ($count== 0) {

    $query = "INSERT INTO table (username, email, password, join_date) VALUES ('$username', '$email', SHA('$password1'), NOW())";

    if (!mysqli_query($dbc, $query)) {
        //error
    }

    $query = "SELECT * FROM table WHERE username = '$username'";

    if (!($data2 = mysqli_query($dbc, $query))) {
        //error
    }

    while ($row = mysqli_fetch_array($data2)) {

        $recipent = '' . $row['user_id'] . '';

        $query = "INSERT INTO messages (recipent, MsgTit, MsgR, MsgA, sender, time, readb, reada, MsgCon) VALUES ('$recipent', '$MsgTit', '$MsgR', '$MsgA', '$sender', NOW(), '$readb', '$reada', '$MsgCon')";

        if (!mysqli_query($dbc, $query)) {
            //error
        }

       // Aftermath.
       echo '<p>Your new account has been successfully created. You\'re now ready to <a href="game2.php" target="_blank">log in</a>. After this you should implement basic character-details on your users profile to begin the game.</p>';

       mysqli_close($dbc);
       exit();
   }
}
//The query did not return 0 rows, so it does exist in the DB
else {
    // An account already exists for this email, so display an error message
    echo '<p class="error">An account already exists for this e-mail.</p>';
    $email = "";
}

您应该将其余的查询完全转换为使用 PDO。

【讨论】:

  • 我多次尝试使用 row_count(连同 COUNT(*)),但它对我不起作用。错误是“在非对象上调用成员函数 rowCount()”。我读到 rowCount 并不总是适用于 SELECT 查询。非常感谢您的回答,您知道为什么它将自己标识为非对象吗?我认为数组是对象。
  • @SamBowyer “调用非对象”通常意味着某处存在另一个问题。不过,我明白你的意思。给我一点时间。
  • @ Geoff_Montee - 这是我的错。重新排列的代码缺少 }。我不确定为什么会导致该错误,但代码现在可以工作。非常感谢 - 以及其他答案,这提供了对 PDO 如何处理与 mysqli 不同的见解(并且仅在几天前开始使用 PDO 意味着我真的没有学到这一点)。谢谢!
  • @SamBowyer 太棒了!乐意效劳。通过切换到 PDO,您正朝着正确的方向前进。
  • 如何使用$rows = $stmt-&gt;fetchAll(PDO::FETCH_ASSOC); if (count($rows) == 0) ... 应该也可以。
【解决方案2】:

+1 来自@Geoff_Montee 的回答,但这里还有一些提示:

  • 确保在每次 prepare() 或 execute() 之后检查错误。报告错误(但不要将您的 SQL 暴露给用户),然后优雅地失败。

  • 请注意,即使您检查了是否存在与 $email 匹配的行,也可能会在您检查后和 INSERT 之前的短时间内创建这样的行。这是race condition。即使您选择匹配 $email 的行,您也应该在数据库中使用 UNIQUE 约束,并在执行 INSERT 时捕获错误,以防 UNIQUE 约束因冲突而阻止插入。

  • SELECT email 而不是SELECT *。如果您在电子邮件上有索引,则查询运行效率更高,因为它可以只检查给定值的索引,而不必在不需要时读取表的所有列。这种优化称为仅索引查询

  • 同样使用SELECT user_id 而不是SELECT *。仅当您确实需要获取所有列时才使用SELECT *

  • Bcrypt is more secure than SHA for hashing passwords.

【讨论】:

  • 致你的观点:通过列名而不是 选择,我同意并且通常不这样做,我真的不知道 * 是如何结束的,因为mysql(i) 版本没有它,我只能假设尝试添加 COUNT() 并删除它会让我很高兴。关于 SHA,是的,我正在考虑在这个问题 here 上使用盐、密钥等。通过检查错误,您的意思是当要返回行时执行“如果返回的行 = 0”类型的错误停止器?
  • @SamBowyer 他的意思是您在原始代码中没有错误检查。因此,如果查询失败(语法错误、服务器死机、飓风吹走数据中心),代码将继续运行。查看我添加到代码中的错误检查。很多if (!$stmt-&gt;prepare(...))
  • 另外,关于 Bill 关于竞争条件的观点......一个好的解决方案是使用事务并选择适当的事务隔离级别:dev.mysql.com/doc/refman/5.5/en/dynindex-isolevel.html
  • @Geoff_Montee,事务隔离在这种情况下没有帮助。 MySQL 不会锁定 SELECT。此外,如果 SELECT 没有找到这样的行,则没有任何东西可以锁定以防止另一个线程插入具有该值的新行。如果违反了唯一约束,您只需捕获错误。
  • @BillKarwin 很有趣。我认为SERIALIZABLE 事务级别可以防止事务相互混淆。
猜你喜欢
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多