首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 靜態頁生成實作:結合 Apache mod_rewrite、輸出緩衝與文件寫入

     編輯:PHP 相關知識

前言

靜態頁生成能大幅降低資料庫查詢壓力,提升頁面載入速度。本文展示一套輕量級實作:使用 Apache mod_rewrite 判斷靜態檔是否存在,不存在時觸發 PHP 動態生成並寫入檔案,後續請求直接由 Web Server 服務靜態檔。

核心技術棧

  • Apache mod_rewrite:URL 重寫與檔案存在性判斷(RewriteCond %{REQUEST_FILENAME} !-f)。
  • PHP Output Buffering (ob_*):捕獲動態生成的 HTML 內容。
  • file_put_contents():將緩衝內容寫入靜態檔案。

目錄結構

/Test/
├── .htaccess          # 重寫規則
├── news.php           # 文章列表頁(動態)
├── getnews.php        # 靜態頁生成觸發器
├── newsDetail.php     # 文章內容模板(動態生成)
└── html/              # 靜態頁輸出目錄(需可寫入權限)
    └── news_3.html    # 生成範例

關鍵程式碼

1. .htaccess 重寫規則

RewriteEngine On
# 首頁重寫
RewriteRule ^index.html$ /news.php [L]

# 靜態頁不存在時重寫至生成腳本
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^html/news_([0-9]+).html$ getnews.php?id=$1 [L]

關鍵點:RewriteCond %{REQUEST_FILENAME} !-f 只有當請求的檔案**不存在**時才觸發後續 RewriteRule,避免生成後再次觸發重寫造成無限迴圈。

2. 文章列表頁(news.php)

<?php
header("Content-Type: text/html; charset=gbk");
mysql_connect("localhost", "root", "");
mysql_query('SET NAMES gbk');
mysql_select_db("test");

$sql = "SELECT `id`, `title` FROM `arc` ORDER BY `id` DESC";
$rs = mysql_query($sql);
while ($row = mysql_fetch_array($rs)) {
    // 連結指向靜態頁 URL
    echo "<a href='/Test/html/news_{$row['id']}.html'>{$row['title']}</a><br>";
}
?>

3. 靜態頁生成觸發器(getnews.php)

<?php
$id = $_GET['id'];
$root = $_SERVER['DOCUMENT_ROOT'];
$filename = "news_{$id}.html";
$file = $root . "/Test/html/" . $filename;

// 1. 開啟輸出緩衝
ob_start();

// 2. 包含內容模板(會輸出 HTML 到緩衝區)
include($root . "/Test/newsDetail.php");

// 3. 取得緩衝內容並寫入檔案
$content = ob_get_contents();
file_put_contents($file, $content);

// 4. 結束緩衝並輸出給瀏覽器(首次請求直接看到內容)
ob_end_flush();
?>

4. 文章內容模板(newsDetail.php)

<?php
header("Content-Type: text/html; charset=gbk");
if (!isset($_GET['id'])) {
    header("Location: https://127.0.0.1/Test/html/news_failed.html");
    exit();
}
$id = $_GET['id'];

mysql_connect("localhost", "root", "");
mysql_query('SET NAMES gbk');
mysql_select_db("test");

$sql = "SELECT `news` FROM `arc` WHERE `id`=$id";
$rs = mysql_query($sql);
while ($row = mysql_fetch_array($rs)) {
    echo $row['news']; // 直接輸出文章內容
}
?>

流程時序圖

用戶請求 /Test/html/news_3.html
        ↓
Apache 檢查 news_3.html 是否存在
        ↓
存在 → 直接返回靜態檔(結束)
不存在 → RewriteRule 重寫至 getnews.php?id=3
        ↓
getnews.php 執行:
  1. ob_start()
  2. include newsDetail.php → 查詢 DB → 輸出 HTML 到緩衝
  3. ob_get_contents() → file_put_contents(news_3.html)
  4. ob_end_flush() → 返回 HTML 給用戶
        ↓
下次請求 → Apache 直接服務 news_3.html

避坑指南

  1. 無限迴圈問題:早期嘗試用 PHP file_exists() 判斷並 header('Location: ...') 導向,會導致重寫規則再次匹配觸發生成腳本,形成迴圈。解決:將「檔案存在性判斷」交給 Apache RewriteCond !-f。
  2. 效能選擇:原本用 fopen() + fwrite(),後改用 ob_* + file_put_contents(),效率提升約 20 倍。
  3. 權限設定:html/ 目錄需給 PHP 進程寫入權限(Linux: chmod 777 或設定擁有者為 www-data)。
  4. 緩存失效:文章更新時需手動刪除對應 news_{id}.html 或建立後台「重新生成」功能。

擴展建議

  • 分頁靜態化:列表頁同理可生成 list_1.html, list_2.html。
  • 局部靜態化:僅將側邊欄、推薦模組等高耗能片段生成靜態片段,主內容保持動態(ESI 或自定義片段快取)。
  • CDN 配合:靜態檔配合 CDN 緩存,實現全站極速訪問。

總結

「Apache 判斷檔案存在性 + PHP 動態生成寫檔」是經典且高效的靜態化架構。核心在於將「存在性檢查」下沉到 Web Server 層,避免 PHP 進程啟動與迴圈問題,同時利用 ob_* 高效捕獲輸出。此模式易於理解、部署簡單,適合中小型內容型網站。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved