打造一個輕量級論壇/留言板,功能包含:
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(30) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
role ENUM('guest','user','admin') DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE forums (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description TEXT,
sort_order INT DEFAULT 0,
allow_guest_post TINYINT(1) DEFAULT 0
);
CREATE TABLE topics (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
forum_id INT UNSIGNED NOT NULL,
user_id INT UNSIGNED NOT NULL,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
is_sticky TINYINT(1) DEFAULT 0,
is_essence TINYINT(1) DEFAULT 0,
views INT UNSIGNED DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (forum_id) REFERENCES forums(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
CREATE TABLE posts (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
topic_id INT UNSIGNED NOT NULL,
user_id INT UNSIGNED NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (topic_id) REFERENCES topics(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
/config.php # 設定檔(DB連線、常數)
/functions.php # 通用函式(驗證、清理、分頁、CSRF)
/header.php # 頁首模板
/footer.php # 頁尾模板
/index.php # 論壇首頁(版塊列表)
/forum.php # 版塊頁(主題列表、發文表單)
/topic.php # 主題頁(貼文列表、回覆表單)
/post.php # 發文/回覆/編輯處理
/user.php # 註冊/登入/登出/個人資料
/admin/ # 後台目錄
/index.php # 後台首頁
/forums.php # 版塊管理
/topics.php # 主題管理
/users.php # 用戶管理
// 註冊
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT);
// 登入驗證
if (password_verify($_POST['password'], $user['password_hash'])) { /* 成功 */ }
session_start();
// 登入成功
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['role'] = $user['role'];
session_regenerate_id(true); // 防 Session Fixation
// 表單生成
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
echo '<input type="hidden" name="csrf_token" value="' . $_SESSION['csrf_token'] . '">';
// 處理驗證
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) die('CSRF 驗證失敗');
function h($str) { return htmlspecialchars($str, ENT_QUOTES, 'UTF-8'); }
// 所有輸出到 HTML 的變數必須經 h() 處理
function paginate($total, $per_page, $page, $url_pattern) {
$pages = ceil($total / $per_page);
$page = max(1, min($page, $pages));
$start = ($page - 1) * $per_page;
// 返回 ['limit'=>$start.','.$per_page, 'html'=>分頁HTML]
}
function can($action, $resource = null) {
$role = $_SESSION['role'] ?? 'guest';
$uid = $_SESSION['user_id'] ?? 0;
$rules = [
'post' => ['user','admin'],
'reply' => ['user','admin'],
'edit_own' => ['user','admin'],
'delete_own'=> ['user','admin'],
'manage_forum'=> ['admin'],
'manage_topic'=> ['admin'],
'manage_user'=> ['admin'],
];
if (!in_array($role, $rules[$action] ?? [])) return false;
if ($action === 'edit_own' || $action === 'delete_own') {
return $resource['user_id'] == $uid; // 擁有者檢查
}
return true;
}
| 議題 | 建議 |
|---|---|
| SQL 注入 | 全程使用 PDO 預處理語句,絕不拼接變數。 |
| XSS | 輸出轉義 h();富文本編輯器需後端 HTMLPurifier 白名單過濾。 |
| 暴力破解 | 登入失敗計數 + 延遲 + 驗證碼;使用 password_hash 高成本雜湊。 |
| 檔案上傳 | 若加入附件,嚴格驗證類型、重命名、存放非 Web 目錄、禁用腳本執行。 |
| 效能 | 適當索引;熱門列表頁引入 Redis 快取;靜態資源 CDN。 |
| 擴展性 | 採用 MVC 結構(如微型框架 Flight/Slim 或自製路由),分離業務邏輯與視圖。 |
本教程提供骨架與核心邏輯,實際開發中請逐步完善錯誤處理、日誌記錄、單元測試、部署腳本等工程化環節。祝編碼順利!