會員登入後發布新主題,包含標題、表情圖示、內容輸入,前端 JS 驗證必填欄位,後端寫入 guestbook 資料表(type=1 表主貼)。
<!DOCTYPE html>
<html><head><title>疑難問題</title>
<link href="mypic/style.css" rel="stylesheet" type="text/css">
</head>
<?php
// 驗證登入 Cookie
if (!$cookie_user) {
echo "";
exit;
}
include 'connect.inc.php';
$query = "SELECT * FROM my_user WHERE user='$cookie_user' AND password='$cookie_password'";
$res = mysql_query($query);
if (!$res || !mysql_num_rows($res)) {
echo "";
exit;
}
// 處理發文
if (isset($theme)) {
$content = htmlspecialchars($content);
$content = nl2br($content);
$theme = htmlspecialchars($theme);
$theme = nl2br($theme);
$query = "INSERT INTO guestbook (name, type, theme, content, icon, time_open, time_close, answer_count, answer_name)
VALUES ('$cookie_user', 1, '$theme', '$content', $icon, NOW(), NOW(), 1, '$cookie_user')";
$res = mysql_query($query);
if ($res) {
echo "";
} else {
echo $query; // 除錯輸出 SQL
}
}
?>
<script language="JavaScript">
var submitcount = 0;
function check_com() {
if (document.form.theme.value.length == 0) {
alert('主題不能為空!\nYou must supply a subject.');
return false;
}
if (document.form.content.value.length == 0) {
alert('加貼內容不能為空!\nYou must supply a message.');
return false;
}
return true;
}
</script>
<body bgcolor="#cccc99" bottommargin="0" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<table border="0" cellpadding="0" cellspacing="0" width="100%" class="body_br">
<tbody>
<script language="JavaScript" src="mypic/x.js"></script>
<tr><td valign="top">
<form action="post.php?forum_id=11" method="post" name="form" onsubmit="return check_com()">
<table align="center" border="0" cellpadding="4" cellspacing="0" width="100%">
<tbody>
<tr>
<td class="mid" width="20%">主 題</td>
<td><input maxlength="30" name="theme" size="50"> </td>
</tr>
<tr>
<td class="mid" valign="top">表情圖標</td>
<td>
<input checked name="icon" type="radio" value="1"> <img align="absmiddle" height="18" src="mypic/icon1.gif" width="18">
<input name="icon" type="radio" value="2"> <img align="absmiddle" height="18" src="mypic/icon2.gif" width="18">
...(略,共 14 個圖示)...
<input name="icon" type="radio" value="14"> <img align="absmiddle" height="18" src="mypic/icon14.gif" width="18">
</td>
</tr>
<tr>
<td class="mid" valign="top">加貼內容</td>
<td><textarea cols="50" name="content" rows="6"></textarea> </td>
</tr>
<tr>
<td></td>
<td>
<input name="submit" onclick="return checkSubmit()" type="submit" value=" 發 表 ">
<input name="reset" type="reset" value=" 清 除 ">
</td>
</tr>
</tbody></table></form>
</td></tr>
</tbody></table>
</body></html>
| 項目 | 現狀 | 風險 | 改進建議 |
|---|---|---|---|
| SQL 注入 | 直接拼接變數進 SQL | 極高 | 改用 PDO 預處理語句:$stmt->execute([$cookie_user, $theme, ...]) |
| XSS | htmlspecialchars() + nl2br() | 中 | 儲存原始文字,輸出時統一 htmlspecialchars();若需富文本採用 Purifier |
| 密碼明文比對 | SQL 中直接 password='$cookie_password' | 極高 | 資料庫儲存 password_hash() 雜湊,驗證用 password_verify() |
| CSRF | 無 Token 驗證 | 中 | 表單加入 <input type="hidden" name="csrf_token" value="= $_SESSION['csrf_token'] ?>"> |
| JS 依賴 | 內嵌 check_com()、checkSubmit() | 低 | 前後端分離,後端二次驗證不可省略 |
CREATE TABLE guestbook (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(12) NOT NULL,
type TINYINT NOT NULL, -- 0:回覆, 1:主貼
theme VARCHAR(50),
content BLOB NOT NULL,
icon TINYINT NOT NULL,
time_open DATETIME NOT NULL,
time_close DATETIME NOT NULL,
answer_count INT NOT NULL,
answer_name VARCHAR(12) NOT NULL,
main_id BIGINT -- 回覆指向的主貼 ID
);
main_id、time_close)。本檔案為「模仿 OSO 論壇」系列第三部分,配合 read.php(二)、faq.php(一) 可構成基本論壇雛形。