【问题标题】:php if statement random failurephp if 语句随机失败
【发布时间】:2015-03-17 11:46:16
【问题描述】:

我正在为我的网站创建一个电子邮件激活页面,但遇到了问题。似乎尽管页面接收到显示成功激活消息所需的所有信息,但它随机决定显示错误消息,指出凭据与数据库中的任何内容都不匹配。这是代码

 // Check their credentials against the database
  try {
    $check = $db->prepare("SELECT * FROM users WHERE id= ? AND username = ? AND email = ? AND user_ident = ? AND activated = '1' AND email_activated = '0' LIMIT 1");

    $check->bindParam(1, $id);
    $check->bindParam(2, $u);
    $check->bindParam(3, $e);
    $check->bindParam(4, $p);
    $check->execute();

    $num_rows = $check->rowCount();

} catch(Exception $er){
    // ERROR : COULD NOT INSERT EMAIL INTO USERS TABLE
    Send_email('support@site.com', 'check user - email activation failure', 'Could not check user '.$er);   
    exit;
}
// Evaluate for a match in the system (0 = no match, 1 = match)
if($num_rows === 0){
    Send_email('support@site.com', 'email activation credentials no match', 'invalid email activation variables.<br/> email: '.$e.'<br/>userid: '.$id.'<br/>username: '.$u.'<br/>user_ident: '.$p); 
    header("location: message.php?msg=Your credentials are not matching anything in our system");
    exit();
}
// Match was found, you can activate them
try {
    $checking = $db->prepare("UPDATE users SET email_activated = 1 WHERE id= ? LIMIT 1");
    $checking->bindParam(1, $id);
    $checking->execute();
} catch (Exception $er){
    // ERROR : COULD NOT INSERT EMAIL INTO USERS TABLE
    Send_email('support@site.com', 'Email add error', 'Could not set active state '.$er);   
    exit;
}

因此,有时,当单击电子邮件中的激活链接时,它会正常工作,然后有时它会抛出错误,提示凭据与数据库中的任何内容都不匹配,但是当我在单击后立即检查数据库时链接,email_activated 字段已更新以显示它已被激活。 这在技术上不应该发生,因为如果我这样做正确,页面将在抛出凭据错误后退出,这意味着 email_activated 更新代码甚至不应该运行。 似乎它可能运行了两次,但我使用了一个计数器,并且只显示了一次运行。 任何帮助都会很棒!

【问题讨论】:

  • 可能是浏览器正在缓存重定向。第一次访问具有清除缓存的 URL 时会发生这种情况吗?尝试明确指定这是“302 Found”重定向,看看是否有帮助。
  • 我刚刚再次对其进行了测试,发现我什至不必在地址栏中按 Enter 即可更新页面。我从电子邮件中复制了激活链接,粘贴在 chrome 地址栏中,然后查看了我的用户表,它更新了 email_activated 列以显示它已被激活..
  • 看来您对缓存的预感是正确的。我在激活页面中添加了header('Expires: Sun, 01 Jan 2014 00:00:00 GMT'); header('Cache-Control: no-store, no-cache, must-revalidate'); header('Cache-Control: post-check=0, pre-check=0', FALSE); header('Pragma: no-cache');,问题似乎已经停止。
  • Chrome 特别难。我有经验,即使在您清除缓存后,它有时也会缓存重定向。因此,以 Firefox 为例。我添加了一个完整的答案仅供参考。顺便说一句,没有在地址栏中按 Enter 键的东西是“chrome page preloading”功能。如果确定您会打开它,它会预加载页面。

标签: php conditional


【解决方案1】:

可能是浏览器正在缓存重定向。尝试明确指定这是“302 Found”重定向。

header('HTTP/1.1 302 Found');
header('Location: /your-location');

或者按照您的建议包含所有缓存标头:

header('Expires: Sun, 01 Jan 2014 00:00:00 GMT'); 
header('Cache-Control: no-store, no-cache, must-revalidate'); 
header('Cache-Control: post-check=0, pre-check=0', FALSE); 
header('Pragma: no-cache');

【讨论】:

    【解决方案2】:

    嗯,您的第一个查询中有很多过滤器。那就是:

    id= ? AND username = ? AND email = ? AND user_ident = ? AND activated = '1' AND email_activated = '0' 
    

    而你只有第二个:

    id= ?
    

    如果查询完全不同,您不能期望得到相同的结果。第一个查询中的一个项目显然无法匹配,但是由于您的第二个查询忽略了除“id”之外的所有内容,因此它会继续并更新该行。

    【讨论】:

    • 我明白你的意思,并已将额外的过滤器添加到第二个查询中,但不管怎样,第二个查询甚至不应该在第一个查询中运行,因为 exit();放在标题之后。
    • 您在使用 PDO 吗?如果是这样,请注意 php.net 上的建议:“对于大多数数据库,PDOStatement::rowCount() 不会返回受 SELECT 语句影响的行数”。它提供了另一种方法。
    【解决方案3】:

    PDO rowCount 不适合您的目的。检查 - http://php.net/manual/en/pdostatement.rowcount.php

    "PDOStatement::rowCount() 返回受相应 PDOStatement 对象执行的最后一个 DELETE、INSERT 或 UPDATE 语句影响的行数。

    如果关联 PDOStatement 执行的最后一条 SQL 语句是 SELECT 语句,则某些数据库可能会返回该语句返回的行数。然而,这种行为并不能保证适用于所有数据库,并且不应依赖于可移植应用程序。”

    请参阅此SO question too,以更好地了解该场景。

    【讨论】:

    • 我明白你在说什么,并且可以从文档中看到它应该以不同的方式完成,但是到目前为止我已经在我的网站上使用 rowCount 没有问题。在这种情况下,我发现问题不是 rowCount。不过,我会考虑调整我的代码,以确保它不会在未来引起问题。
    猜你喜欢
    • 2018-02-02
    • 2019-01-26
    • 2021-10-17
    • 2015-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-10
    相关资源
    最近更新 更多