require("common.php3")(錯誤處理)、require("mail.php3")(發信函數)。$submit 變數(舊式 register_globals 風格)。$id 不可空、僅允許英數字(eregi("^[0-9a-zA_Z]+$"),eregi 已棄用)。$password 不可空、兩次輸入一致($password1)。$name、Email $mail 必填。dbmopen("class", "w") 開啟會員資料庫(寫入模式)。dbmexists() 檢查用戶名是否已存在。|!:!| 串接成單一字串 $data,dbminsert($dbm, $id, $data) 存入。dbmopen("password", "w") 以 dbminsert($pwd, $id, $password) 存明文密碼(極度不安全)。$sendmsg,呼叫 mail2() 寄送至註冊 Email。header("Location:index.php3")。reg.php3。$dbm = dbmopen("class", "c"); // "c" = create if not exists
dbmclose($dbm);
$dbm = dbmopen("password", "c");
dbmclose($dbm);
僅建立空的 class.db、password.db(或 .dir/.pag 視處理器而定),供後續註冊寫入使用。
| 問題 | 風險 | 修正方向 |
|---|---|---|
| 明文密碼存儲 | 資料庫洩露即帳號全失陷 | 改用 password_hash(),僅存雜湊 |
| ereg/eregi 已棄用 | PHP 7+ 直接報錯 | 改用 preg_match('/^[a-zA-Z0-9]+$/') |
| register_globals 依賴 | 變數汙染、安全性極差 | 改用 $_POST/$_GET 顯式取值 |
| DBM 無並發鎖 | 多用戶同時註冊可能損壞檔案 | 遷移至 SQLite/MySQL/PostgreSQL |
| Email 內含明文密碼 | 郵件傳輸過程可被竊聽 | 改發「設定密碼連結」,不寄密碼 |
| 分隔符 |!:!| 衝突 | 使用者輸入含該字串導致解析錯誤 | 改用 JSON/serialize 結構化存儲 |
$pdo = new PDO("sqlite:class.db");
$pdo->exec("CREATE TABLE IF NOT EXISTS members (
id TEXT PRIMARY KEY, name TEXT, nickname TEXT, email TEXT, home TEXT,
oicq TEXT, icq TEXT, address TEXT, tel TEXT, birth TEXT, job TEXT,
intro TEXT, sex TEXT, pwd_hash TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)");
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 驗證 $_POST 欄位...
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt = $pdo->prepare("INSERT INTO members (id,name,nickname,email,home,oicq,icq,address,tel,birth,job,intro,sex,pwd_hash) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
$stmt->execute([$_POST['id'], $_POST['name'], $_POST['nickname'], $_POST['mail'], $_POST['home'], $_POST['oicq'], $_POST['icq'], $_POST['add'], $_POST['tel'], $_POST['birth'], $_POST['job'], $_POST['intro'], $_POST['sex'], $hash]);
// 發送設定密碼郵件(含一次性 token)...
header("Location: index.php");
exit;
}
// 輸出 HTML 表單...