高效率网页缓存页面代码

之前研究了,高性能 PHP 缓存系统设计:智能清理与计数管理

但我发现,这只能缓存单独的html,不能缓存一些想要缓存的数据。

同时,为了解决inode的限制。

所以我尝试着将缓存文件,放到db数据库里,从而实现高效存储。

缓存代码:

<?php
/**
 * 统一缓存类(SQLite 分布式)
 * 支持 API 缓存(get/set)和页面缓存(allget)
 */
class ApiCache
{
    private $root;
    private $dbPool = [];
    private $obStarted = false;
    private $currentUrl = null;

    public function __construct($rootDir)
    {
        $this->root = rtrim($rootDir, '/') . '/';
        if (!is_dir($this->root)) {
            mkdir($this->root, 0755, true);
        }
    }

    public function get($url)
    {
        $md5 = md5($url);
        $db = $this->getDb($md5);
        if (!$db) return false;

        $stmt = $db->prepare("SELECT content, access_count, permanent, first_time FROM cache WHERE md5 = ?");
        $stmt->execute([$md5]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$row) {
            return false;
        }

        $update = $db->prepare("UPDATE cache SET access_count = access_count + 1, last_time = ? WHERE md5 = ?");
        $update->execute([time(), $md5]);

        return gzuncompress($row['content']);
    }

    public function set($url, $data, $permanent = 0)
    {
        $md5 = md5($url);
        $db = $this->getDb($md5);
        if (!$db) return false;

        $compressed = gzcompress($data);
        $now = time();
        $stmt = $db->prepare("INSERT OR REPLACE INTO cache (md5, content, access_count, first_time, last_time, permanent)
                              VALUES (?, ?, 0, ?, ?, ?)");
        return $stmt->execute([$md5, $compressed, $now, $now, $permanent]);
    }

    public function allget()
    {
        if ($this->obStarted) return;

        $url = $this->getCurrentUrl();
        $this->currentUrl = $url;

        $content = $this->get($url);
        if ($content !== false) {
            echo $content;
            exit;
        }

        ob_start([$this, 'autoStore']);
        $this->obStarted = true;
    }

    public function autoStore($content)
    {
        if ($this->currentUrl !== null) {
            $this->set($this->currentUrl, $content, 0);
        }
        $this->obStarted = false;
        return $content;
    }

    private function getCurrentUrl()
    {
        $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
        return $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    }

    private function getDb($md5)
    {
        $dir1 = substr($md5, 0, 2);
        $dir2 = substr($md5, -2);
        $dirPath = $this->root . $dir1 . '/' . $dir2;
        $dbFile = $dirPath . '/data.db';

        $key = $dir1 . '/' . $dir2;
        if (isset($this->dbPool[$key])) {
            return $this->dbPool[$key];
        }

        if (!is_dir($dirPath)) {
            if (!mkdir($dirPath, 0755, true)) {
                return false;
            }
        }

        try {
            $pdo = new PDO("sqlite:" . $dbFile);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $pdo->exec("CREATE TABLE IF NOT EXISTS cache (
                md5 TEXT PRIMARY KEY,
                content BLOB,
                access_count INTEGER DEFAULT 0,
                first_time INTEGER,
                last_time INTEGER,
                permanent INTEGER DEFAULT 0
            )");
            $pdo->exec("CREATE INDEX IF NOT EXISTS idx_first_time ON cache(first_time)");
            $pdo->exec("CREATE INDEX IF NOT EXISTS idx_access_count ON cache(access_count)");
            $pdo->exec("CREATE INDEX IF NOT EXISTS idx_permanent ON cache(permanent)"); // 新增索引
            $pdo->exec("PRAGMA synchronous = OFF");
            $pdo->exec("PRAGMA journal_mode = MEMORY");

            $this->dbPool[$key] = $pdo;
            return $pdo;
        } catch (PDOException $e) {
            error_log("SQLite open failed: " . $e->getMessage());
            return false;
        }
    }

    public function close()
    {
        $this->dbPool = [];
    }
}

清理代码:

 

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容