本文目录导读:

我来详细介绍 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);
}
}
使用建议
触发更新时机:发布/更新时**:立即触发相关页面更新
- 定时任务:设置cron job定期检查更新
- 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);
}
}
注意事项
- 文件锁定:并发访问时使用
flock()防止冲突 - 权限管理:确保缓存目录可写
- 备份机制:更新失败时能回滚
- 监控告警:生成失败时及时通知
- 性能优化:使用内存缓存减少数据库查询
这种增量静态生成方案可以有效减少服务器负载,提高页面响应速度,特别适合内容更新频繁的网站。