功能需求
- 單選投票,5 個選項
- 以文字檔
voterec.txt 儲存各選項票數
- 提交後當頁重新整理,顯示各選項票數、百分比、總票數
完整程式碼 vote.php
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>意見投票箱</title></head>
<body bgcolor="#FFFFCC">
<h2>請您投票</h2>
<?php
$vote_file = 'voterec.txt';
$options = [
1 => '非常滿意',
2 => '滿意',
3 => '普通',
4 => '不滿意',
5 => '非常不滿意'
];
// 處理提交
if (isset($_POST['vote'])) {
$choice = (int)$_POST['vote'];
if ($choice >= 1 && $choice <= 5) {
// 讀取現有資料
$votes = file_exists($vote_file) ? array_map('intval', file($vote_file, FILE_IGNORE_NEW_LINES)) : array_fill(1, 5, 0);
// 陣列索引從 1 起,轉 0-based
$votes[$choice - 1]++;
// 寫回 (檔案鎖定防併發)
$fp = fopen($vote_file, 'c+');
if (flock($fp, LOCK_EX)) {
ftruncate($fp, 0);
rewind($fp);
foreach ($votes as $v) fwrite($fp, $v . "\n");
flock($fp, LOCK_UN);
}
fclose($fp);
}
}
// 讀取顯示
$votes = file_exists($vote_file) ? array_map('intval', file($vote_file, FILE_IGNORE_NEW_LINES)) : array_fill(1, 5, 0);
$total = array_sum($votes);
?>
<form method="post">
<table border="1" cellpadding="4" cellspacing="0">
<tr><th>選項</th><th>內容</th><th>票數</th><th>百分比</th><th>投票</th></tr>
<?php foreach ($options as $k => $txt):
$cnt = isset($votes[$k-1]) ? $votes[$k-1] : 0;
$pct = $total ? round($cnt / $total * 100, 1) : 0;
?>
<tr>
<td><?= $k ?></td>
<td><?= htmlspecialchars($txt) ?></td>
<td align="right"><?= $cnt ?></td>
<td align="right"><?= $pct ?>%</td>
<td><input type="radio" name="vote" value="<?= $k ?>"></td>
</tr>
<?php endforeach; ?>
<tr><td colspan="2" align="right">總計</td><td align="right"><?= $total ?></td><td align="right">100%</td><td></td></tr>
</table>
<p><input type="submit" value="送出投票"></p>
</form>
</body></html>
關鍵改進點 (相較原始版)
- 檔案鎖定:
flock(LOCK_EX) 防止併發寫入資料遺失
- 輸入驗證:
(int)$_POST['vote'] 確保整數、範圍檢查
- XSS 防護:
htmlspecialchars() 輸出選項文字
- 結構化資料:陣列索引對應選項,擴充性佳
- 現代 HTML:DOCTYPE、charset、表格語意化
進階擴充方向
- 改用 SQLite/PDO:支援並發、查詢彈性、避免檔案鎖定效能瓶頸
- 加入 Cookie/IP 限制:防止重複投票
- 後台管理介面:新增/修改/刪除選項、重置票數、匯出 CSV
- AJAX 無刷新提交:提升使用者體驗