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

如何基于PostgreSQL和PHP实现注册用户名重复校验功能

注册环节用户名重复校验实现方案

首先要先给数据库register表的username字段加唯一约束,从数据库层面阻止重复用户名插入,避免并发请求下的脏数据:

ALTER TABLE register ADD CONSTRAINT unique_username UNIQUE (username);

基础实现:表单提交后页内显示错误提示

你原来的代码把表单页和处理逻辑分开,没法直接在原页显示提示,最简便的改法是把两个部分合并到同一个sign_up.php文件里,通过变量传递错误信息,直接在页面渲染提示。
另外原代码有两个必须修复的问题:

  • 调用header()做跳转后没有加exit终止执行,后续的数据库插入逻辑依然会运行
  • 直接把用户输入拼接进SQL语句,存在严重的SQL注入风险,需要改用参数化查询

修正后的完整sign_up.php代码如下:

<?php
$errorMsg = '';
$host = "localhost";
$dbusername = "postgres";
$dbpassword = "admroot";
$db = "local_db_server_test";
$con = pg_connect("host=$host dbname=$db user=$dbusername password=$dbpassword") or die ("Could not connect to Server\n");

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = trim($_POST['username']);
    $password = $_POST['password'];

    if (strlen($password) < 6) {
        pg_close($con);
        header("Location:sign_up_pass_err.html");
        exit;
    }

    // 校验用户名是否已存在
    $checkSql = "SELECT 1 FROM register WHERE username = $1";
    $checkRes = pg_query_params($con, $checkSql, [$username]);
    if (pg_num_rows($checkRes) > 0) {
        $errorMsg = "username is already taken";
        pg_free_result($checkRes);
    } else {
        // 校验通过,执行插入
        $insertSql = "INSERT INTO register(username, password) VALUES ($1, crypt($2, gen_salt('md5')))";
        $insertRes = pg_query_params($con, $insertSql, [$username, $password]);
        if ($insertRes) {
            pg_close($con);
            header("Location: login.html");
            exit;
        } else {
            $errorMsg = "Registration failed, please try again later";
        }
    }
}
pg_close($con);
?>
<!DOCTYPE html>
<html>
<head>
    <style>.err-tip { color: #f00; margin: 6px 0; font-size: 14px; }</style>
</head>
<body>
    <form action="sign_up.php" method="post">
        <input type="text" name="username" placeholder="Username" required 
               value="<?php echo isset($_POST['username']) ? htmlspecialchars($_POST['username']) : ''; ?>">
        <br>
        <?php if ($errorMsg): ?>
            <div class="err-tip"><?php echo htmlspecialchars($errorMsg); ?></div>
        <?php endif; ?>
        <br>
        <input type="password" name="password" placeholder="Password" required><br><br>
        <input type="submit" value="Sign up">
    </form>
</body>
</html>

这个实现的逻辑很直接:

  • 提交表单后先查库判断用户名是否存在,存在就把错误信息存到$errorMsg变量
  • 页面渲染时如果$errorMsg不为空,直接把提示显示在用户名输入框下方
  • 校验失败时自动保留用户之前输入的用户名,不用重复填写
  • 所有输出到页面的动态内容都用htmlspecialchars转义,避免XSS漏洞

优化方案:输入时实时异步校验

如果需要提升体验,让用户输入完用户名不用点提交就知道是否被占用,可以加前端异步校验逻辑。

注意:前端异步校验仅用于提升用户体验,表单提交时的后端重复校验必须保留,前端校验逻辑可以被随意绕过,不能作为唯一的校验依据。

  1. 新增check_username.php校验接口:
<?php
$host = "localhost";
$dbusername = "postgres";
$dbpassword = "admroot";
$db = "local_db_server_test";
$con = pg_connect("host=$host dbname=$db user=$dbusername password=$dbpassword");

$res = ['exists' => false];
if (isset($_GET['username']) && trim($_GET['username'])) {
    $username = trim($_GET['username']);
    $checkSql = "SELECT 1 FROM register WHERE username = $1";
    $query = pg_query_params($con, $checkSql, [$username]);
    $res['exists'] = pg_num_rows($query) > 0;
}
header('Content-Type: application/json');
echo json_encode($res);
pg_close($con);
?>
  1. 在注册页</body>标签前加入JS逻辑,监听用户名输入框失焦事件:
<script>
const usernameInput = document.querySelector('input[name="username"]');
const tipDom = document.querySelector('.err-tip');
usernameInput.addEventListener('blur', async () => {
    const uname = usernameInput.value.trim();
    if (!uname) return;
    const resp = await fetch(`check_username.php?username=${encodeURIComponent(uname)}`);
    const data = await resp.json();
    tipDom.textContent = data.exists ? 'username is already taken' : '';
})
</script>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 15:39:14