首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 檢查 MySQL 用戶名是否存在:Prepared Statement 防注入最佳實踐

     編輯:PHP 相關知識

註冊系統核心邏輯:檢查用戶名唯一性再插入。本文示範 mysqli Prepared Statement 防 SQL 注入、正確處理競態條件、避免已棄用 mysql_* 函式。

完整註冊流程範例

<?php
// register.php
require_once 'db.php'; // 回傳 mysqli 實例 $mysqli

$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';

if ($username === '' || $password === '') {
    exit(json_encode(['ok' => false, 'msg' => '欄位不可為空']));
}

// 1. 檢查是否存在(SELECT ... FOR UPDATE 鎖定間隙,防併發重複)
$stmt = $mysqli->prepare('SELECT id FROM users WHERE username = ? FOR UPDATE');
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->store_result();

if ($stmt->num_rows > 0) {
    exit(json_encode(['ok' => false, 'msg' => '用戶名已存在']));
}
$stmt->close();

// 2. 密碼雜湊(bcrypt/argon2)
$hash = password_hash($password, PASSWORD_BCRYPT); // PHP 5.5+

// 3. 插入新用戶
$stmt = $mysqli->prepare('INSERT INTO users (username, password_hash) VALUES (?, ?)');
$stmt->bind_param('ss', $username, $hash);
if ($stmt->execute()) {
    echo json_encode(['ok' => true, 'msg' => '註冊成功', 'uid' => $mysqli->insert_id]);
} else {
    echo json_encode(['ok' => false, 'msg' => '寫入失敗:' . $stmt->error]);
}
$stmt->close();
?>

關鍵點解析

  1. Prepared Statement:? 佔位符 + bind_param,徹底杜絕 SQL 注入。
  2. SELECT ... FOR UPDATE:在事務中鎖定該記錄/間隙,防止兩個並發請求同時通過檢查。需配合 $mysqli->begin_transaction() / commit()。
  3. 唯一索引:資料庫層面 ALTER TABLE users ADD UNIQUE KEY uniq_username (username) 是最後防線,插入失敗會拋 1062 Duplicate entry。
  4. password_hash / password_verify:內建 bcrypt/argon2,自動處理鹽值與成本因子,嚴禁自行 MD5/SHA1。
  5. 棄用函式:mysql_connect、mysql_query、mysql_num_rows 自 PHP 7.0 移除,請全面遷移至 mysqli 或 PDO。

PDO 寫法(推薦)

$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8mb4', 'user', 'pass', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$pdo->beginTransaction();
$stmt = $pdo->prepare('SELECT id FROM users WHERE username = ? FOR UPDATE');
$stmt->execute([$username]);
if ($stmt->fetch()) { $pdo->rollBack(); exit('exists'); }
$stmt = $pdo->prepare('INSERT INTO users (username, password_hash) VALUES (?, ?)');
$stmt->execute([$username, password_hash($password, PASSWORD_BCRYPT)]);
$pdo->commit();
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved