【问题标题】:How to check for duplicate username and/or email?如何检查重复的用户名和/或电子邮件?
【发布时间】:2012-09-15 00:15:16
【问题描述】:

我一直想知道如果在注册期间用户名和/或电子邮件重复,如何签入 MySQL 表。以下是我迄今为止尝试过但无济于事的方法:

$username = $_POST['username'];
$sq = $db->exec("SELECT * FROM `users` WHERE `username` = '$username'");
if ($sq->rowCount() > 0)
{
    $msg = "That username is already taken.";
    $error = true;
}

$email = $_POST['email'];
$sq = $db->exec("SELECT * FROM `users` WHERE `email` = '$email'");
if ($sq->rowCount > 0)
{
    $msg = "That email is already taken.";
    $error = true;
}

if (!error)
{
    //add to db
}

这给出的错误是Call to a member function rowCount() on a non-object

你能帮忙吗?

【问题讨论】:

  • 有什么问题?它根本不起作用吗?做一些意想不到的事情?不拿起现有的用户名和电子邮件?
  • 哦,我知道我忘记了什么。已编辑。
  • 您的代码容易受到 SQL 注入的攻击。您真的应该使用prepared statements,将变量作为不获得 SQL 评估。如果你不知道我在说什么,或者如何解决它,请阅读Bobby Tables 的故事。
  • 我对 PHP 了解不多,但第一个如果你在 $sq->rowCount() 中有括号,第二个如果你只有 $sq->rowCount。这可能是个问题吗?

标签: php mysql sql pdo


【解决方案1】:

PDO::exec() 返回一个整数,因此您的上述代码将因call to member function rowCount() on a non-object 行中的致命错误而死。你应该为此做的是SELECT COUNT(*) 来获取行数。

您还可以使用异常来帮助错误处理过程。

像这样:

// Ensure PDO will throw exceptions on error
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

// Turn emulated prepares off
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

try {

  // Check if username is taken
  $stmt = $db->prepare("SELECT COUNT(*) FROM `users` WHERE `username` = :username");
  $stmt->execute(array('username' => $_POST['username']));
  if ($stmt->fetchColumn() > 0) {
    throw new Exception("That username is already taken.");
  }

  // Check if email is taken
  $stmt = $db->prepare("SELECT COUNT(*) FROM `users` WHERE `email` = :email");
  $stmt->execute(array('email' => $_POST['email']));
  if ($stmt->fetchColumn() > 0) {
    throw new Exception("That email is already taken.");
  }

  // Username and email are free

} catch (PDOException $e) {

  // A database error occured

} catch (Exception $e) {

  // Either the username of email is taken

}

如果列中的数据应该是唯一的,它应该有一个唯一索引以防止重复插入,并加快基于该列的值进行搜索的查询。

【讨论】:

  • 或者甚至是SELECT EXISTS (SELECT * FROM ...),这样 MySQL 在找到单个匹配记录后就知道停止搜索,而不是继续寻找其他记录以找到不感兴趣的总计数。
  • @eggyal 出于这个原因,我想知道LIMIT 1。虽然公平地说,如果列应该是唯一的,它应该有一个唯一的索引,这样就不会真正优化它。
  • 我认为LIMIT 1 不会有任何区别,因为它只适用于汇总结果(其中只有 1 条记录)。但是,是的,UNIQUE 键会让我的观点变得多余。
  • @eggyal 啊,是的,LIMIT 是在收集结果后应用的,所以我想它不会影响性能。更新了提到唯一索引的答案,并重构得更好。
  • 如果我使列值唯一,它会在执行这段代码之前抛出一个mysql错误,不是吗?
【解决方案2】:

为避免潜在的竞争条件,您只需将用户名和电子邮件字段设置为唯一索引。

当您尝试插入重复行时,您的数据库引擎会给您一个特定的错误代码,对于 MySQL,它是 1062。

如果查询失败,检查错误号是否是重复行的错误号,并据此显示消息。

至少,您的列应该是唯一索引,以防止在数据库级别出现重复。

【讨论】:

    【解决方案3】:

    请说明 $db 的类型,假设它是 sqllite3。

    检查http://php.net/manual/en/sqlite3.exec.php 的 SQLLITE3::exec() 文档。据它所说,它仅对 (UPDATE, INSERT, DELETE) 有效并返回布尔值。因此,您的代码可能不会运行。

    如果根据您的标签,您使用的是 MySQL。我相信您需要查看 mysql/mysqli 扩展、mysql_query() 和 mysqli_query() 或 $db -> query() 如果 $db 是 mysqli 类型。

    【讨论】:

    • 明确表示是MySQL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    • 2019-04-06
    • 1970-01-01
    • 2014-05-28
    • 1970-01-01
    • 2018-07-05
    相关资源
    最近更新 更多