PHP注册功能重复条目拦截失效 提示已存在仍创建账号问题
问题根因
你加的校验逻辑没生效、重复账号依然能创建的核心原因有3个:
- 只写了用户查询语句,没加判断逻辑,也没在查到重复用户时终止后续代码执行,查询完程序还是会走到INSERT插入的流程
- 校验代码里用的数据库连接变量是
$db,但你当前类里的数据库连接实例是$this->conn,变量不匹配会导致查询本身执行失败,根本没拿到正确的重复校验结果 - 前端把所有非1的返回值都统一显示为“Email already exist”,哪怕后端报错、插入逻辑异常也会弹这个提示,和实际校验结果没有对应关系
修复方案
1. 调整后端校验逻辑位置和写法
把重复校验放到所有SQL拼接、写入操作的最前面,使用类内正确的数据库连接,查到重复用户时直接返回错误码终止执行,同时兼容注册、更新用户信息两个场景:
public function register(){ extract($_POST); // 重复用户校验:放在所有数据库写操作之前执行 if(empty($id)){ // 新用户注册场景:校验用户名是否已存在 $check = $this->conn->prepare("SELECT id FROM users WHERE username = ? LIMIT 1"); $check->bind_param("s", $username); $check->execute(); $check_res = $check->get_result(); if($check_res->num_rows > 0){ return 3; // 返回3代表用户名重复,直接终止后续逻辑 } }else{ // 编辑已有用户场景:排除当前用户自身,校验用户名是否被其他人占用 $check = $this->conn->prepare("SELECT id FROM users WHERE username = ? AND id != ? LIMIT 1"); $check->bind_param("si", $username, $id); $check->execute(); $check_res = $check->get_result(); if($check_res->num_rows > 0){ return 3; } } $data = ''; foreach($_POST as $k => $v){ if(!in_array($k,array('id','password'))){ if(!empty($data)) $data .=" , "; // 对输入内容做转义,避免SQL注入 $v = $this->conn->real_escape_string($v); $data .= " {$k} = '{$v}' "; } } if(!empty($password)){ $password = md5($password); if(!empty($data)) $data .=" , "; $data .= " `password` = '{$password}' "; } if(isset($_FILES['img']) && $_FILES['img']['tmp_name'] != ''){ $fname = 'uploads/'.strtotime(date('y-m-d H:i')).'_'.$_FILES['img']['name']; $move = move_uploaded_file($_FILES['img']['tmp_name'],'../'. $fname); if($move){ $data .=" , avatar = '{$fname}' "; if(isset($_SESSION['userdata']['avatar']) && is_file('../'.$_SESSION['userdata']['avatar'])) unlink('../'.$_SESSION['userdata']['avatar']); } } if(empty($id)){ $data .= " ,`type` = '2' "; $qry = $this->conn->query("INSERT INTO users set {$data}"); if($qry){ return 1; }else{ return 2; } }else{ $qry = $this->conn->query("UPDATE users set $data where id = {$id}"); if($qry){ $this->settings->set_flashdata('success','User Details successfully updated.'); foreach($_POST as $k => $v){ if($k != 'id'){ if(!empty($data)) $data .=" , "; $this->settings->set_userdata($k,$v); } } if(isset($fname) && isset($move)) $this->settings->set_userdata('avatar',$fname); return 1; }else{ return "UPDATE users set $data where id = {$id}"; } } }
2. 修改前端回调逻辑,适配不同错误码
调整AJAX的success回调,对不同返回值做对应提示,不要所有错误都显示邮箱已存在:
$('#manage-user').submit(function(e){ e.preventDefault(); start_loader() $.ajax({ url:_base_url_+'classes/Users.php?f=register', data: new FormData($(this)[0]), cache: false, contentType: false, processData: false, method: 'POST', type: 'POST', success:function(resp){ if(resp ==1){ alert('Registration Successful. You may now log-in.') window.location.reload() }else if(resp == 3){ $('#msg').html('<div class="alert alert-danger">Username already exist</div>') end_loader() }else{ $('#msg').html('<div class="alert alert-danger">Registration failed, please retry</div>') end_loader() } } }) })
优化建议
- 给数据库
users表的username字段加唯一索引,从数据库层面彻底拦截重复用户名,就算代码逻辑出问题也不会插入重复数据 - 不要用md5存储密码,替换为PHP原生的
password_hash()做密码加密、password_verify()做密码校验,安全性更高 - 所有数据库操作尽量用预处理参数绑定,不要直接拼接用户输入到SQL语句里,避免SQL注入漏洞
内容的提问来源于stack exchange,提问作者Jonjon Candare
相关产品推荐
相关产品推荐

