雙表設計防刷新
hit_count:單行單列存總計數
page_visit_record:記錄 IP+日期+頁面,同一天同 IP 同頁面只計一次
CREATE TABLE hit_count (hit_count INT NOT NULL DEFAULT 0);
CREATE TABLE page_visit_record (
visit_time DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
remote_addr CHAR(15) NOT NULL,
visit_page CHAR(60) NOT NULL,
KEY idx_visit (visit_time, visit_page),
PRIMARY KEY (visit_time)
);
核心 PHP 邏輯
<?php
include("config.inc.php");
$db = mysql_connect($host, $user, $pass);
mysql_select_db($dbname, $db);
// 1. 檢查今日是否已計數
$ip = $_SERVER['REMOTE_ADDR'];
$today = date('Y-m-d');
$sql = "SELECT COUNT(*) AS cnt FROM page_visit_record
WHERE remote_addr='$ip' AND DATE(visit_time)='$today'";
$res = mysql_query($sql, $db);
$row = mysql_fetch_assoc($res);
$has_count = $row['cnt'];
// 2. 更新總計數 (表鎖防併發)
mysql_query("LOCK TABLES hit_count WRITE", $db);
$res = mysql_query("SELECT hit_count FROM hit_count", $db);
if (mysql_num_rows($res) > 0) {
$cur = mysql_result($res, 0, 'hit_count');
if ($has_count == 0) {
$cur++;
mysql_query("UPDATE hit_count SET hit_count=$cur", $db);
}
} else {
$cur = 1;
mysql_query("INSERT INTO hit_count VALUES (1)", $db);
}
mysql_query("UNLOCK TABLES", $db);
// 3. 記錄訪問日誌
$visit_time = date('Y-m-d H:i:s');
$page = $_SERVER['REQUEST_URI'];
mysql_query("INSERT INTO page_visit_record VALUES ('$visit_time', '$ip', '$page')", $db);
// 4. 輸出 GIF 圖片
header("Content-type: image/gif");
$im = imagecreate(56, 16);
$black = imagecolorallocate($im, 0, 0, 0);
$white = imagecolorallocate($im, 255, 255, 255);
$num_str = sprintf("%08d", $cur); // 8 位補零
imagestring($im, 5, 2, 0, $num_str, $white);
imagegif($im);
imagedestroy($im);
mysql_close($db);
?>
關鍵點解析
- 表鎖:
LOCK TABLES ... WRITE 保證計數器原子性,避免併發丟更新
- 防刷新:複合唯一鍵 (IP + 日期 + 頁面) 可替代表鎖,更高效
- GD 繪圖:
imagecreate 創建畫布,imagestring 寫文本,imagegif 輸出
- 補零格式化:
sprintf("%08d", $num) 保證圖片寬度固定
現代化改造建議
- 使用
mysqli/PDO + 準備語句防注入
- 計數器改用 Redis
INCR + Lua 腳本原子操作,性能提升 100 倍
- 防刷新用 Redis Set 存
ip:date:page 並設置 24h 過期
- 圖片輸出改用
imagepng + 透明背景,或直接前端 JS 顯示數字