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

PHP 簡單文件緩存類實現(支持過期時間、MD5 文件名、目錄自動創建)

     編輯:PHP 相關知識

在無 Redis/Memcached 環境下,基於文件系統的緩存是輕量級 PHP 應用的常見選擇。本文提供一個功能完整的 Cache 類,支持鍵值存取、過期時間、MD5 混淆文件名、目錄自動創建與遞歸清理。

類功能特性

  • set_dir(): 設置緩存目錄,自動遞歸創建(權限 0777)。
  • write(): 寫入緩存,序列化存儲 ['data' => value, 'time' => timestamp],使用 flock(LOCK_EX) 防併發寫入衝突。
  • read(): 讀取緩存,檢查過期時間(分鐘),過期返回 false。
  • clear_all(): 遞歸刪除緩存目錄下所有文件。
  • 文件名生成: {key}_{md5(key . secret)},防止鍵名衝突與遍歷猜測。

完整類代碼

<?php
class Cache {
    private $dir = 'data/cache/';      // 默認緩存目錄
    private $key = 'c_a_sss';          // 文件名 MD5 加密密鑰

    /**
     * 設置緩存目錄並自動創建
     * @param string $dirpath
     */
    public function set_dir($dirpath) {
        $this->dir = rtrim($dirpath, '/') . '/';
        $this->make_dir($this->dir);
    }

    /**
     * 讀取緩存
     * @param string $key
     * @param int $minutes 過期分鐘數
     * @return mixed|false
     */
    public function read($key, $minutes = 1) {
        $filename = $this->get_filename($key);
        if ($datas = @file_get_contents($filename)) {
            $datas = unserialize($datas);
            if (is_array($datas) && isset($datas['time'], $datas['data'])) {
                if (time() - $datas['time'] < $minutes * 60) {
                    return $datas['data'];
                }
            }
        }
        return false;
    }

    /**
     * 寫入緩存
     * @param string $key
     * @param mixed $data
     * @return bool
     */
    public function write($key, $data) {
        $filename = $this->get_filename($key);
        $datas = array('data' => $data, 'time' => time());
        $serialized = serialize($datas);

        if ($handle = fopen($filename, 'w+')) {
            flock($handle, LOCK_EX);
            $rs = fwrite($handle, $serialized);
            flock($handle, LOCK_UN);
            fclose($handle);
            return $rs !== false;
        }
        return false;
    }

    /**
     * 清空所有緩存
     */
    public function clear_all() {
        $this->del_file($this->dir);
    }

    // 生成帶密鑰的 MD5 文件名
    private function get_filename($key) {
        return $this->dir . $key . '_' . md5($key . $this->key);
    }

    // 遞歸創建目錄
    private function make_dir($path) {
        if (!file_exists($path)) {
            $this->make_dir(dirname($path));
            if (!mkdir($path, 0777)) {
                die('無法創建緩存目錄: ' . $path);
            }
        }
    }

    // 遞歸刪除目錄下所有文件(保留目錄結構)
    private function del_file($dir) {
        if (is_dir($dir)) {
            $dh = opendir($dir);
            while (($file = readdir($dh)) !== false) {
                if ($file !== '.' && $file !== '..') {
                    $fullpath = $dir . '/' . $file;
                    if (is_dir($fullpath)) {
                        $this->del_file($fullpath);
                    } else {
                        unlink($fullpath);
                    }
                }
            }
            closedir($dh);
        }
    }
}
?>

使用示例

<?php
require 'Cache.class.php';

$cache = new Cache();
$cache->set_dir(__DIR__ . '/data/cache_dir/'); // 設置絕對路徑

// 嘗試讀取緩存(1 分鐘過期)
$data = $cache->read('sys', 1);

if ($data === false) {
    // 緩存未命中或過期,生成數據
    $data = array(
        'aa' => 1111,
        'bb' => 2222,
        'date' => date('Y-m-d H:i:s')
    );
    // 寫入緩存
    $cache->write('sys', $data);
    echo "數據來自數據庫/計算,已寫入緩存\n";
} else {
    echo "數據來自緩存\n";
}

print_r($data);
?>

關鍵設計解析

設計點實現方式優勢
併發安全flock(LOCK_EX) 獨佔鎖防止多進程同時寫入導致文件損壞
文件名安全md5(key . secret)避免鍵名包含特殊字符、防止遍歷猜測真實鍵
過期機制存儲時間戳,讀取時比較無需額外掃描進程,讀取時惰性過期
目錄管理遞歸 mkdir / 遞歸 unlink自適應多級目錄,清理徹底
序列化存儲serialize()支持任意 PHP 變量類型(數組、對象、標量)

優化建議(生產環境)

  1. 分目錄存儲: 緩存文件過多(>1萬)會導致目錄讀取變慢,建議按 md5(key)[0..1] 分 256 個子目錄。
  2. 緩存擊穿防護: 熱點鍵過期瞬間大量請求穿透 DB,可用「互斥鎖重建」或「邏輯過期+異步更新」。
  3. 性能優化: 高頻讀寫場景改用 var_export + include 或 igbinary 序列化,或直接升級 Redis。
  4. GC 機制: 定期(如 cron 每小時)清理過期文件,避免磁盤佔滿。
  5. 權限控制: 緩存目錄權限設為 0755,文件 0644,避免 0777 風險。

進階:支持標籤/分組的緩存清理

<?php
// 擴展思路:在緩存文件中存儲元數據
$meta = array(
    'data' => $data,
    'time' => time(),
    'tags' => array('user', 'profile') // 標籤
);
// 清理時掃描文件解析 tags,匹配則刪除
?>

該類代碼精簡、依賴極少(僅需文件系統),適合中小型項目、微服務、無緩存中間件環境。掌握其原理有助於理解緩存系統的核心機制:序列化、原子寫入、過期判定、命名隔離。

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