整體架構
index.htm (表單 + jQuery 驗證 + AJAX)
↓ POST JSON
_process.php (伺服端驗證 + 防注入 + MySQLi 入庫)
↓ JSON 回應 {res: 1/-1, msg: '...'}
前端顯示結果
前端 index.htm 關鍵程式碼
<form id="regForm">
<input type="text" id="name" name="name" placeholder="使用者">
<input type="text" id="ages" name="ages" placeholder="年齡">
<input type="password" id="password" name="password" placeholder="密碼">
<input type="text" id="addr" name="addr" placeholder="地址">
<input type="email" id="email" name="email" placeholder="Email">
<button type="button" id="btnSubmit">註冊</button>
</form>
<p id="result"></p>
<span id="msg" style="display:none">處理中...</span>
<script src="jquery-1.3.1.js"></script>
<script>
$('#btnSubmit').click(function(){
var data = {
name: $.trim($('#name').val()),
ages: $.trim($('#ages').val()),
pass: $.trim($('#password').val()),
addr: $.trim($('#addr').val()),
email: $.trim($('#email').val())
};
// 前端驗證 (略)
$.post('_process.php', data, function(res){
$('#result').toggleClass('error', res.res===-1).text(res.msg);
}, 'json');
});
$('#msg').ajaxStart(function(){$(this).fadeIn();})
.ajaxStop(function(){$(this).fadeOut();});
</script>
後端 _process.php 完整程式碼
<?php
header('Content-Type: application/json; charset=utf-8');
sleep(1); // 模擬延遲
$conn = mysqli_connect('localhost', 'root', 'root', 'register');
if (!$conn) die(json_encode(['res'=>-1,'msg'=>'DB連線失敗']));
mysqli_set_charset($conn, 'utf8');
function clean($conn, $str) {
$str = trim($str);
if (!get_magic_quotes_gpc()) $str = addslashes($str);
return stripslashes(htmlspecialchars($str, ENT_QUOTES, 'UTF-8'));
}
$name = clean($conn, $_POST['name'] ?? '');
$ages = isset($_POST['ages']) ? intval($_POST['ages']) : 0;
$pass = clean($conn, $_POST['pass'] ?? '');
$addr = clean($conn, $_POST['addr'] ?? '');
$email = clean($conn, $_POST['email'] ?? '');
// 伺服端二次驗證
if ($name==='') die(json_encode(['res'=>-1,'msg'=>'請輸入姓名']));
if ($ages===0) die(json_encode(['res'=>-1,'msg'=>'請輸入年齡']));
if ($pass==='') die(json_encode(['res'=>-1,'msg'=>'請輸入密碼']));
if ($addr==='') die(json_encode(['res'=>-1,'msg'=>'請輸入地址']));
if ($email==='' || !filter_var($email, FILTER_VALIDATE_EMAIL))
die(json_encode(['res'=>-1,'msg'=>'Email格式錯誤']));
// 檢查帳號唯一
$sql = "SELECT COUNT(*) AS cnt FROM tb_register WHERE username=?";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 's', $name);
mysqli_stmt_execute($stmt);
mysqli_stmt_bind_result($stmt, $cnt);
mysqli_stmt_fetch($stmt);
mysqli_stmt_close($stmt);
if ($cnt > 0) die(json_encode(['res'=>-1,'msg'=>'帳號已存在']));
// 入庫 (Prepared Statement 防注入)
$add_day = date('YmdHis');
$sql = "INSERT INTO tb_register (username, ages, password, address, email, add_day)
VALUES (?, ?, ?, ?, ?, ?)";
$stmt = mysqli_prepare($conn, $sql);
mysqli_stmt_bind_param($stmt, 'sissss', $name, $ages, $pass, $addr, $email, $add_day);
mysqli_stmt_execute($stmt);
mysqli_stmt_close($stmt);
echo json_encode(['res'=>1,'msg'=>'註冊成功!']);
?>
關鍵安全點總結
| 風險 | 對策 |
| SQL Injection | Prepared Statement (mysqli_prepare + bind_param) |
| XSS 輸出 | htmlspecialchars(ENT_QUOTES, 'UTF-8') |
| Magic Quotes 相容 | get_magic_quotes_gpc() 判斷後 addslashes |
| 編碼不一致 | mysqli_set_charset('utf8') + header charset=utf-8 |
| 前端繞過驗證 | 伺服端完整二次驗證 (不可信任前端) |
資料表結構建議
CREATE TABLE tb_register (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
ages TINYINT UNSIGNED NOT NULL,
password VARCHAR(255) NOT NULL, -- 實務應存 hash (password_hash)
address VARCHAR(200) NOT NULL,
email VARCHAR(100) NOT NULL,
add_day DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;