PHP注册表单跳过校验直接写入数据库问题修复方案
问题根因
代码存在5类核心问题,导致校验逻辑完全失效,空数据直接入库:
- 校验逻辑与入库逻辑之间无拦截判断:无论
$errorMsg是否存在错误,代码都会无条件执行后续PDO插入操作 - 后端变量名拼写错误:校验姓氏时判断的是
empty($lastname),但接收表单值存储的变量为$surname,该校验规则永远不会触发 - 下拉选项默认值未做拦截:性别、种族下拉框默认值为字符串
0,PHP中empty("0")会被判定为空,但原有逻辑未拦截该默认值,会把未选择的0值当成合法数据写入 - 前端错误输出逻辑错误:一是PHP字符串拼接语法错误,变量被包裹在单引号内无法解析;二是除姓名字段外,其余字段的错误循环都错误引用了
$nameErrors变量,导致对应错误无法正常显示 - 缺失必要校验与安全处理:无邮箱格式校验、无用户条款同意校验、密码明文存储、未处理用户名/邮箱重复注册的场景、未做表单值回填,用户提交失败后需要重新填写所有内容
修复方案
采用标准的POST-Redirect-GET模式处理表单,校验不通过时携带错误信息和旧输入跳回注册页,校验完全通过后才执行入库操作。
1. 后端处理文件(includes/register-inc.php)修复
<?php // 开启session用于跨页面传递错误信息和旧表单值 session_start(); if(isset($_POST["submit"])) { // 初始化错误数组,避免未定义变量报错 $errorMsg = []; // 接收表单数据,先做默认值处理避免未定义索引报错 $name = isset($_POST["name"]) ? trim($_POST["name"]) : ''; $surname = isset($_POST["surname"]) ? trim($_POST["surname"]) : ''; $gender = isset($_POST["gender"]) ? trim($_POST["gender"]) : ''; $race = isset($_POST["race"]) ? trim($_POST["race"]) : ''; $email = isset($_POST["email"]) ? strtolower(trim($_POST["email"])) : ''; $username = isset($_POST["username"]) ? trim($_POST["username"]) : ''; $pwd = isset($_POST["password"]) ? $_POST["password"] : ''; $pwdRepeat = isset($_POST["retype_password"]) ? $_POST["retype_password"] : ''; $terms = isset($_POST["terms"]) ? $_POST["terms"] : ''; $joined = date("Y-m-d H:i:s"); // 字段规则校验 if(empty($name)) { $errorMsg[0][] = "Name required!"; } // 修正之前写错的变量名$lastname为$surname if(empty($surname)) { $errorMsg[1][] = "Last name required!"; } // 拦截下拉框默认0值 if(empty($gender) || $gender == '0') { $errorMsg[2][] = "Please select gender!"; } // 拦截下拉框默认0值 if(empty($race) || $race == '0') { $errorMsg[3][] = "Please select your race!"; } if(empty($email)) { $errorMsg[4][] = "Email required!"; } elseif(!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errorMsg[4][] = "Invalid email format!"; } if(empty($username)) { $errorMsg[5][] = "Username required!"; } if(empty($pwd)) { $errorMsg[6][] = "Password required!"; } elseif(strlen($pwd) < 8) { $errorMsg[6][] = "Password must be at least 8 characters"; } if($pwd !== $pwdRepeat) { $errorMsg[7][] = "Password don't match!"; } // 增加条款同意校验 if($terms !== 'accepted') { $errorMsg[8][] = "You must accept the terms and conditions to register!"; } // 核心拦截逻辑:无任何错误时才执行数据库入库 if(empty($errorMsg)) { try { $pdo = require_once '../classes/DB.php'; // 密码哈希加密,禁止明文存储 $hashedPwd = password_hash($pwd, PASSWORD_DEFAULT); $query = 'INSERT INTO users (name, surname, gender, race, email, username, password, joined) VALUES (?, ?, ?, ?, ?, ?, ?, ?)'; $stmt = $pdo->prepare($query); $stmt->execute([$name, $surname, $gender, $race, $email, $username, $hashedPwd, $joined]); $register_id = $pdo->lastInsertId(); // 注册成功存提示信息,跳转到登录页 $_SESSION["success_msg"] = 'You have successfully registered as register id ' . $register_id . '. You may proceed to login.'; header("Location: ../login.php"); exit(); } catch (PDOException $e) { // 处理唯一约束冲突(用户名/邮箱重复) if(str_contains($e->getMessage(), 'username')) { $errorMsg[5][] = "This username is already taken!"; } elseif(str_contains($e->getMessage(), 'email')) { $errorMsg[4][] = "This email is already registered!"; } else { $errorMsg[] = ["Registration failed, please try again later."]; } } } // 存在错误时,把错误和旧表单值存入session,跳回注册页 $_SESSION["errorMsg"] = $errorMsg; $_SESSION["old_input"] = $_POST; header("Location: ../register.php"); exit(); } // 非POST请求直接跳回注册页 header("Location: ../register.php"); exit(); ?>
2. 前端注册页(register.php)修复
<?php // 开启session session_start(); // 取出错误信息和旧表单值,读取后立即清除避免刷新重复显示 $errorMsg = isset($_SESSION["errorMsg"]) ? $_SESSION["errorMsg"] : []; $oldInput = isset($_SESSION["old_input"]) ? $_SESSION["old_input"] : []; unset($_SESSION["errorMsg"], $_SESSION["old_input"]); ?> <form action="includes/register-inc.php" method="post"> <?php if(isset($errorMsg[0])) { foreach($errorMsg[0] as $nameErrors) { // 修正字符串拼接错误 echo '<p class="error-msg">'.$nameErrors.'</p>'; } } ?> <!-- 回填用户之前输入的内容 --> <input type="text" name="name" placeholder="Type your firstname(s)" value="<?php echo isset($oldInput['name']) ? htmlspecialchars($oldInput['name']) : ''; ?>"> <?php if(isset($errorMsg[1])) { foreach($errorMsg[1] as $surnameErrors) { // 修正错误引用的变量名 echo '<p class="error-msg">'.$surnameErrors.'</p>'; } } ?> <input type="text" name="surname" placeholder="Type your surname" value="<?php echo isset($oldInput['surname']) ? htmlspecialchars($oldInput['surname']) : ''; ?>"> <div class="row"> <?php if(isset($errorMsg[2])) { foreach($errorMsg[2] as $genderErrors) { echo '<p class="error-msg">'.$genderErrors.'</p>'; } } ?> <select name="gender" class="gender"> <option value="0" selected disabled>Select your Gender</option> <option value="male" <?php echo (isset($oldInput['gender']) && $oldInput['gender'] == 'male') ? 'selected' : ''; ?>>Male</option> <option value="female" <?php echo (isset($oldInput['gender']) && $oldInput['gender'] == 'female') ? 'selected' : ''; ?>>Female</option> </select> <?php if(isset($errorMsg[3])) { foreach($errorMsg[3] as $raceErrors) { echo '<p class="error-msg">'.$raceErrors.'</p>'; } } ?> <select name="race" class="race"> <option value="0" selected disabled>Select your Race</option> <option value="african" <?php echo (isset($oldInput['race']) && $oldInput['race'] == 'african') ? 'selected' : ''; ?>>African</option> <option value="asian" <?php echo (isset($oldInput['race']) && $oldInput['race'] == 'asian') ? 'selected' : ''; ?>>Asian</option> <option value="caucasian" <?php echo (isset($oldInput['race']) && $oldInput['race'] == 'caucasian') ? 'selected' : ''; ?>>Caucasian</option> <option value="mixed-race" <?php echo (isset($oldInput['race']) && $oldInput['race'] == 'mixed-race') ? 'selected' : ''; ?>>Mixed Race</option> <option value="indian" <?php echo (isset($oldInput['race']) && $oldInput['race'] == 'indian') ? 'selected' : ''; ?>>Indian</option> <option value="other" <?php echo (isset($oldInput['race']) && $oldInput['race'] == 'other') ? 'selected' : ''; ?>>Other</option> </select> </div> <?php if(isset($errorMsg[4])) { foreach($errorMsg[4] as $emailErrors) { echo '<p class="error-msg">'.$emailErrors.'</p>'; } } ?> <input type="email" name="email" placeholder="Type your email address" value="<?php echo isset($oldInput['email']) ? htmlspecialchars($oldInput['email']) : ''; ?>"> <?php if(isset($errorMsg[5])) { foreach($errorMsg[5] as $usernameErrors) { echo '<p class="error-msg">'.$usernameErrors.'</p>'; } } ?> <input type="text" name="username" placeholder="Create username" value="<?php echo isset($oldInput['username']) ? htmlspecialchars($oldInput['username']) : ''; ?>" autocomplete="off"> <?php if(isset($errorMsg[6])) { foreach($errorMsg[6] as $passwordErrors) { echo '<p class="error-msg">'.$passwordErrors.'</p>'; } } ?> <input type="password" name="password" placeholder="Create password"> <?php if(isset($errorMsg[7])) { foreach($errorMsg[7] as $matchErrors) { echo '<p class="error-msg">'.$matchErrors.'</p>'; } } ?> <?php if(isset($errorMsg[8])) { foreach($errorMsg[8] as $termErrors) { echo '<p class="error-msg">'.$termErrors.'</p>'; } } ?> <input type="password" name="retype_password" placeholder="Re-type password"> <div class="text-white"> <div class="link-white"> <label for="terms">I accept the <a href="terms.php">Terms and Conditions</a>.</label> <input type="checkbox" name="terms" value="accepted" <?php echo isset($oldInput['terms']) ? 'checked' : ''; ?>> </div> </div> <button type="submit" name="submit" class="contact-btn2">Register</button> </form>
额外配置建议
- 给数据库
users表的username和email字段添加唯一索引,从数据库层面阻止重复数据写入 - 登录校验密码时使用
password_verify($inputPwd, $dbHashedPwd)方法匹配哈希值,不可直接明文对比 - 生产环境关闭PHP错误显示,避免泄露数据库敏感信息
内容的提问来源于stack exchange,提问作者Itumeleng Kgosana
相关产品推荐
相关产品推荐

