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

PHP 檢查使用者名稱是否存在於 MySQL:Prepared Statement 防注入完整範例

     編輯:PHP 綜合知識

註冊系統中檢查使用者名稱是否已存在是基本功能,但直接拼接 SQL 字串極易造成 SQL Injection。本文展示正確做法:使用 MySQLi Prepared Statement 進行參數化查詢,並修正原文中的邏輯錯誤(如 mysqli_num_rows 用法、變數拼寫)。

❌ 錯誤示範(原文程式碼問題)

  • 直接將 $_REQUEST['username'] 拼入 SQL → SQL Injection 風險極高。
  • mysql_num_rows($result) 是舊 mysql_* 函式,與 mysqli 混用會報錯。
  • 變數 $username / $password 未過濾、未驗證。
  • 邏輯倒置:查到資料應顯示「已存在」,原文寫反。

✅ 正確實作:MySQLi Prepared Statement

<?php
// 1. 取得並基本驗證輸入
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';

if ($username === '') {
    exit('使用者名稱不可為空');
}

// 2. 建立連線(建議改用 PDO,此處示範 MySQLi)
$mysqli = new mysqli('localhost', 'root', '', 'my_db');
if ($mysqli->connect_errno) {
    exit('資料庫連線失敗: ' . $mysqli->connect_error);
}
$mysqli->set_charset('utf8mb4');

// 3. 檢查使用者是否存在(Prepared Statement)
$stmt = $mysqli->prepare('SELECT id FROM `user` WHERE `username` = ? LIMIT 1');
$stmt->bind_param('s', $username);
$stmt->execute();
$stmt->store_result(); // 重要:取得行數前必須呼叫

if ($stmt->num_rows > 0) {
    echo '此使用者名稱已存在';
    $stmt->close();
    $mysqli->close();
    exit;
}
$stmt->close();

// 4. 插入新使用者(密碼務必 hash!)
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
$stmt = $mysqli->prepare('INSERT INTO `user` (`username`, `password`) VALUES (?, ?)');
$stmt->bind_param('ss', $username, $passwordHash);
if ($stmt->execute()) {
    echo '註冊成功,新增 1 筆資料';
} else {
    echo '錯誤: ' . $stmt->error;
}
$stmt->close();
$mysqli->close();
?>

關鍵安全點總整理

項目錯誤做法正確做法
SQL 參數字串拼接 'WHERE username=\"$username\"'Prepared Statement WHERE username = ? + bind_param
密碼儲存明文儲存password_hash() + password_verify()
字元集預設 latin1set_charset('utf8mb4')
錯誤處理直接 die(mysql_error()) 洩漏結構記錄日誌、回傳通用訊息
輸入驗證無長度、格式、唯一性驗證

進階建議:改用 PDO

<?php
$pdo = new PDO('mysql:host=localhost;dbname=my_db;charset=utf8mb4', 'root', '', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false, // 真正的預處理
]);

$stmt = $pdo->prepare('SELECT id FROM `user` WHERE `username` = ?');
$stmt->execute([$username]);
if ($stmt->fetch()) {
    exit('使用者名稱已存在');
}

$hash = password_hash($password, PASSWORD_DEFAULT);
$pdo->prepare('INSERT INTO `user` (`username`, `password`) VALUES (?, ?)')
    ->execute([$username, $hash]);
echo '註冊成功';
?>

PDO 程式碼更簡潔、支援多資料庫、預處理預設為真正預處理(EMULATE_PREPARES=false),是現代 PHP 專案的首選資料庫介面。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved