將動態頁面靜態化可大幅降低資料庫壓力、提升前端效能並利於 SEO。本文示範從 MySQL 讀取資料,套用 HTML 模板替換佔位符,批量生成 .html 或 .txt 靜態檔案的完整流程。
conn.php<?php
// 建議改用 PDO 或 mysqli,此處沿用舊 mysql_* 示範邏輯
$link = mysqli_connect("localhost", "db_user", "db_pass", "my_database");
if (!$link) die("Connect failed: " . mysqli_connect_error());
mysqli_set_charset($link, "utf8");
?>
template.html<!DOCTYPE html>
<html xmlns="https://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{title}</title>
</head>
<body>
{introduce}
</body>
</html>
佔位符採用 {欄位名} 格式,易於 str_replace 處理。
generate_html.php<?php
require_once("conn.php");
$query = "SELECT id, title, introduce FROM my_table";
$result = mysqli_query($link, $query);
if (!$result) die("Query failed: " . mysqli_error($link));
$template = file_get_contents("template.html");
if ($template === false) die("Template file not found");
$output_dir = "html/";
if (!is_dir($output_dir)) mkdir($output_dir, 0755, true);
while ($row = mysqli_fetch_assoc($result)) {
$id = $row['id'];
$title = $row['title'];
$introduce = $row['introduce'];
// 替換佔位符
$html = str_replace(
['{title}', '{introduce}'],
[$title, $introduce],
$template
);
$path = $output_dir . $id . ".html";
if (file_put_contents($path, $html) === false) {
error_log("Failed to write $path");
} else {
echo "生成成功: $path
";
}
}
mysqli_free_result($result);
mysqli_close($link);
?>
generate_txt.php<?php
require_once("conn.php");
$query = "SELECT id, title, introduce FROM pro_courses";
$result = mysqli_query($link, $query);
$output_dir = "txt/";
if (!is_dir($output_dir)) mkdir($output_dir, 0755, true);
while ($row = mysqli_fetch_assoc($result)) {
$id = $row['id'];
$content = strip_tags($row['introduce']); // 移除 HTML 標籤
$path = $output_dir . $id . ".txt";
file_put_contents($path, $content);
}
mysqli_free_result($result);
mysqli_close($link);
?>
// 大量檔案時,累積內容批次寫入或使用 fwrite 追加
$fp = fopen($path, 'w');
fwrite($fp, $html);
fclose($fp);
<?php
// 使用 Smarty / Blade / Twig
$smarty->assign('row', $row);
$html = $smarty->fetch('template.tpl');
file_put_contents($path, $html);
{id: 123, action: 'generate_html'}/var/www/html/static/v20240115/ 版本目錄。root 指向最新版本,或使用符號連結切換。$status_file = "generate_status.json";
$status = file_exists($status_file) ? json_decode(file_get_contents($status_file), true) : [];
$last_id = $status['last_id'] ?? 0;
$query = "SELECT ... WHERE id > $last_id ORDER BY id LIMIT 1000";
// ... 生成 ...
$status['last_id'] = $current_id;
file_put_contents($status_file, json_encode($status));
server {
listen 80;
server_name static.example.com;
root /var/www/html/static/current;
location / {
try_files $uri $uri/ =404;
expires 30d;
add_header Cache-Control "public";
}
# 防止 PHP 檔案被執行
location ~ \.php$ {
deny all;
}
}
| 問題 | 原因 | 解決 |
|---|---|---|
| 生成檔案為空/亂碼 | 模板讀取失敗、編碼不一致 | 確認 template.html 為 UTF-8 無 BOM、file_get_contents 正常 |
| 權限拒絕 | 目錄擁有者非 PHP 執行用戶 | chown www-data:www-data html/、chmod 755 |
| 大量資料記憶體耗盡 | 一次撈取過多行、模板過大 | 分批處理 LIMIT、使用生成器 yield |
| 佔位符未替換 | 欄位名拼寫錯誤、模板佔位符格式不符 | 統一佔位符命名規範、加入缺失欄位預設值 |