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

PHP + Memcache 實作 WordPress 訪問總數統計(非外掛、高效能)

     編輯:PHP 綜合知識

設計目標

  • 高效能:讀寫計數器操作在亞毫秒級完成,不阻塞頁面渲染。
  • 資料持久化:定期同步至 MySQL,重啟 Memcache 不丟失資料。
  • 非侵入式:不安裝任何 WordPress 外掛,僅修改主題 functions.php 或建立 Must-Use Plugin。
  • 抗併發:Memcache 原子 increment 避免競爭條件。

核心實作程式碼

<?php
/**
 * WordPress 訪問計數器 - Memcache 版
 * 放置於 wp-content/mu-plugins/visit-counter.php 或主題 functions.php
 */

// 初始化 Memcache 連線 (單例模式)
function wc_get_memcache(): Memcache {
    static $mc = null;
    if ($mc === null) {
        $mc = new Memcache();
        $host = '127.0.0.1';
        $port = 11211;
        // 生產環境建議加入連線池/持久連線
        if (!$mc->connect($host, $port)) {
            // 降級:無法連線 Memcache 時直接查資料庫
            error_log('[VisitCounter] Memcache 連線失敗,降級至資料庫模式');
            return false;
        }
    }
    return $mc;
}

// 取得並遞增總訪問數
function wc_get_total_visits(): int {
    $mc = wc_get_memcache();
    $key = 'wc_total_visits';
    
    if ($mc) {
        // 原子遞增:若 key 不存在則從資料庫初始化
        $visits = $mc->increment($key);
        if ($visits === false) {
            // Key 不存在,從資料庫讀取初始值
            global $wpdb;
            $row = $wpdb->get_row("SELECT option_value FROM {$wpdb->options} WHERE option_name = '$key'", ARRAY_A);
            $initValue = $row ? (int)$row['option_value'] : 0;
            $mc->set($key, $initValue + 1, 0, 86400); // 設定初始值+1,24小時過期(僅作備援)
            $visits = $initValue + 1;
        }
    } else {
        // 降級模式:直接資料庫原子更新
        global $wpdb;
        $wpdb->query("UPDATE {$wpdb->options} SET option_value = option_value + 1 WHERE option_name = '$key'");
        $row = $wpdb->get_row("SELECT option_value FROM {$wpdb->options} WHERE option_name = '$key'", ARRAY_A);
        $visits = $row ? (int)$row['option_value'] : 0;
    }
    
    return $visits;
}

// 定期同步至資料庫 (掛載於 shutdown 或 cron)
function wc_sync_visits_to_db(): void {
    $mc = wc_get_memcache();
    if (!$mc) return;
    
    $key = 'wc_total_visits';
    $visits = $mc->get($key);
    if ($visits === false) return; // 無資料
    
    // 僅每 100 次同步一次,減少資料庫寫入
    if ($visits % 100 !== 0) return;
    
    global $wpdb;
    $wpdb->update(
        $wpdb->options,
        ['option_value' => $visits],
        ['option_name' => $key],
        ['%d'],
        ['%s']
    );
}

// 前台顯示短代碼 [total_visits]
add_shortcode('total_visits', function() {
    $visits = wc_get_total_visits();
    return number_format($visits);
});

// 每次頁面載入遞增計數 (排除後台、登入用戶、爬蟲)
add_action('wp_head', function() {
    if (is_admin() || is_user_logged_in()) return;
    // 簡易爬蟲過濾
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    if (preg_match('/bot|crawler|spider|slurp/i', $ua)) return;
    
    wc_get_total_visits(); // 觸發遞增
}, 1); // 優先級 1,極早執行

// 關站/定時同步
register_shutdown_function('wc_sync_visits_to_db');
// 或使用 WP Cron 每小時同步
if (!wp_next_scheduled('wc_hourly_sync')) {
    wp_schedule_event(time(), 'hourly', 'wc_hourly_sync');
}
add_action('wc_hourly_sync', 'wc_sync_visits_to_db');

進階優化:分頁/文章獨立計數

// 文章閱讀數
function wc_get_post_views(int $postId): int {
    $mc = wc_get_memcache();
    $key = "wc_post_views_{$postId}";
    
    if ($mc) {
        $views = $mc->increment($key);
        if ($views === false) {
            $views = (int)get_post_meta($postId, 'views', true);
            $mc->set($key, $views + 1, 0, 86400);
            $views++;
        }
    } else {
        $views = (int)get_post_meta($postId, 'views', true) + 1;
        update_post_meta($postId, 'views', $views);
    }
    return $views;
}

// 同步文章閱讀數 (每 50 次)
function wc_sync_post_views(int $postId): void {
    $mc = wc_get_memcache();
    if (!$mc) return;
    $key = "wc_post_views_{$postId}";
    $views = $mc->get($key);
    if ($views !== false && $views % 50 === 0) {
        update_post_meta($postId, 'views', $views);
    }
}

// 掛載於 single.php 或 the_content 過濾器
add_filter('the_content', function($content) {
    if (is_singular('post') && !is_admin()) {
        $postId = get_the_ID();
        $views = wc_get_post_views($postId);
        // 可選:在文章開頭顯示閱讀數
        // $content = "

閱讀數: {$views}

" . $content; wc_sync_post_views($postId); } return $content; });

部署檢查清單

項目建議設定
Memcache 記憶體分配 64MB-256MB 視流量;啟用 LRU 淘汰
連線方式持久連線 pconnect 或連線池 (php-memcached)
金鑰命名統一前綴 wc_,避免衝突
同步頻率總計數 100 次/次,文章計數 50 次/次,可依流量調整
降級策略Memcache 不可用時自動切換資料庫模式,記錄錯誤日誌
監控告警監控 Memcache 命中率、連線數、記憶體使用率

為何選擇 Memcache 而非 Redis?

  • 簡單性:純 Key-Value、無持久化複雜度、記憶體效率極高。
  • 原子遞增:increment() 原生支援,無需 Lua 腳本。
  • WordPress 相容:眾多虛擬主機預裝 Memcache,部署門檻低。
  • 足夠用:計數器屬於「可丟失、可重算」資料,Memcache 特性完美匹配。
注意:若專案已使用 Redis 快取,建議統一使用 Redis INCR,減少元件依賴。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved