{$article.title}
{$article.content}
文章詳情頁、列表頁等高頻讀、低頻寫頁面,生成純靜態 HTML 可:
1. 後台發布/定時任務觸發
2. 遍歷數據 (文章 ID 列表)
3. $smarty->assign('article', $articleData)
4. $html = $smarty->fetch('article.tpl') // 獲取渲染字符串,不輸出
5. file_put_contents("/html/article/{$id}.html", $html)
6. (可選) 刷新 CDN 緩存 / 推送搜索引擎
MakeHtmlFile 方法<?php
// 放入 Smarty 類或繼承類中
public function MakeHtmlFile(string $filePath, string $content): bool {
// 確保目錄存在
$dir = dirname($filePath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
// 原子寫入:臨時文件 + rename (防止讀到半寫文件)
$tmpFile = $filePath . '.tmp.' . uniqid();
if (file_put_contents($tmpFile, $content, LOCK_EX) === false) {
return false;
}
return rename($tmpFile, $filePath);
}
?>
generate_html.php<?php
require_once 'config.php';
require_once 'init.php'; // 初始化 $smarty, $db
// 1. 獲取需生成的文章 ID 列表 (可加 where 条件、分批)
$sql = "SELECT id FROM articles WHERE status = 1 AND is_static = 1";
$ids = $db->getCol($sql); // 返回一維陣列 [1, 5, 12, ...]
echo "Start generating " . count($ids) . " articles...\n";
foreach ($ids as $id) {
// 2. 獲取單篇文章完整數據
$article = $db->getRow("SELECT * FROM articles WHERE id = ?", [$id]);
if (!$article) continue;
// 3. 賦值模板變量 (注意:模板中統一用 $article 訪問)
$smarty->assign('article', $article);
// 4. 渲染獲取 HTML 字符串
// fetch 參數:模板文件、cache_id、compile_id、display=false(返回字符串)
$html = $smarty->fetch('article.tpl', null, null, false);
// 5. 寫入靜態文件
$filePath = "/var/www/html/article/{$id}.html";
if ($smarty->MakeHtmlFile($filePath, $html)) {
echo "[$id] OK\n";
} else {
echo "[$id] FAILED\n";
}
// 6. 可選:清除該文章相關緩存
$smarty->clearCache('article.tpl', $id);
}
// 7. 批量生成列表頁 (分頁)
$pageSize = 20;
$total = $db->getOne("SELECT COUNT(*) FROM articles WHERE status=1");
$pages = ceil($total / $pageSize);
for ($p = 1; $p <= $pages; $p++) {
$list = $db->getAll("SELECT * FROM articles WHERE status=1 ORDER BY id DESC LIMIT ?, ?", [($p-1)*$pageSize, $pageSize]);
$smarty->assign('articles', $list);
$smarty->assign('page', $p);
$smarty->assign('totalPages', $pages);
$html = $smarty->fetch('list.tpl', null, null, false);
$filePath = "/var/www/html/list/page_{$p}.html";
$smarty->MakeHtmlFile($filePath, $html);
}
echo "All done.\n";
?>
templates/article.tpltemplates/list.tplserver {
root /var/www/html;
index index.html index.php;
location / {
# 嘗試直接服務靜態文件,不存在則 fallback 到 PHP
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
| 策略 | 實現 | 收益 |
|---|---|---|
| 增量生成 | 只重新生成變更的文章 + 受影響列表頁 | 減少 90%+ I/O |
| 異步隊列 | 發布後推送任務到 Redis/RabbitMQ,Worker 消費生成 | 不阻塞用戶請求、削峰填谷 |
| 多進程並行 | PCNTL fork 或 GNU parallel 分批跑 | 利用多核,縮短總耗時 |
| CDN 預熱 | 生成後調用 CDN API 刷新/預熱 URL | 首屏秒開 |
| 模板片段緩存 | Smarty {block} + cache_id 緩存公共片段 (頭部、側邊欄) | 減少重複渲染 |
Smarty 批量靜態化核心:**fetch() 獲取渲染字符串 + file_put_contents() 原子寫入**。關鍵點:模板變量統一命名 (如 $article)、目錄預創建、臨時文件重命名、Nginx try_files 優先靜態。**生產環境務必上異步隊列 + 增量生成 + CDN 預熱**。