PHP 怎么PHP 增量静态生成

wen PHP项目 2

本文目录导读:

PHP 怎么PHP 增量静态生成

  1. 基本原理
  2. 实现方案
  3. 完整的增量静态生成系统
  4. 使用建议
  5. 注意事项

我来详细介绍 PHP 增量静态生成的几种实现方法:

基本原理

增量静态生成的核心思想:只重新生成发生变化的页面,而不是全站重新生成。

实现方案

基于文件时间戳

<?php
class IncrementalStaticGenerator {
    private $cacheDir = 'cache/';
    private $sourceDir = 'source/';
    // 检查是否需要重新生成
    public function needRegenerate($pageName) {
        $sourceFile = $this->sourceDir . $pageName . '.php';
        $cacheFile = $this->cacheDir . $pageName . '.html';
        // 如果没有缓存文件,需要生成
        if (!file_exists($cacheFile)) {
            return true;
        }
        // 如果源文件更新,需要重新生成
        if (filemtime($sourceFile) > filemtime($cacheFile)) {
            return true;
        }
        return false;
    }
    // 生成静态页面
    public function generate($pageName) {
        if (!$this->needRegenerate($pageName)) {
            return false;
        }
        ob_start();
        include $this->sourceDir . $pageName . '.php';
        $content = ob_get_clean();
        file_put_contents(
            $this->cacheDir . $pageName . '.html', 
            $content
        );
        return true;
    }
}

更新

<?php
class ContentBasedGenerator {
    private $db;
    private $cacheDir = 'cache/';
    private $contentTable = 'content_update_log';
    // 记录内容变更
    public function markContentChanged($contentId) {
        $sql = "INSERT INTO {$this->contentTable} 
                (content_id, change_time) 
                VALUES (?, NOW())
                ON DUPLICATE KEY UPDATE change_time = NOW()";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$contentId]);
    }
    // 获取需要更新的页面
    public function getChangedPages() {
        $sql = "SELECT DISTINCT p.page_id, p.page_name 
                FROM pages p 
                JOIN page_content pc ON p.page_id = pc.page_id
                JOIN content_update_log l ON pc.content_id = l.content_id
                WHERE l.change_time > p.last_generated_time";
        return $this->db->query($sql)->fetchAll();
    }
    // 生成更新的页面
    public function generateChangedPages() {
        $pages = $this->getChangedPages();
        foreach ($pages as $page) {
            $this->generateSinglePage($page['page_id']);
            $this->updateGeneratedTime($page['page_id']);
        }
    }
}

基于文件的增量生成

<?php
class FileBasedIncrementalGenerator {
    private $templateDir = 'templates/';
    private $outputDir = 'public/';
    private $hashFile = 'cache/page_hashes.json';
    // 检查文件内容是否变化
    public function hasFileChanged($file) {
        $hashes = $this->loadHashes();
        $currentHash = md5_file($file);
        if (!isset($hashes[$file]) || $hashes[$file] !== $currentHash) {
            $hashes[$file] = $currentHash;
            $this->saveHashes($hashes);
            return true;
        }
        return false;
    }
    // 增量生成
    public function incrementalGenerate() {
        $files = glob($this->templateDir . '*.php');
        foreach ($files as $file) {
            if ($this->hasFileChanged($file)) {
                $outputFile = $this->outputDir . 
                             basename($file, '.php') . '.html';
                ob_start();
                include $file;
                $content = ob_get_clean();
                file_put_contents($outputFile, $content);
                echo "Regenerated: " . basename($outputFile) . PHP_EOL;
            }
        }
    }
    private function loadHashes() {
        if (file_exists($this->hashFile)) {
            return json_decode(file_get_contents($this->hashFile), true);
        }
        return [];
    }
    private function saveHashes($hashes) {
        file_put_contents($this->hashFile, json_encode($hashes));
    }
}

数据库驱动的增量生成

<?php
class DBDrivenIncrementalGenerator {
    private $pdo;
    private $outputDir = 'public/';
    // 获取需要更新的内容ID
    public function getContentUpdates() {
        $sql = "SELECT c.*, t.template_file 
                FROM contents c
                JOIN content_templates t ON c.template_id = t.template_id
                WHERE c.is_published = 1 
                AND (c.updated_at > c.last_generated_at 
                     OR c.last_generated_at IS NULL)";
        return $this->pdo->query($sql)->fetchAll();
    }
    // 生成特定内容
    public function generateContent($content) {
        $template = file_get_contents($content['template_file']);
        // 替换内容变量
        $html = $this->replaceVariables($template, $content);
        // 生成文件名
        $filename = $this->generateFilename($content);
        $filepath = $this->outputDir . '/' . $filename;
        // 保存文件
        file_put_contents($filepath, $html);
        // 更新生成时间
        $this->updateGeneratedTime($content['id']);
        return $filename;
    }
    // 批量增量更新
    public function batchIncrementalUpdate() {
        $contents = $this->getContentUpdates();
        $generated = [];
        foreach ($contents as $content) {
            $filename = $this->generateContent($content);
            $generated[] = $filename;
            // 更新相关页面(如列表页、首页等)
            $this->updateRelatedPages($content);
        }
        return $generated;
    }
    private function updateRelatedPages($content) {
        // 更新包含此内容的列表页、首页等
        if ($content['is_featured']) {
            $this->generateHomepage();
        }
        $this->generateCategoryList($content['category_id']);
    }
}

完整的增量静态生成系统

<?php
class FullStaticGenerationSystem {
    private $config;
    private $db;
    private $logger;
    private $cache;
    public function __construct() {
        $this->config = require 'config.php';
        $this->db = new PDO(/* 数据库连接 */);
        $this->logger = new Logger();
        $this->cache = new Cache();
    }
    // 主生成方法
    public function generate($pageType, $pageId = null) {
        switch ($pageType) {
            case 'single':
                return $this->generateSingle($pageId);
            case 'list':
                return $this->generateList($pageId);
            case 'home':
                return $this->generateHome();
            case 'all':
                return $this->generateAll();
        }
    }
    // 生成单页
    private function generateSingle($id) {
        // 检查是否需要更新
        if (!$this->needsUpdate($id, 'single')) {
            return ['status' => 'skipped', 'id' => $id];
        }
        // 获取数据
        $data = $this->getPageData($id);
        // 渲染模板
        $html = $this->renderTemplate('single', $data);
        // 保存文件
        $filename = $this->saveToFile($data['slug'], $html);
        // 更新标记
        $this->markGenerated($id, 'single');
        return ['status' => 'generated', 'file' => $filename];
    }
    // 检查是否需要更新
    private function needsUpdate($id, $type) {
        // 检查内容是否更新
        $lastModified = $this->getLastModified($id, $type);
        $lastGenerated = $this->getLastGenerated($id, $type);
        return $lastModified > $lastGenerated;
    }
    // 智能批量生成
    public function smartBatchGenerate() {
        // 获取所有需要更新的内容
        $updates = $this->getQueue();
        $results = [];
        foreach ($updates as $update) {
            // 更新单个页面
            $result = $this->generate($update['type'], $update['id']);
            $results[] = $result;
            // 更新相关列表页
            if ($update['type'] === 'single') {
                $this->updateListsContaining($update['id']);
            }
        }
        // 更新站点地图
        $this->updateSitemap();
        return $results;
    }
    // 热更新:在线替换文件
    public function hotUpdate($file) {
        $tempFile = $file . '.tmp';
        $backupFile = $file . '.bak';
        // 生成新版本到临时文件
        $this->generateToFile($file, $tempFile);
        // 备份原文件
        copy($file, $backupFile);
        // 原子替换
        rename($tempFile, $file);
        // 清理备份
        unlink($backupFile);
    }
}

使用建议

触发更新时机:发布/更新时**:立即触发相关页面更新

  1. 定时任务:设置cron job定期检查更新
  2. Webhook:通过API回调触发更新

Cron Job 示例:

# 每小时执行增量更新
0 * * * * /usr/bin/php /path/to/generator.php --incremental
# 每天凌晨全量更新
0 3 * * * /usr/bin/php /path/to/generator.php --full

监控和日志:

// 添加日志记录
class GenerationLogger {
    public function logGeneration($file, $status) {
        $log = sprintf(
            "[%s] %s - %s\n",
            date('Y-m-d H:i:s'),
            $file,
            $status
        );
        file_put_contents('generation.log', $log, FILE_APPEND);
    }
}

注意事项

  1. 文件锁定:并发访问时使用 flock() 防止冲突
  2. 权限管理:确保缓存目录可写
  3. 备份机制:更新失败时能回滚
  4. 监控告警:生成失败时及时通知
  5. 性能优化:使用内存缓存减少数据库查询

这种增量静态生成方案可以有效减少服务器负载,提高页面响应速度,特别适合内容更新频繁的网站。

抱歉,评论功能暂时关闭!