資料庫準備
CREATE TABLE pm_user (
u_id INT AUTO_INCREMENT PRIMARY KEY,
u_user VARCHAR(50) NOT NULL UNIQUE,
u_pwd VARCHAR(255) NOT NULL, -- 存 password_hash()
u_name VARCHAR(50)
);
核心邏輯檔案
1. 登入頁 login.htm(靜態表單)
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>登入</title></head>
<body>
<form method="post" action="login.php">
帳號:<input type="text" name="user" id="user" required><br>
密碼:<input type="password" name="pwd" id="pwd" required><br>
<button type="submit" name="button">提交</button>
</form>
</body></html>
2. 登入驗證 login.php
<?php
session_start();
// 現代寫法:使用 mysqli + 預處理 + password_hash
$mysqli = new mysqli('localhost', 'root', 'password', 'dbname');
if ($mysqli->connect_errno) die("DB連線失敗");
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$user = trim($_POST['user'] ?? '');
$pwd = $_POST['pwd'] ?? '';
if ($user && $pwd) {
$stmt = $mysqli->prepare("SELECT u_id, u_user, u_pwd FROM pm_user WHERE u_user = ?");
$stmt->bind_param("s", $user);
$stmt->execute();
$result = $stmt->get_result();
if ($row = $result->fetch_assoc()) {
if (password_verify($pwd, $row['u_pwd'])) {
// 登入成功,建立 session
$_SESSION['user_id'] = $row['u_id'];
$_SESSION['user'] = $row['u_user'];
$_SESSION['name'] = $row['u_name'];
// 記住我功能(可選)
if (!empty($_POST['remember'])) {
$token = bin2hex(random_bytes(32));
setcookie('auth_token', $token, time() + 30*86400, '/', '', true, true);
// 這裡應將 token 存入資料庫關聯 user_id
}
header('Location: index.php');
exit;
}
}
$error = "帳號或密碼錯誤";
} else {
$error = "請輸入帳號密碼";
}
}
?>
<!DOCTYPE html>
<html><body>
<?php if (!empty($error)) echo "<p style='color:red'>$error</p>"; ?>
<form method="post">
帳號:<input type="text" name="user" required><br>
密碼:<input type="password" name="pwd" required><br>
<label><input type="checkbox" name="remember"> 記住我</label><br>
<button type="submit">登入</button>
</form>
</body></html>
3. 頁面存取控制 auth.php(共用引入)
<?php
session_start();
function checkLogin() {
// 1. Session 已存在
if (isset($_SESSION['user_id'])) return true;
// 2. 嘗試從 Cookie 恢復(記住我功能)
if (isset($_COOKIE['auth_token'])) {
$token = $_COOKIE['auth_token'];
// 這裡查資料庫驗證 token 有效性並取得 user_id
// 簡化示範:
$mysqli = new mysqli('localhost', 'root', 'password', 'dbname');
$stmt = $mysqli->prepare("SELECT u_id, u_user, u_name FROM pm_user WHERE auth_token = ?");
$stmt->bind_param("s", $token);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
if ($row) {
$_SESSION['user_id'] = $row['u_id'];
$_SESSION['user'] = $row['u_user'];
$_SESSION['name'] = $row['u_name'];
return true;
}
}
return false;
}
// 未登入導向登入頁
if (!checkLogin()) {
header('Location: login.htm');
exit;
}
?>
4. 會員頁 index.php
<?php require 'auth.php'; ?>
<!DOCTYPE html>
<html><body>
<h2>歡迎,<?= htmlspecialchars($_SESSION['user']) ?></h2>
<p>User ID: <?= $_SESSION['user_id'] ?></p>
<a href="logout.php">登出</a>
</body></html>
5. 登出 logout.php
<?php
session_start();
// 清除記住我 Cookie
if (isset($_COOKIE['auth_token'])) {
setcookie('auth_token', '', time() - 3600, '/', '', true, true);
// 這裡也應清除資料庫中的 token
}
// 銷毀 Session
$_SESSION = [];
session_destroy();
header('Location: login.htm');
exit;
?>
安全性關鍵點總結
| 項目 | 建議做法 |
| 密碼儲存 | password_hash($pwd, PASSWORD_DEFAULT) + password_verify() |
| SQL 注入防護 | 全程使用預處理語句 |
| Session 劫持防護 | session.cookie_httponly=1、session.cookie_secure=1 (HTTPS)、session.use_strict_mode=1 |
| CSRF 防護 | 表單加入 $_SESSION['csrf_token'] 驗證 |
| 暴力破解防護 | 登入失敗計數 + 延遲/鎖定 + 驗證碼 |
| 記住我 Token | 隨機 32+ 位元組、資料庫存雜湊、設定過期時間、HTTPS Only |
原始碼中已棄用功能提醒
mysql_* 函數:PHP 7.0 移除,必須改用 mysqli 或 PDO
session_register():PHP 5.4 移除,直接操作 $_SESSION
SHA() 資料庫函數:不可逆但非專為密碼設計,請用 password_hash()