首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP + MySQL 實作文章瀏覽次數統計與發布時間顯示

     編輯:PHP 相關知識

前言

文章「發布時間」與「瀏覽次數」是內容型網站的基本指標。本文示範使用 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();
}
?>

關鍵點解析

  1. Session 防重複:鍵名加前綴 viewed_ 避免衝突;關閉瀏覽器後 Session 失效,下次再訪會再計數(符合多數需求)。若需「同一使用者永遠只算一次」,改用 Cookie 或登入用戶 ID 判斷。
  2. UPSERT 原子操作:INSERT ... ON DUPLICATE KEY UPDATE 避免「先查後寫」的競態條件,單一 SQL 完成「不存在則建立、存在則累加」。
  3. 參數化查詢:使用 prepare/bind_param 防 SQL 注入。
  4. 錯誤不中斷:統計失敗僅記錄 log,不 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>

進階優化建議

1. 使用 Redis/Memcached 做熱點計數

高流量文章頻繁寫入 MySQL 會造成鎖爭用。改為:

  • 瀏覽時 INCR redis:views:article_1001。
  • 定時任務(每 5 分鐘)將快取值同步回 MySQL。
  • 顯示時讀取快取 + MySQL 基準值,即時性與效能兼顧。

2. 區分「人次」與「頁面瀏覽量 (PV)」

  • PV:每次請求 +1(移除 Session 判斷)。
  • UV(Unique Visitor):以 Cookie/使用者 ID 去重。
  • 可同時維護兩個欄位 pv、uv。

3. 非同步寫入(Message Queue)

將計數請求推入 Queue(如 RabbitMQ、Kafka、Redis List),Worker 批次寫入 DB,大幅降低 DB 負載。

4. 靜態頁面快取與統計分離

若文章頁面為靜態 HTML,可用 JavaScript 發送 Beacon/AJAX 到統計 API,完全不經 PHP 模板渲染路徑。

常見問題 FAQ

Q: 為什麼用 int(11) 存 Unix timestamp 而不用 DATETIME?
A: 整數比較、排序、跨時區轉換效能更好;PHP date() 直接支援。
Q: Session 防重複在分散式部署(多台 PHP-FPM)會失效?
A: 需共享 Session 儲存(Redis/Memcached/Database),或改用 Cookie/用戶 ID 判斷。
Q: 如何重置某篇文章計數?
A: 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),控制器只需兩行呼叫,維護性大幅提升。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved