Initial commit: Oraset B-5 with C++ style features
This commit is contained in:
@@ -0,0 +1,377 @@
|
||||
<?php
|
||||
/**
|
||||
* Oraset 文档系统
|
||||
* 自动识别 md 文件夹下的 md 文件并显示
|
||||
* 支持 HTML 和 Markdown 语法
|
||||
*
|
||||
* 使用方式:
|
||||
* index.php - 显示第一个可用文档
|
||||
* index.php?doc=name - 显示指定文档
|
||||
* index.php?list - 列出所有文档
|
||||
* index.php?list-api - 输出 JSON 格式的文档列表
|
||||
*/
|
||||
|
||||
// 配置
|
||||
$md_dir = __DIR__ . '/md';
|
||||
$css_path = '../css/style.css';
|
||||
$version_file = dirname(__DIR__) . '/download/version.txt';
|
||||
|
||||
// 获取版本号
|
||||
function get_version($version_file) {
|
||||
if (file_exists($version_file)) {
|
||||
return trim(file_get_contents($version_file));
|
||||
}
|
||||
return '4.0.1-BetaN(+AU)';
|
||||
}
|
||||
|
||||
$current_version = get_version($version_file);
|
||||
|
||||
// 获取所有 md 文件列表
|
||||
function get_articles_list($md_dir) {
|
||||
$articles = [];
|
||||
$files = glob($md_dir . '/*.md');
|
||||
|
||||
foreach ($files as $file) {
|
||||
$name = basename($file, '.md');
|
||||
$content = file_get_contents($file);
|
||||
|
||||
// 提取标题
|
||||
$title = $name;
|
||||
if (preg_match('/^# (.+)$/m', $content, $matches)) {
|
||||
$title = $matches[1];
|
||||
}
|
||||
|
||||
// 提取描述(第一段非标题、非代码块、非列表的内容)
|
||||
$desc = '';
|
||||
$lines = explode("\n", $content);
|
||||
$in_code = false;
|
||||
foreach ($lines as $line) {
|
||||
$trimmed = trim($line);
|
||||
|
||||
// 跳过代码块
|
||||
if (strpos($trimmed, '```') !== false) {
|
||||
$in_code = !$in_code;
|
||||
continue;
|
||||
}
|
||||
if ($in_code) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 跳过空行、标题、列表、太短的行
|
||||
if ($trimmed === '' ||
|
||||
preg_match('/^#/', $trimmed) ||
|
||||
preg_match('/^-/', $trimmed) ||
|
||||
strlen($trimmed) < 10) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 找到第一个有效描述,去除Markdown语法
|
||||
$desc = $trimmed;
|
||||
// 去除链接语法
|
||||
$desc = preg_replace('/\[([^\]]+)\]\([^)]+\)/', '$1', $desc);
|
||||
// 去除粗体/斜体
|
||||
$desc = preg_replace('/\*+([^*]+)\*+/', '$1', $desc);
|
||||
// 去除行内代码
|
||||
$desc = preg_replace('/`([^`]+)`/', '$1', $desc);
|
||||
|
||||
if (strlen($desc) > 100) {
|
||||
$desc = substr($desc, 0, 100) . '...';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$articles[] = [
|
||||
'name' => $name,
|
||||
'title' => $title,
|
||||
'desc' => $desc,
|
||||
'file' => $file
|
||||
];
|
||||
}
|
||||
|
||||
return $articles;
|
||||
}
|
||||
|
||||
// JSON API 模式
|
||||
if (isset($_GET['list-api'])) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$articles = get_articles_list($md_dir);
|
||||
echo json_encode([
|
||||
'version' => $current_version,
|
||||
'articles' => $articles
|
||||
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Markdown 解析函数(改进版)
|
||||
function parse_markdown($text, $version) {
|
||||
// 替换版本号占位符
|
||||
$text = str_replace('{{VERSION}}', $version, $text);
|
||||
|
||||
// 处理代码块(先处理,避免被其他规则干扰)
|
||||
$text = preg_replace_callback('/```(\w*)\n(.*?)```/s', function($m) {
|
||||
$lang = $m[1] ? ' class="language-' . htmlspecialchars($m[1]) . '"' : '';
|
||||
return '<pre><code' . $lang . '>' . htmlspecialchars($m[2]) . '</code></pre>';
|
||||
}, $text);
|
||||
|
||||
// 处理行内代码
|
||||
$text = preg_replace('/`([^`]+)`/', '<code>$1</code>', $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);
|
||||
|
||||
// 处理链接(支持 URL 中包含括号)
|
||||
$text = preg_replace_callback('/\[([^\]]+)\]\(\s*([^)]*(?:\([^)]*\)[^)]*)*)\s*\)/', function($m) {
|
||||
$link_text = $m[1];
|
||||
$url = trim($m[2]);
|
||||
return '<a href="' . htmlspecialchars($url, ENT_QUOTES, 'UTF-8') . '">' . $link_text . '</a>';
|
||||
}, $text);
|
||||
|
||||
// 处理分隔线
|
||||
$text = preg_replace('/^---$/m', '<hr>', $text);
|
||||
|
||||
// 处理无序列表
|
||||
$lines = explode("\n", $text);
|
||||
$result = [];
|
||||
$in_list = false;
|
||||
$in_code = false;
|
||||
$in_paragraph = false;
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$trimmed = trim($line);
|
||||
|
||||
// 检查是否在代码块中
|
||||
if (strpos($trimmed, '<pre>') !== false) {
|
||||
$in_code = true;
|
||||
}
|
||||
if (strpos($trimmed, '</pre>') !== false) {
|
||||
$in_code = false;
|
||||
}
|
||||
|
||||
if ($in_code) {
|
||||
$result[] = $line;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理列表项
|
||||
if (preg_match('/^- (.+)$/', $trimmed, $m)) {
|
||||
if (!$in_list) {
|
||||
$result[] = '<ul>';
|
||||
$in_list = true;
|
||||
}
|
||||
$result[] = '<li>' . $m[1] . '</li>';
|
||||
continue;
|
||||
}
|
||||
|
||||
// 结束列表
|
||||
if ($in_list && !preg_match('/^-/', $trimmed)) {
|
||||
$result[] = '</ul>';
|
||||
$in_list = false;
|
||||
}
|
||||
|
||||
// 处理块元素(标题、hr、pre等)
|
||||
if (preg_match('/^<(h[1-6]|hr|pre|ul|li)/', $trimmed) || $trimmed === '') {
|
||||
if ($in_paragraph) {
|
||||
$result[] = '</p>';
|
||||
$in_paragraph = false;
|
||||
}
|
||||
$result[] = $line;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 处理段落
|
||||
if (!$in_paragraph && $trimmed !== '') {
|
||||
$result[] = '<p>' . $trimmed;
|
||||
$in_paragraph = true;
|
||||
} else if ($in_paragraph && $trimmed !== '') {
|
||||
$result[] = $trimmed;
|
||||
}
|
||||
}
|
||||
|
||||
// 结束未闭合的标签
|
||||
if ($in_list) {
|
||||
$result[] = '</ul>';
|
||||
}
|
||||
if ($in_paragraph) {
|
||||
$result[] = '</p>';
|
||||
}
|
||||
|
||||
return implode("\n", $result);
|
||||
}
|
||||
|
||||
// 获取文章列表
|
||||
$articles = get_articles_list($md_dir);
|
||||
|
||||
// 判断是否显示列表模式
|
||||
$show_list = isset($_GET['list']);
|
||||
|
||||
// 获取请求的文档
|
||||
$doc = isset($_GET['doc']) ? $_GET['doc'] : '';
|
||||
|
||||
// 安全处理:只允许字母、数字、下划线、连字符
|
||||
$doc = preg_replace('/[^a-zA-Z0-9_-]/', '', $doc);
|
||||
|
||||
// 文件路径
|
||||
$file_path = '';
|
||||
if ($doc !== '') {
|
||||
$file_path = $md_dir . '/' . $doc . '.md';
|
||||
}
|
||||
|
||||
// 如果文件不存在,显示第一个可用文档
|
||||
if ($file_path === '' || !file_exists($file_path)) {
|
||||
if (count($articles) > 0) {
|
||||
$file_path = $articles[0]['file'];
|
||||
$doc = $articles[0]['name'];
|
||||
} else {
|
||||
// 没有文档时显示默认页面
|
||||
$html_content = '<h1>Oraset 文档</h1><p>暂无文档。</p>';
|
||||
$title = 'Oraset 文档';
|
||||
$doc = '';
|
||||
}
|
||||
}
|
||||
|
||||
// 读取文档内容
|
||||
if ($file_path !== '' && file_exists($file_path)) {
|
||||
$content = file_get_contents($file_path);
|
||||
|
||||
// 先执行 PHP 代码
|
||||
ob_start();
|
||||
eval('?>' . $content . '<?php ');
|
||||
$content = ob_get_clean();
|
||||
|
||||
// 替换版本号占位符 {{VERSION}}
|
||||
$content = str_replace('{{VERSION}}', $current_version, $content);
|
||||
|
||||
$html_content = parse_markdown($content, $current_version);
|
||||
|
||||
// 提取当前文档标题
|
||||
$title = 'Oraset 文档';
|
||||
if (preg_match('/^# (.+)$/m', $content, $matches)) {
|
||||
$title = $matches[1] . ' - Oraset';
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是列表模式,生成列表 HTML
|
||||
if ($show_list) {
|
||||
$title = '文档列表 - Oraset';
|
||||
$list_html = "<h1>文档列表</h1>\n<p>以下是所有可用的文档:</p>\n<ul class=\"doc-list\">";
|
||||
foreach ($articles as $art) {
|
||||
$list_html .= '<li>';
|
||||
$list_html .= '<a href="?doc=' . htmlspecialchars($art['name']) . '">' . htmlspecialchars($art['title']) . '</a>';
|
||||
if ($art['desc']) {
|
||||
$list_html .= '<br><span class="doc-desc">' . htmlspecialchars($art['desc']) . '</span>';
|
||||
}
|
||||
$list_html .= '</li>';
|
||||
}
|
||||
$list_html .= '</ul>';
|
||||
$html_content = $list_html;
|
||||
}
|
||||
?>
|
||||
<!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($title); ?></title>
|
||||
<link rel="stylesheet" href="<?php echo $css_path; ?>">
|
||||
<style>
|
||||
/* 文档系统额外样式 */
|
||||
.doc-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
.doc-list li {
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.doc-list a {
|
||||
font-size: 16px;
|
||||
color: #0000ee;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.doc-desc {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
margin-top: 4px;
|
||||
display: block;
|
||||
}
|
||||
.sidebar-loading {
|
||||
color: #999;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layout">
|
||||
<nav class="sidebar">
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-title">Oraset</div>
|
||||
<ul>
|
||||
<li><a href="../index.php">首页</a></li>
|
||||
<li><a href="../download.php">下载</a></li>
|
||||
<li><a href="../releases.php">历史版本</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sidebar-section">
|
||||
<div class="sidebar-section-title">文档</div>
|
||||
<ul>
|
||||
<li><a href="?list" id="nav-list"<?php echo $show_list ? ' class="active"' : ''; ?>>文档列表</a></li>
|
||||
</ul>
|
||||
<ul id="doc-nav-list">
|
||||
<li><span class="sidebar-loading">加载中...</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="main">
|
||||
<?php echo $html_content; ?>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 获取当前文档名
|
||||
var currentDoc = '<?php echo htmlspecialchars($doc); ?>';
|
||||
var showList = <?php echo $show_list ? 'true' : 'false'; ?>;
|
||||
|
||||
// 加载文档列表
|
||||
fetch('./api.php')
|
||||
.then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(function(data) {
|
||||
var navList = document.getElementById('doc-nav-list');
|
||||
navList.innerHTML = '';
|
||||
|
||||
if (data.articles && data.articles.length > 0) {
|
||||
data.articles.forEach(function(article) {
|
||||
var li = document.createElement('li');
|
||||
var a = document.createElement('a');
|
||||
a.href = './?doc=' + article.name;
|
||||
a.textContent = article.title;
|
||||
|
||||
if (!showList && article.name === currentDoc) {
|
||||
a.className = 'active';
|
||||
}
|
||||
|
||||
li.appendChild(a);
|
||||
navList.appendChild(li);
|
||||
});
|
||||
} else {
|
||||
navList.innerHTML = '<li><span class="sidebar-loading">暂无文档</span></li>';
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error('Error loading document list:', error);
|
||||
document.getElementById('doc-nav-list').innerHTML = '<li><span class="sidebar-loading">加载失败</span></li>';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user