PHP注册报错:Duplicate entry for key 'email' 原因及解决咨询
PHP注册系统邮箱重复错误分析与解决
错误含义解释
你遇到的Fatal error: Uncaught mysqli_sql_exception: Duplicate entry...错误,本质是:你的数据库user表的email字段设置了唯一约束(UNIQUE KEY),当尝试插入已存在的邮箱地址时,MySQL会触发1062错误码(重复条目);而PHP 8.0+版本的mysqli默认开启了严格异常模式,执行失败时直接抛出异常,导致原代码里的错误判断逻辑根本没机会执行。
原代码失效原因
原代码里的if ($stmt->execute()) else分支判断$mysqli->errno === 1062之所以没用,是因为mysqli默认抛出异常,当execute()执行失败时直接抛出了mysqli_sql_exception,程序直接终止,不会走到else分支里的错误判断。
正确处理方式
方案1:用try/catch捕获异常(你已采用的方法)
直接捕获执行阶段抛出的异常,通过异常对象获取错误码判断:
<?php if (empty($_POST["name"])){ die("请填写姓名"); } if (! filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)) { die("请输入有效的邮箱地址"); } if (strlen($_POST["password"])<8) { die("密码长度至少8位"); } if (! preg_match("/[a-z]/i", $_POST["password"])) { die("密码必须包含至少一个字母"); } if (! preg_match("/[0-9]/", $_POST["password"])) { die("密码必须包含至少一个数字"); } if ($_POST["password"] !== $_POST["confirmpassword"]) { die("两次输入的密码不一致"); } $password_hash = password_hash($_POST["password"], PASSWORD_DEFAULT); $mysqli = require __DIR__ . "/database.php"; $sql = "INSERT INTO user (name, email, password_hash) VALUES (?,?,?)"; $stmt = $mysqli->stmt_init(); if (! $stmt->prepare($sql)){ die("SQL错误:" . $mysqli->error); } $stmt->bind_param("sss", $_POST["name"], $_POST["email"], $password_hash); try { $stmt->execute(); echo "注册成功"; } catch (mysqli_sql_exception $e) { if ($e->getCode() === 1062) { die("邮箱已被占用"); } die("注册失败:" . $e->getMessage()); }
方案2:关闭mysqli异常模式,沿用原逻辑
如果你想保留原代码的分支判断结构,可以关闭mysqli的严格异常报告,让它返回错误而非抛出异常:
<?php // 先关闭严格异常模式 mysqli_report(MYSQLI_REPORT_OFF); // 以下表单验证逻辑不变... $password_hash = password_hash($_POST["password"], PASSWORD_DEFAULT); $mysqli = require __DIR__ . "/database.php"; $sql = "INSERT INTO user (name, email, password_hash) VALUES (?,?,?)"; $stmt = $mysqli->stmt_init(); if (! $stmt->prepare($sql)){ die("SQL错误:" . $mysqli->error); } $stmt->bind_param("sss", $_POST["name"], $_POST["email"], $password_hash); if ($stmt->execute()) { echo "注册成功"; } else { if ($mysqli->errno === 1062) { die("邮箱已被占用"); } die("注册失败:" . $mysqli->error . " " . $mysqli->errno); }
额外优化建议
除了依赖数据库唯一约束,还可以在插入前主动查询邮箱是否存在,提前给用户提示:
// 在插入逻辑前添加查询 $check_sql = "SELECT id FROM user WHERE email = ?"; $check_stmt = $mysqli->prepare($check_sql); $check_stmt->bind_param("s", $_POST["email"]); $check_stmt->execute(); // 如果能查询到结果,说明邮箱已存在 if ($check_stmt->fetch()) { die("邮箱已被占用"); }
注意:这个查询只能做前置提示,数据库的唯一约束不能去掉——因为存在竞态条件(比如两个请求同时检查同一邮箱,都通过后同时插入),唯一约束是最后一道防线。
内容的提问来源于stack exchange,提问作者thatstupidguy
相关产品推荐
相关产品推荐

