隨著網站訪問量增長,動態頁面(PHP + 數據庫)的實時查詢渲染會給服務器帶來巨大壓力。將動態頁面預先生成靜態 HTML 文件,由 Web 服務器直接響應,能大幅降低 CPU/內存/數據庫負載,提升首屏加載速度。本文介紹基於 PHP 命令行模式(CLI)的靜態化生成方案,含核心函數、批量生成邏輯、命名規則設計及 Nginx 配置建議。
利用 PHP CLI 執行動態腳本,捕獲輸出緩存(ob_start())或直接將腳本輸出重定向寫入文件,而非發送給瀏覽器。生成的靜態文件部署在 Web 根目錄,Nginx/Apache 直接靜態服務。
<?php
/**
* 生成靜態 HTML 文件
* @param string $dynamicScript 動態腳本相對路徑(如 "article.php")
* @param string $staticFile 目標靜態文件相對路徑(如 "static/article_123.html")
* @param array $params 传递给动态脚本的 GET 參數 ['id'=>123, 'page'=>1]
* @return bool
*/
function genStaticFile($dynamicScript, $staticFile, $params = array())
{
// 構建完整路徑
$basePath = dirname(__FILE__); // 當前腳本所在目錄
$scriptPath = $basePath . '/' . $dynamicScript;
$filePath = $basePath . '/' . $staticFile;
// 確保目標目錄存在
$dir = dirname($filePath);
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
// 構建查詢字符串
$queryString = http_build_query($params);
// 方法 1:CLI 直接執行腳本並捕獲輸出(推薦,隔離環境)
$cmd = sprintf(
'php %s "%s" > %s 2>&1',
escapeshellarg($scriptPath),
escapeshellarg($queryString),
escapeshellarg($filePath)
);
exec($cmd, $output, $returnVar);
if ($returnVar !== 0) {
error_log("靜態化失敗 [$dynamicScript]: " . implode("\n", $output));
return false;
}
// 方法 2:同進程 include + 輸出緩存(較輕量,但變量污染風險)
/*
$_GET = array_merge($_GET, $params); // 注入參數
ob_start();
include $scriptPath;
$content = ob_get_clean();
return file_put_contents($filePath, $content) !== false;
*/
return true;
}
// 動態腳本示例:article.php
// ?>
// <?php
// // 接收參數
// $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
// // 查詢數據庫...
// // 輸出 HTML
// include 'template/article.tpl.php';
// ?>
<?php
// gen_all.php - 定時任務 / 手動執行
set_time_limit(0);
ini_set('memory_limit', '512M');
require_once 'config.php';
require_once 'gen_static_file.php'; // 上述函數
// 1. 生成首頁
genStaticFile('index.php', 'static/index.html');
// 2. 生成分類列表頁(分頁)
$catIds = array(1, 2, 3, 5, 8); // 從數據庫獲取
foreach ($catIds as $catId) {
$totalPages = getTotalPages($catId); // 自定義函數
for ($p = 1; $p <= $totalPages; $p++) {
genStaticFile(
'category.php',
"static/category_{$catId}_page_{$p}.html",
array('cat' => $catId, 'page' => $p)
);
// 避免過載,可適當 sleep
usleep(100000); // 0.1 秒
}
}
// 3. 生成文章詳情頁(增量/全量)
$articleIds = getAllArticleIds(); // 或 getRecentArticleIds()
foreach ($articleIds as $id) {
genStaticFile(
'article.php',
"static/article_{$id}.html",
array('id' => $id)
);
}
echo "靜態化生成完成。\n";
?>
| 頁面類型 | URL 規則 | 靜態文件路徑 |
|---|---|---|
| 首頁 | / | /static/index.html |
| 分類列表 | /cat/12/page/3 | /static/cat_12_page_3.html |
| 文章詳情 | /article/456 | /static/article_456.html |
| 標簽聚合 | /tag/seo/page/2 | /static/tag_seo_page_2.html |
原則:唯一性、可預測、層級淺(避免極深目錄)、字符安全(僅字母數字下劃線連字符)。
server {
listen 80;
server_name example.com;
root /var/www/html; # 靜態文件根目錄
location / {
# 1. 優先嘗試直接服務靜態文件
try_files /static$uri /static$uri.html /static$uri/index.html @php;
# 2. 靜態文件緩存策略
location ~* \.(html|css|js|jpg|png|gif|ico|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public";
}
}
location @php {
# 3. 回退到 PHP 動態處理(如未生成靜態、POST 請求、帶查詢參數等)
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
}
ob_gzhandler 或 Nginx gzip_static on 預壓縮 .gz 文件。| 場景 | 推薦方案 |
|---|---|
| 內容型站點(博客、CMS、新聞) | 全站靜態化 + 增量更新 |
| 電商商品頁(價格、庫存頻變) | 局部靜態化(框架靜態、數據 AJAX)或 ESI |
| 用戶中心、後台管理 | 完全動態,不靜態化 |
| 高併發活動頁(秒殺、大促) | 預生成純靜態 + CDN 边緣緩存 |
PHP 靜態化生成是經典且高效的性能優化手段。結合合理的命名規則、Nginx try_files 回退、增量更新機制,可將動態頁面響應時間從百毫秒級降至毫秒級,支撐更大流量洪峰。