文章「發布時間」與「瀏覽次數」是內容型網站的基本指標。本文示範使用 PHP Session 防止重複計數、MySQL 儲存統計資料的完整實作,包含資料表設計、核心邏輯、顯示模板與優化建議。
CREATE TABLE `statistics` (
`StsID` int(11) NOT NULL AUTO_INCREMENT,
`StsFile` varchar(100) NOT NULL COMMENT '文章唯一識別(如檔名或 ID)',
`StsTime` int(11) NOT NULL COMMENT '發布時間 Unix timestamp',
`StsNumb` int(11) NOT NULL DEFAULT 0 COMMENT '瀏覽次數',
PRIMARY KEY (`StsID`),
UNIQUE KEY `uk_file` (`StsFile`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
放在 HTML 輸出之前(如 header.php 或控制器最前端):
<?php
session_start();
// 文章唯一鍵:可用 ID、slug 或檔名
$articleKey = 'article_1001'; // 實際應從路由/參數取得
$now = time();
// 設定時區(依專案需求)
date_default_timezone_set('Asia/Taipei');
// 連線資料庫(建議用 PDO,此處為示範用 mysqli)
$mysqli = new mysqli('localhost', 'db_user', 'db_pass', 'db_name');
if ($mysqli->connect_errno) {
error_log('DB 連線失敗:' . $mysqli->connect_error);
// 這裡不 die,避免統計失敗影響主頁面
} else {
$mysqli->set_charset('utf8mb4');
// 判斷同一 Session 是否已計數過
$sessionKey = 'viewed_' . $articleKey;
if (!isset($_SESSION[$sessionKey])) {
// 原子性 UPSERT:不存在則插入(次數 0),存在則次數 +1
$sql = <<prepare($sql);
$stmt->bind_param('si', $articleKey, $now);
$stmt->execute();
$stmt->close();
// 標記此 Session 已計數
$_SESSION[$sessionKey] = true;
}
$mysqli->close();
}
?>
viewed_ 避免衝突;關閉瀏覽器後 Session 失效,下次再訪會再計數(符合多數需求)。若需「同一使用者永遠只算一次」,改用 Cookie 或登入用戶 ID 判斷。INSERT ... ON DUPLICATE KEY UPDATE 避免「先查後寫」的競態條件,單一 SQL 完成「不存在則建立、存在則累加」。prepare/bind_param 防 SQL 注入。die(),保證主內容正常顯示。在文章頁面適當位置輸出:
<?php
// 讀取統計資料(可與上方合併查詢,這裡分開示範)
$mysqli = new mysqli('localhost', 'db_user', 'db_pass', 'db_name');
$mysqli->set_charset('utf8mb4');
$sql = 'SELECT `StsTime`, `StsNumb` FROM `statistics` WHERE `StsFile` = ?';
$stmt = $mysqli->prepare($sql);
$stmt->bind_param('s', $articleKey);
$stmt->execute();
$stmt->bind_result($stsTime, $stsNumb);
$stmt->fetch();
$stmt->close();
$mysqli->close();
?>
<div class="article-meta">
<span class="publish-time">
發布時間:<?= date('Y-m-d H:i:s', $stsTime) ?>
</span>
<span class="view-count">
瀏覽次數:<?= number_format($stsNumb) ?>
</span>
</div>
高流量文章頻繁寫入 MySQL 會造成鎖爭用。改為:
INCR redis:views:article_1001。pv、uv。將計數請求推入 Queue(如 RabbitMQ、Kafka、Redis List),Worker 批次寫入 DB,大幅降低 DB 負載。
若文章頁面為靜態 HTML,可用 JavaScript 發送 Beacon/AJAX 到統計 API,完全不經 PHP 模板渲染路徑。
int(11) 存 Unix timestamp 而不用 DATETIME?date() 直接支援。UPDATE statistics SET StsNumb = 0 WHERE StsFile = '...';同步清除快取。
project/
├── config/
│ └── db.php # 資料庫設定
├── lib/
│ └── Stats.php # 統計類別(封裝上述邏輯)
├── article.php # 文章頁面控制器
└── templates/
└── article.tpl.php # 顯示模板
將核心邏輯封裝為 Stats::hit($articleKey)、Stats::get($articleKey),控制器只需兩行呼叫,維護性大幅提升。