我决定尝试建立一个简单的登录和注册表单,但我遇到了一个问题。
当有人注册时,我显然要求他们填写Name
, E-Mail
, Password
和Confirm Password
。
我正在检查电子邮件是否已经在数据库中使用以下代码:
$query = $conn->prepare("SELECT email FROM users WHERE email ='" . $_POST['email'] . "'");
$query->execute();
if ( $query->rowCount() > 0 ) {
$error = true;
$email_again = "E-Mail already exists";
}
我问题:假设当有人输入已经在数据库中的电子邮件时,页面刷新并显示错误。
数据库不会将其添加到表中但它会将id加1所以下次有人注册时使用的是有效的电子邮件id不是2而是3因为有人尝试注册时使用的是已经存在的电子邮件
$query = $conn->prepare("SELECT email FROM users WHERE email ='" . $_POST['email'] . "'");
$query->execute();
if ( $query->rowCount() > 0 ) {
$error = true;
$email_again = "E-Mail already exists";
exit();
}
所以我继续并将exit();
添加到if
语句中,但是如果电子邮件已经在数据库中,那么在提交后它只显示一个空白页面。
我该如何解决这个问题?
:
Fatal error: Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'me@stephenhinett.co.uk' for key 'email' in /Applications/MAMP/htdocs/tasks/register.php:69 Stack trace: #0 /Applications/MAMP/htdocs/tasks/register.php(69): PDO->exec('INSERT INTO use...') #1 {main} thrown in /Applications/MAMP/htdocs/tasks/register.php on line 69
第69行:
$sql_insert = "INSERT INTO users(name, email, password)
VALUES ('" . $name . "', '" . $email . "', '" . md5($password) . "')";
$conn->exec($sql_insert);
问题1
if ( $query->rowCount() > 0 ) { $error = true; $email_again = "E-Mail already exists"; exit(); }
所以我添加了exit();但是,如果电子邮件已经在数据库中,则在提交后只显示一个空白页。
您的问题是,当您添加exit
时,您没有添加header
来告诉浏览器输出什么,如果有的话。没有输出的exit
将永远是一个暗淡的白屏。Exit
在此时停止脚本,因此通常不太友好。
所以,在退出之前添加一个标题,这样你的页面就可以正确地重定向用户。我还添加了一个$_SESSION
变量,包含您想要反馈给用户的消息(关于电子邮件重复):
session_start(); //if not already started at the top of the page
if ( $query->rowCount() > 0 ) {
$error = true;
$_SESSION['message'] = "E-Mail already exists.";
header("Location: somepage.php"); //will display session message
exit();
}
在您访问的页面上,设置一个系统来检查消息的会话值,并将消息输出到浏览器窗口。
问题2
阅读您的问题错误:您正在尝试复制数据库表中的唯一键(email
)索引,复制的电子邮件仍然被某些脚本函数(尝试)INSERT
编辑。
您还没有向我们展示这个脚本函数(在register.php第69行),所以我不能说更多关于这个的细节,但是您可能有兴趣使用on duplicate Key Update语法来帮助您克服这个问题。
边注:
如果你已经使用面向对象的符号为您的SQL,为什么你不使用预处理语句?这是一种更安全、更有效的检查电子邮件是否已经存在于数据库表中的方法。
我不明白为什么你想在尝试复制电子邮件时增加行id,为什么增加
id
字段?如果id值是主键(PK),并且是MySQLauto_increment
,那么手动增加,这是非常糟糕的做法,并将导致各种相关问题。最好有另一个表列,如repetation_attempts
,这是一个标准的tinyint(3)
(或smallint(6)
,无论什么)列(默认为零),然后将更新以跟踪在任何给定的电子邮件行上尝试了多少次复制尝试。- id列是id认证列,不应该用作计数器。
出于安全考虑,我建议您使用预处理语句。我不是MySQL专家,但我认为这是情况…
autoincrement索引也会在插入语句失败时自增。
- 查询A执行INSERT语句,DB保留一个索引
- 查询B执行INSERT语句,DB保留索引
- 查询A失败,但"B"完成了他的语句,并且是并发的
- 为了保证一致性,将A的索引直接浪费掉
如您所说,您可以手动检查电子邮件是否已经存在。伪代码:
if(mail_already_exists()){ show_error(); }else{ insert_data(); }
数据库不会将其添加到表中,但它会做的是将id增加1,以便下次有人注册时使用有效的id他们的id不是2而是3,因为有人试图这么做注册一个已经在那里的电子邮件
我看不出为什么ID会增加,除非你实际上插入数据。使用一个检查重复记录的函数
- 检查是否存在EMAIL。如果存在,返回TRUE,否则返回FALSE
- 如果TRUE (email存在),抛出一个消息给用户
- 如果FALSE,执行INSERT作业。