如何修复 CodeIgniter 中 OTP 未写入数据库的问题

8次阅读

如何修复 CodeIgniter 中 OTP 未写入数据库的问题

本文详解 codeigniter 项目中注册时生成并存储 otp 失败的根本原因——模型方法参数传递错误,并提供修正后的控制器与模型代码、安全建议及完整流程说明。

在 CodeIgniter 开发中,常见场景是用户提交邮箱后,系统生成 8 位数字 OTP 并发送至该邮箱,同时将邮箱与 OTP 一同存入数据库(如 cred 表)用于后续验证。但如您所遇问题:邮件成功发出、邮箱入库成功,而 OTP 却未写入数据库——这通常并非逻辑或邮件配置问题,而是数据插入时参数结构错误导致的静默失败。

关键问题定位在控制器 auth.phpregister() 方法中这一行:

$data = $this->user_model->insert('cred', ['email' => $to], ['otp' => ($newotp)]);

此处调用了 user_model->insert() 方法,却传入了 三个参数:$table、$data1、$data2。而您的模型方法定义为:

public function insert($table, $data = array())

即仅接受两个参数:表名 + 待插入数据数组。第三个参数 [‘otp’ => …] 被完全忽略,因此只有 [’email’ => $to] 被传入并执行插入,OTP 自然不会入库。

✅ 正确做法是:将 email 和 OTP 合并为单个关联数组,作为第二个参数传入:

$data = $this->user_model->insert('cred', ['email' => $to, 'otp' => $newotp]);

同时,建议优化模型方法,增强健壮性与可维护性:

✅ 修正后的 user_model.php(推荐):

public function insert($table, $data = []) {     if (empty($data)) {         return FALSE;     }      $this->db->insert($table, $data);     return $this->db->affected_rows() === 1          ? $this->db->insert_id()          : FALSE; }

? 提示:insert_id() 仅在主键为自增整型时有效;若 cred 表无自增主键,可直接返回布尔值。

此外,还需注意以下几点以保障功能安全与可用性:

  • ? OTP 安全性:当前 OTP 以明文形式存入数据库且通过邮件明文发送,存在严重安全隐患。生产环境务必:
    • 使用 password_hash($newotp, PASSword_ARgoN2ID) 加密存储 OTP;
    • 设置 OTP 过期时间(如 5 分钟),并在表中增加 otp_expires_at 字段;
    • 邮件中避免显示完整 OTP,改用「您的验证码是:****1234」或仅提示「请在登录页输入收到的 8 位数字」。
  • ? 邮件发送校验:$this->Others->send_email() 返回值未被检查。建议添加判断,失败时记录日志并回滚或提示用户重试:
    if (!$mail) {     log_message('error', 'OTP email failed for: ' . $to);     $this->session->set_flashdata('error', '验证码发送失败,请重试');     redirect(base_url() . 'auth/register'); }
  • ? OTP 生成优化:当前 rand() 在某些环境下可能不够随机。推荐使用更安全的 random_int()(PHP 7+):
    $newotp = ''; for ($i = 0; $i < 8; $i++) {     $newotp .= random_int(0, 9); }

最后,完整修正后的控制器逻辑应如下(精简关键部分):

public function register() {     $to = trim($this->input->post('email'));     if (!filter_var($to, FILTER_VALIDATE_EMAIL)) {         $this->session->set_flashdata('error', '邮箱格式不正确');         redirect(base_url() . 'auth/register');         return;     }      // 安全 OTP 生成(PHP 7+)     $newotp = str_pad(random_int(0, 99999999), 8, '0', STR_PAD_LEFT);      // 发送邮件     $subject = "OTP FOR LOGIN";     $message = "Dear User,

Thanks for requesting OTP.
Your verification code is: {$newotp}.

this code expires in 5 minutes.

— Auto-generated"; if (!$this->Others->send_email($to, $subject, $message)) { log_message('error', "Email send failed for {$to}"); $this->session->set_flashdata('error', '验证码发送失败,请稍后重试'); redirect(base_url() . 'auth/register'); return; } // 插入邮箱 + OTP(单数组!) $result = $this->user_model->insert('cred', [ 'email' => $to, 'otp' => $newotp, // 生产环境请替换为 password_hash($newotp, PASSWORD_ARGON2ID) 'created_at' => date('Y-m-d H:i:s') ]); if ($result) { $this->session->set_flashdata('success', '验证码已发送,请查收邮箱'); } else { $this->session->set_flashdata('error', '注册信息保存失败'); } redirect(base_url() . 'auth/login'); }

总结:一次看似微小的参数误传(多传一个数组),就可能导致核心认证流程断裂。排查此类问题时,应优先审查方法签名与实际调用是否一致,再结合日志与数据库操作结果交叉验证。遵循“单一职责+明确契约”的编码原则,可大幅提升 CodeIgniter 应用的稳定性与可维护性。

text=ZqhQzanResources