You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OTP验证码验证系统故障排查及替代修复方案咨询

修复OTP验证功能的关键问题及解决方案

核心问题分析

  1. 路径常量使用错误:include_once("__DIR__ ...") 会将__DIR__视为字符串字面量,而非PHP常量,可能导致数据库连接失败(若你实际运行中连接正常,大概率是代码粘贴错误,但需修正)。
  2. OTP类型不匹配:生成的OTP是整数,存入数据库后仍为整数类型,但前端传入的OTP是字符串,使用严格比较!==会判定为不相等。
  3. UPDATE查询逻辑缺陷:WHERE子句同时包含otp和activation_code,但activation_code已是唯一标识,且OTP的字符串格式与数据库中的整数类型不匹配,导致更新无效果。
  4. SQL注入风险:直接拼接用户输入到SQL查询中,存在安全隐患。
  5. 更新结果判断不准确:仅通过mysqli_query返回值判断更新成功,但该函数在查询语法正确时即使无行更新也会返回true。

修正后的注册代码

<?php
// 修复路径常量使用方式
include_once(__DIR__ . '/../connection/conn.php');

if(isset($_POST['submit'])){
    $username = mysqli_real_escape_string($conn, $_POST['username']);
    $email = mysqli_real_escape_string($conn, $_POST['email']);
    $pass = mysqli_real_escape_string($conn, md5($_POST['password']));
    $cpass = mysqli_real_escape_string($conn, md5($_POST['cpassword']));
    $role = 'user';
    $verification_status = '0';
    $otp = mt_rand(1111,9999);    // 生成4位OTP(整数类型)
    $activation_code = rand(time(),10000000);  // 生成唯一激活码

    // 仅检查邮箱是否已存在,无需关联密码
    $select_users = mysqli_query($conn, "SELECT * FROM `userssystem1` WHERE email = '$email'") or die('查询失败');

    if(mysqli_num_rows($select_users) > 0){
        $message[] = '用户已存在!';
    }else{
        if($pass != $cpass){
            $message[] = '确认密码不匹配!';
        }else{
            // 使用预处理语句防止SQL注入
            $stmt = mysqli_prepare($conn, "INSERT INTO `userssystem1`(username, email, password, role, otp, activation_code, verification_status) VALUES(?, ?, ?, ?, ?, ?, ?)");
            mysqli_stmt_bind_param($stmt, "sssssis", $username, $email, $cpass, $role, $otp, $activation_code, $verification_status);
            if(mysqli_stmt_execute($stmt)){
                $message[] = '注册成功!';
                header('location:verify.php?code='.$activation_code);
                exit; // 跳转后终止脚本执行
            }else{
                die('插入失败:' . mysqli_error($conn));
            }
        }
    }
}
?>

修正后的验证代码

<?php
ini_set('display_errors', 1); 
ini_set('display_startup_errors', 1); 
error_reporting(E_ALL);

// 修复路径常量使用方式
include_once(__DIR__ . '/../connection/conn.php');

// 若用户已验证,直接跳转至登录页
if(isset($_GET['code'])){
    $stmt = mysqli_prepare($conn, "SELECT verification_status FROM userssystem1 WHERE activation_code = ?");
    mysqli_stmt_bind_param($stmt, "s", $_GET['code']);
    mysqli_stmt_execute($stmt);
    $result = mysqli_stmt_get_result($stmt);
    if($row = mysqli_fetch_assoc($result)){
        if($row['verification_status'] === 'verified'){
            header('location:login.php');
            exit;
        }
    }
}

if(isset($_POST['submit_otp'])){
    if(isset($_GET['code'])){
        $activation_code = $_GET['code'];
        $otp = $_POST['otp'];

        // 使用预处理语句查询用户信息
        $stmt = mysqli_prepare($conn, "SELECT otp FROM userssystem1 WHERE activation_code = ?");
        mysqli_stmt_bind_param($stmt, "s", $activation_code);
        mysqli_stmt_execute($stmt);
        $resultSelect = mysqli_stmt_get_result($stmt);
        
        if(mysqli_num_rows($resultSelect) > 0){
            $rowSelect = mysqli_fetch_assoc($resultSelect);
            // 统一类型后再做严格比较
            if((string)$rowSelect['otp'] !== $otp){
                echo "<script>alert('请输入正确的OTP!')</script>";
            }else{
                // 仅通过activation_code更新,无需再使用OTP条件
                $stmtUpdate = mysqli_prepare($conn, "UPDATE userssystem1 SET otp = '', verification_status = 'verified' WHERE activation_code = ?");
                mysqli_stmt_bind_param($stmtUpdate, "s", $activation_code);
                mysqli_stmt_execute($stmtUpdate);
                
                // 检查是否有行被更新
                if(mysqli_affected_rows($conn) > 0){
                    echo "<script>alert('邮箱验证成功!')</script>";
                    header("Refresh:1; url=login.php");
                    exit;
                }else{
                    echo "<script>alert('邮箱验证失败,请重试!')</script>";
                }
            }
        }else{
            echo "<script>alert('无效的激活码!')</script>";
            header("Refresh:1; url=signup.php");
            exit;
        }
    }else{
        header("Refresh:1; url=verify.php");
        exit;
    }
}
?>

额外优化建议

  • 密码哈希:md5是极不安全的哈希算法,建议使用password_hash()和password_verify()替代。
  • OTP有效期:添加OTP过期时间字段,防止OTP长期有效。
  • 前端输入验证:在前端限制OTP输入为4位数字,减少无效请求。
  • 错误信息处理:使用更友好的错误提示,避免直接暴露数据库错误。

内容的提问来源于stack exchange,提问作者Frederick Yanclo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 01:50:33