初始化知识库网页系统

功能:
- 用户登录/退出
- 文档列表展示(支持子目录)
- 关键词搜索
- Markdown 文档在线查看
- 管理员添加用户脚本
This commit is contained in:
2026-02-14 00:04:12 +08:00
commit 608d05cf5e
10 changed files with 1042 additions and 0 deletions
+138
View File
@@ -0,0 +1,138 @@
# 知识库网页系统
一个简单的知识库文档管理系统,支持多用户登录、文档列表和搜索。
## 功能
- ✅ 账号密码登录
- ✅ 每个用户有独立的知识库目录
- ✅ 文档列表展示
- ✅ 关键词搜索(标题+内容)
- ✅ 在线查看文档(支持 Markdown)
- ✅ 管理员添加用户
## 目录结构
```
kb-web/
├── index.php # 登录页
├── dashboard.php # 文档列表 + 搜索
├── view.php # 查看文档内容
├── logout.php # 退出登录
├── config.php # 数据库配置
├── add_user.php # 添加用户脚本
├── style.css # 样式
├── init.sql # 数据库初始化
├── README.md # 说明文档
└── {username}/ # 用户文档目录
├── 文档1.md
└── 文档2.md
```
## 部署步骤
### 1. 上传文件
将整个 `kb-web` 目录上传到服务器的网站目录中。
### 2. 创建数据库
```bash
# 登录 MySQL
mysql -u root -p
# 执行初始化脚本
source init.sql
```
或者直接在 MySQL 中执行:
```sql
CREATE DATABASE IF NOT EXISTS kb_web DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
```
### 3. 修改配置
编辑 `config.php`,修改数据库连接信息:
```php
define('DB_HOST', 'localhost');
define('DB_NAME', 'kb_web');
define('DB_USER', 'your_db_user');
define('DB_PASS', 'your_db_password');
```
### 4. 添加用户
在服务器上执行:
```bash
cd /path/to/kb-web
php add_user.php 用户名 密码
```
示例:
```bash
php add_user.php zhangqing mypassword123
```
### 5. 添加文档
将用户的文档(.md 或 .txt 格式)放入对应用户目录:
```bash
cp ~/knowledge-base/analyzed/*.md /path/to/kb-web/zhangqing/
```
### 6. 访问
打开浏览器访问:`http://your-domain.com/kb-web/`
## 管理员操作
### 添加新用户
```bash
php add_user.php newuser newpassword
```
### 重置密码
```bash
# 删除旧用户
mysql -u root -p -e "DELETE FROM kb_web.users WHERE username='olduser';"
# 重新添加
php add_user.php olduser newpassword
```
### 批量导入文档
```bash
# 将分析好的文档复制到用户目录
cp ~/work/knowledge-base/analyzed/*.md /path/to/kb-web/zhangqing/
```
## 注意事项
1. **安全性**
- 修改 `config.php` 中的数据库密码
- 确保 `config.php` 不可被外部访问(LNMP 默认已处理)
- 定期备份数据库
2. **文件权限**
```bash
chown -R www-data:www-data /path/to/kb-web
chmod -R 755 /path/to/kb-web
```
3. **支持的文档格式**
- .md (Markdown)
- .txt (纯文本)
- .markdown
## 技术栈
- PHP 7.4+
- MySQL 5.7+
- 纯前端(HTML + CSS + JS)
+63
View File
@@ -0,0 +1,63 @@
<?php
/**
* 添加用户脚本
* 使用方法: php add_user.php <username> <password>
* 示例: php add_user.php zhangqing mypassword123
*/
if ($argc < 3) {
echo "使用方法: php add_user.php <username> <password>\n";
echo "示例: php add_user.php zhangqing mypassword123\n";
exit(1);
}
$username = $argv[1];
$password = $argv[2];
// 验证用户名格式
if (!preg_match('/^[a-zA-Z0-9_]{3,50}$/', $username)) {
echo "错误: 用户名只能是字母、数字、下划线,长度3-50\n";
exit(1);
}
// 验证密码长度
if (strlen($password) < 6) {
echo "错误: 密码长度至少6位\n";
exit(1);
}
require_once 'config.php';
try {
$db = getDB();
// 检查用户是否已存在
$stmt = $db->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute([$username]);
if ($stmt->fetch()) {
echo "错误: 用户 '$username' 已存在\n";
exit(1);
}
// 创建密码哈希
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
// 插入用户
$stmt = $db->prepare("INSERT INTO users (username, password_hash) VALUES (?, ?)");
$stmt->execute([$username, $passwordHash]);
// 创建用户文档目录
$docDir = __DIR__ . '/' . $username;
if (!is_dir($docDir)) {
mkdir($docDir, 0755, true);
echo "✅ 用户目录已创建: $docDir\n";
}
echo "✅ 用户 '$username' 添加成功!\n";
echo " 用户名: $username\n";
echo " 密码: $password\n";
} catch (PDOException $e) {
echo "数据库错误: " . $e->getMessage() . "\n";
exit(1);
}
+57
View File
@@ -0,0 +1,57 @@
<?php
// 知识库网页系统 - 配置文件
// 部署时请修改以下配置
// 数据库配置
define('DB_HOST', 'localhost');
define('DB_NAME', 'kb_web');
define('DB_USER', 'root');
define('DB_PASS', 'your_password');
// Session 配置
session_start();
// 数据库连接
function getDB() {
static $pdo = null;
if ($pdo === null) {
try {
$pdo = new PDO(
"mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4",
DB_USER,
DB_PASS,
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
]
);
} catch (PDOException $e) {
die("数据库连接失败: " . $e->getMessage());
}
}
return $pdo;
}
// 检查登录状态
function checkLogin() {
if (!isset($_SESSION['user_id'])) {
header('Location: index.php');
exit;
}
}
// 获取当前用户信息
function getCurrentUser() {
if (!isset($_SESSION['user_id'])) {
return null;
}
$db = getDB();
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
return $stmt->fetch();
}
// 获取用户文档目录
function getUserDocDir($username) {
return __DIR__ . '/' . $username;
}
+153
View File
@@ -0,0 +1,153 @@
<?php
require_once 'config.php';
checkLogin();
$user = getCurrentUser();
$username = $user['username'];
$docDir = getUserDocDir($username);
// 搜索关键词
$search = trim($_GET['q'] ?? '');
// 递归获取文档列表
$documents = [];
function scanDirectory($dir, $baseDir, $search) {
$docs = [];
if (!is_dir($dir)) return $docs;
$items = scandir($dir);
foreach ($items as $item) {
if ($item === '.' || $item === '..') continue;
$fullPath = $dir . '/' . $item;
$relativePath = str_replace($baseDir . '/', '', $fullPath);
if (is_dir($fullPath)) {
// 递归扫描子目录
$docs = array_merge($docs, scanDirectory($fullPath, $baseDir, $search));
} elseif (is_file($fullPath)) {
// 只处理 .md 和 .txt 文件
$ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
if (!in_array($ext, ['md', 'txt', 'markdown'])) continue;
$content = file_get_contents($fullPath);
// 搜索过滤
if ($search) {
$searchLower = mb_strtolower($search);
$titleLower = mb_strtolower($item);
$contentLower = mb_strtolower($content);
if (strpos($titleLower, $searchLower) === false &&
strpos($contentLower, $searchLower) === false) {
continue;
}
}
$docs[] = [
'name' => $item,
'path' => $relativePath,
'folder' => dirname($relativePath) === '.' ? '' : dirname($relativePath),
'size' => filesize($fullPath),
'mtime' => filemtime($fullPath),
'preview' => mb_substr(strip_tags($content), 0, 200)
];
}
}
return $docs;
}
$documents = scanDirectory($docDir, $docDir, $search);
// 按文件夹分组,然后按修改时间排序
usort($documents, function($a, $b) {
// 先按文件夹排序
if ($a['folder'] !== $b['folder']) {
return strcmp($a['folder'], $b['folder']);
}
// 同一文件夹按修改时间排序(新文件在前)
return $b['mtime'] - $a['mtime'];
});
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>知识库 - <?php echo htmlspecialchars($username); ?></title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="dashboard">
<header class="header">
<h1>📚 我的知识库</h1>
<div class="user-info">
<span><?php echo htmlspecialchars($username); ?></span>
<a href="logout.php" class="btn-logout">退出</a>
</div>
</header>
<div class="search-bar">
<form method="GET" action="">
<input type="text" name="q" placeholder="搜索文档..."
value="<?php echo htmlspecialchars($search); ?>">
<button type="submit">搜索</button>
<?php if ($search): ?>
<a href="dashboard.php" class="btn-clear">清除</a>
<?php endif; ?>
</form>
</div>
<div class="stats">
共 <?php echo count($documents); ?> 个文档
<?php if ($search): ?>
<span class="search-hint">(搜索: "<?php echo htmlspecialchars($search); ?>")</span>
<?php endif; ?>
</div>
<div class="document-list">
<?php if (empty($documents)): ?>
<div class="empty">
<?php if ($search): ?>
没有找到匹配的文档
<?php else: ?>
暂无文档
<?php endif; ?>
</div>
<?php else: ?>
<?php
$currentFolder = '';
foreach ($documents as $doc):
// 显示文件夹分隔
if ($doc['folder'] !== $currentFolder):
$currentFolder = $doc['folder'];
if ($currentFolder):
?>
<div class="folder-separator">
📁 <?php echo htmlspecialchars($currentFolder); ?>
</div>
<?php
endif;
endif;
?>
<a href="view.php?file=<?php echo urlencode($doc['path']); ?><?php echo $search ? '&q=' . urlencode($search) : ''; ?>"
class="document-card">
<div class="doc-icon">📄</div>
<div class="doc-info">
<div class="doc-name"><?php echo htmlspecialchars($doc['name']); ?></div>
<div class="doc-meta">
<?php echo round($doc['size'] / 1024, 1); ?> KB ·
<?php echo date('Y-m-d H:i', $doc['mtime']); ?>
<?php if ($doc['folder']): ?>
· 📁 <?php echo htmlspecialchars($doc['folder']); ?>
<?php endif; ?>
</div>
<div class="doc-preview"><?php echo htmlspecialchars($doc['preview']); ?>...</div>
</div>
</a>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
# 这是一个示例文档
这是您的知识库示例文档。
## 主要内容
- 支持搜索功能
- 支持 Markdown 格式
- 可以查看文档预览
## 代码示例
```python
def hello():
print("Hello, Knowledge Base!")
```
## 链接
这是一个 [示例链接](https://example.com)。
+64
View File
@@ -0,0 +1,64 @@
<?php
require_once 'config.php';
// 已登录则跳转到主页
if (isset($_SESSION['user_id'])) {
header('Location: dashboard.php');
exit;
}
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = trim($_POST['username'] ?? '');
$password = $_POST['password'] ?? '';
if (empty($username) || empty($password)) {
$error = '请输入用户名和密码';
} else {
$db = getDB();
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch();
if ($user && password_verify($password, $user['password_hash'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
header('Location: dashboard.php');
exit;
} else {
$error = '用户名或密码错误';
}
}
}
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>知识库 - 登录</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="login-container">
<div class="login-box">
<h1>📚 知识库</h1>
<?php if ($error): ?>
<div class="error"><?php echo htmlspecialchars($error); ?></div>
<?php endif; ?>
<form method="POST" action="">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" id="username" name="username" required autofocus>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" name="password" required>
</div>
<button type="submit" class="btn-primary">登录</button>
</form>
</div>
</div>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
-- 知识库网页系统 - 数据库初始化脚本
-- 运行方式: mysql -u root -p kb_web < init.sql
-- 创建数据库(如果不存在)
CREATE DATABASE IF NOT EXISTS kb_web DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE kb_web;
-- 用户表
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- ============================================
-- 添加用户示例
-- ============================================
-- 密码使用 PHP password_hash() 生成
-- PHP 生成密码: echo password_hash('your_password', PASSWORD_DEFAULT);
-- ============================================
-- 示例:添加用户 demo,密码为 demo123
-- 密码哈希值需要用 PHP 生成,以下是示例格式:
-- INSERT INTO users (username, password_hash) VALUES
-- ('demo', '$2y$10$...');
-- ============================================
-- 管理员添加用户的 PHP 脚本 (add_user.php)
-- 可以单独部署在管理目录中
-- ============================================
+9
View File
@@ -0,0 +1,9 @@
<?php
require_once 'config.php';
// 清除 session
session_destroy();
// 跳转到登录页
header('Location: index.php');
exit;
+402
View File
@@ -0,0 +1,402 @@
/* 知识库网页系统 - 样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: #f5f7fa;
color: #333;
line-height: 1.6;
}
/* 登录页 */
.login-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.login-box {
background: white;
padding: 40px;
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
width: 100%;
max-width: 400px;
}
.login-box h1 {
text-align: center;
margin-bottom: 30px;
color: #333;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #555;
}
.form-group input {
width: 100%;
padding: 12px 16px;
border: 2px solid #e1e5eb;
border-radius: 8px;
font-size: 16px;
transition: border-color 0.2s;
}
.form-group input:focus {
outline: none;
border-color: #667eea;
}
.btn-primary {
width: 100%;
padding: 14px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
.error {
background: #fee;
color: #c00;
padding: 12px;
border-radius: 8px;
margin-bottom: 20px;
text-align: center;
}
/* 主页 */
.dashboard {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
padding-bottom: 16px;
border-bottom: 2px solid #e1e5eb;
}
.header h1 {
color: #333;
}
.user-info {
display: flex;
align-items: center;
gap: 16px;
}
.user-info span {
color: #666;
}
.btn-logout {
padding: 8px 16px;
background: #f0f0f0;
color: #666;
text-decoration: none;
border-radius: 6px;
font-size: 14px;
transition: background 0.2s;
}
.btn-logout:hover {
background: #e0e0e0;
}
/* 搜索栏 */
.search-bar {
margin-bottom: 20px;
}
.search-bar form {
display: flex;
gap: 10px;
}
.search-bar input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e1e5eb;
border-radius: 8px;
font-size: 16px;
}
.search-bar input:focus {
outline: none;
border-color: #667eea;
}
.search-bar button {
padding: 12px 24px;
background: #667eea;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-size: 16px;
}
.search-bar button:hover {
background: #5a6fd6;
}
.btn-clear {
padding: 12px 16px;
background: #f0f0f0;
color: #666;
text-decoration: none;
border-radius: 8px;
display: flex;
align-items: center;
}
.stats {
color: #666;
margin-bottom: 16px;
}
.search-hint {
color: #999;
font-size: 14px;
}
/* 文档列表 */
.document-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.document-card {
display: flex;
gap: 16px;
padding: 20px;
background: white;
border-radius: 10px;
text-decoration: none;
color: inherit;
transition: transform 0.2s, box-shadow 0.2s;
border: 1px solid #e1e5eb;
}
.document-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.doc-icon {
font-size: 32px;
flex-shrink: 0;
}
.doc-info {
flex: 1;
min-width: 0;
}
.doc-name {
font-size: 18px;
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.doc-meta {
font-size: 13px;
color: #999;
margin-bottom: 8px;
}
.doc-preview {
font-size: 14px;
color: #666;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.empty {
text-align: center;
padding: 60px 20px;
color: #999;
font-size: 18px;
}
/* 文档查看页 */
.view-page {
max-width: 900px;
margin: 0 auto;
padding: 20px;
}
.view-page .header {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.folder-info {
color: #666;
font-size: 14px;
margin-top: 4px;
}
.btn-back {
display: inline-block;
padding: 8px 16px;
background: #f0f0f0;
color: #666;
text-decoration: none;
border-radius: 6px;
font-size: 14px;
}
.btn-back:hover {
background: #e0e0e0;
}
.document-content {
background: white;
padding: 40px;
border-radius: 10px;
border: 1px solid #e1e5eb;
line-height: 1.8;
}
.document-content h1 {
font-size: 28px;
margin: 24px 0 16px 0;
padding-bottom: 12px;
border-bottom: 2px solid #e1e5eb;
}
.document-content h1:first-child {
margin-top: 0;
}
.document-content h2 {
font-size: 22px;
margin: 20px 0 12px 0;
}
.document-content h3 {
font-size: 18px;
margin: 16px 0 8px 0;
}
.document-content p {
margin-bottom: 16px;
}
.document-content ul {
margin: 16px 0;
padding-left: 24px;
}
.document-content li {
margin-bottom: 8px;
}
.document-content code {
background: #f5f5f5;
padding: 2px 6px;
border-radius: 4px;
font-family: "SF Mono", Monaco, "Courier New", monospace;
font-size: 14px;
}
.document-content pre {
background: #2d2d2d;
color: #f8f8f2;
padding: 16px;
border-radius: 8px;
overflow-x: auto;
margin: 16px 0;
}
.document-content pre code {
background: none;
padding: 0;
color: inherit;
}
.document-content a {
color: #667eea;
text-decoration: none;
}
.document-content a:hover {
text-decoration: underline;
}
/* 搜索高亮 */
mark {
background: #fff3cd;
padding: 1px 4px;
border-radius: 3px;
}
/* 文件夹分隔符 */
.folder-separator {
padding: 16px 20px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-left: 4px solid #667eea;
margin: 16px 0 8px 0;
font-weight: 600;
color: #495057;
font-size: 14px;
}
.folder-separator:first-child {
margin-top: 0;
}
/* 文档查看页 */
@media (max-width: 600px) {
.login-box {
margin: 20px;
padding: 30px;
}
.document-card {
padding: 16px;
}
.doc-icon {
display: none;
}
.document-content {
padding: 20px;
}
}
+103
View File
@@ -0,0 +1,103 @@
<?php
require_once 'config.php';
checkLogin();
$user = getCurrentUser();
$username = $user['username'];
$docDir = getUserDocDir($username);
// 获取文件名
$file = $_GET['file'] ?? '';
$search = $_GET['q'] ?? '';
// 安全检查:防止目录遍历攻击(允许子目录,但不能跳出用户目录)
if (empty($file) || strpos($file, '..') !== false) {
die('无效的文件名');
}
$filePath = $docDir . '/' . $file;
// 确保文件在用户目录内
$realPath = realpath($filePath);
$realDocDir = realpath($docDir);
if ($realPath === false || strpos($realPath, $realDocDir) !== 0) {
die('文件不存在或无权访问');
}
if (!file_exists($filePath)) {
die('文件不存在');
}
$content = file_get_contents($filePath);
// 简单的 Markdown 转换
function markdownToHtml($text) {
// 标题
$text = preg_replace('/^### (.*$)/m', '<h3>$1</h3>', $text);
$text = preg_replace('/^## (.*$)/m', '<h2>$1</h2>', $text);
$text = preg_replace('/^# (.*$)/m', '<h1>$1</h1>', $text);
// 粗体和斜体
$text = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $text);
$text = preg_replace('/\*(.+?)\*/', '<em>$1</em>', $text);
// 代码块
$text = preg_replace('/```(\w*)\n(.*?)```/s', '<pre><code class="language-$1">$2</code></pre>', $text);
$text = preg_replace('/`(.+?)`/', '<code>$1</code>', $text);
// 链接
$text = preg_replace('/\[(.+?)\]\((.+?)\)/', '<a href="$2" target="_blank">$1</a>', $text);
// 列表
$text = preg_replace('/^- (.*$)/m', '<li>$1</li>', $text);
$text = preg_replace('/(<li>.*<\/li>\n?)+/', '<ul>$0</ul>', $text);
// 段落
$text = preg_replace('/\n\n/', '</p><p>', $text);
$text = '<p>' . $text . '</p>';
return $text;
}
// 高亮搜索词
function highlightSearch($text, $search) {
if (empty($search)) return $text;
return preg_replace('/(' . preg_quote($search, '/') . ')/i',
'<mark>$1</mark>', $text);
}
$htmlContent = markdownToHtml(htmlspecialchars($content));
if ($search) {
$htmlContent = highlightSearch($htmlContent, $search);
}
// 获取文件名(不含路径)
$displayName = basename($file);
$folder = dirname($file) !== '.' ? dirname($file) : '';
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($displayName); ?> - 知识库</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="view-page">
<header class="header">
<a href="dashboard.php<?php echo $search ? '?q=' . urlencode($search) : ''; ?>" class="btn-back">
← 返回列表
</a>
<h1><?php echo htmlspecialchars($displayName); ?></h1>
<?php if ($folder): ?>
<div class="folder-info">📁 <?php echo htmlspecialchars($folder); ?></div>
<?php endif; ?>
</header>
<div class="document-content">
<?php echo $htmlContent; ?>
</div>
</div>
</body>
</html>