# 简单文档 > 面向 Emlog 博客的 Markdown 文档站插件:将 Markdown 文档**动态解析渲染**为 HTML 文档页,不生成任何静态 HTML 文件。 | 项目 | 说明 | | --- | --- | | 插件名称 | 简单文档(目录名 `lcbk_doc`) | | 当前版本 | 1.0.3 | | 作者 | LAO.CHEN | | 适用平台 | Emlog(PHP 博客系统) | | 插件发布页 | https://www.emlog.net/plugin/detail/1259 | | 作者主页 | https://www.emlog.net/profiles/f065546a | | 数据表前缀 | `DB_PREFIX . 'lcbk_doc'` 系列 | ## 插件简介 简单文档(`lcbk_doc`)让你可以直接在 Emlog 后台用 **Markdown 写文档**,前台自动渲染成带目录、可搜索、可挂附件的文档页面。核心设计目标是"简单": - 文档以 Markdown 原文入库,访问时动态解析渲染,**全程不生成静态 HTML**,升级、改版零负担; - 基于 H2 / H3 标题**自动生成两级目录(TOC)**,标题文字即页内锚点; - 支持**栏目分类**浏览、**站内搜索**、**代码块复制与轻量着色**; - 支持 zip / pdf / office 等**附件上传、下载与浏览器内预览**,并记录下载日志; - 内置防 XSS 的 HTML 白名单净化、附件目录脚本防护、下载防盗链与断点续传。 安装启用后,前台会自动获得一个独立于博客正文的文档栏目入口,适合存放产品手册、开发文档、使用说明、帮助中心等。 ## 功能特性 ### 文档与渲染 - **Markdown 渲染引擎**:内置自包含的 Parsedown + ParsedownExtra(类名已重命名避免与主题或其他插件冲突),支持表格、任务列表、围栏代码块、脚注、删除线、自动链接等扩展语法。 - **纯动态渲染**:文档每次请求时实时解析,**不生成、不缓存静态 HTML 文件**,正文与目录以 JSON 文件缓存于插件 `cache` 目录,缓存 key 由文档 ID 与正文内容哈希决定,内容一改自然失效。 - **自动两级目录**:按 Markdown 的 H2 / H3 标题生成"章节 + 子项"目录;正文侧栏跟随滚动高亮(IntersectionObserver 实现,无依赖),移动端收进可开关的"目录"按钮。 - **中文标题锚点**:锚点优先取标题文字生成的 slug 且**保留中文**,例如 `## 安装` 会生成 `id="安装"`,正文可用 `[点击](#安装)` 直接页内跳转;纯符号 / 表情标题或重名标题自动回退 / 追加 `-1` `-2` 序号,保证 id 唯一。 - **自动摘要**:从正文首行提取纯文本摘要(自动跳过标题、列表、引用、代码块、图片等),用于首页卡片与 ``。 - **代码块增强**:每个围栏代码块自动添加语言标识条与"复制"按钮,并按语言族做**零依赖的轻量着色**(支持 PHP / JS / Python / Bash / SQL / C 系 / HTML / CSS 等),不支持的语言也有通用关键字高亮。 - **防 XSS 净化**:渲染结果先过 HTML 白名单净化——有 DOM 扩展时走 DOMDocument 逐标签白名单(仅放行安全属性与 `http/https/mailto/data:image/*` 协议),无 DOM 扩展时回退正则过滤,删 `script`、`on*` 事件与 `javascript:` 伪协议。 ### 站点与浏览 - **栏目分类**:后台可新增 / 重命名 / 排序栏目,前台首页顶部出现"全部 / 各栏目"导航并可点击筛选;删除栏目不删文档,文档自动归入"未分类"。 - **站内搜索**:首页搜索框按文档标题与正文检索,结果、分页与栏目筛选互相保留。 - **首页卡片栅格**:每页 9 篇,卡片展示标题、自动摘要、更新时间、附件数与阅读量。 - **阅读统计**:文档详情自动累计阅读量。 - **上一篇 / 下一篇**:详情页底部按排序规则自动衔接,可关联阅读。 ### 附件与下载日志 - **附件上传**:为文档挂多个附件,后端做扩展名白名单 + 危险类型黑名单双重校验,存放到独立的 `files` 目录并以随机名落盘。 - **浏览器内预览**:PDF、常见图片、音视频、纯文本 / Markdown 等类型提供"预览"入口(inline 输出,不计数);SVG 因可承载脚本**一律按下载处理**。 - **下载与统计**:强制附件方式输出并记录下载日志(附件名、文档、IP、UA、时间),单个附件累计下载数;后台"下载日志"标签可按文档筛选、一键清空。 - **断点续传**:附件输出完整支持 HTTP Range(`206 Partial Content`),大文件下载与视频拖动进度友好;`HEAD` 请求只回响应头不计数。 - **防盗链开关**:开启后仅放行来自本站页面、同源(含子域)或(可选)空 Referer 直连的请求,拦截跨站盗链。 ### 后台与主题 - **明暗主题**:前台默认跟随系统 `prefers-color-scheme`,右上角可手动切换,选择保存在 localStorage;CSS 全部收敛于 `css/jc-doc.css`,样式为浅色 / 深色双套变量,未引入任何第三方前端库。 - **SEO 增强**:页面输出 ``、`description`、`canonical`、Open Graph、Twitter Card,文档详情页附带 `Article` 类型的 JSON-LD 结构化数据。 - **绿色卸载**:插件删除回调会**清理全部数据表与配置**(附件物理文件随插件目录删除),不留残留数据。 ## 安装与启用 1. 在 Emlog 后台 **插件 → 插件管理 → 上传插件**,上传后插件目录为 `content/plugins/lcbk_doc/`(或手动将本目录解压放置到该路径)。 2. 启用插件。启用回调会**自动创建 4 张数据表**并写入默认配置,无需手动建表。 3. 进入插件设置页进行站点信息配置,并开始新增文档。 > 从旧版本覆盖升级时,即使未重新启用插件也不会缺列:回调里带增量迁移(补 `log.doc_id` 索引、`doc.cat_id` 列),前台 / 后台每次请求开头还会做一次幂等的运行时结构补齐(`lcbk_doc_ensure_schema`),无权限 ALTER 时静默降级不报错。 ## 前台访问地址 插件前台是一个独立页面,地址根据 Emlog 是否开启伪静态自动适配: - **开启伪静态**(推荐,地址更友好): `https://yourdomain/plugin/lcbk_doc` - **未开启伪静态**: `https://yourdomain/?plugin=lcbk_doc` 若前台 404,请检查 Emlog 后台 **系统 → 设置 → SEO** 中的伪静态配置。 ### 路由规则 | 路由 | 伪静态地址 | 兼容参数地址 | 说明 | | --- | --- | --- | --- | | 文档首页 / 全部 | `/plugin/lcbk_doc` | `?plugin=lcbk_doc` | 首页、栏目导航、搜索、分页 | | 栏目筛选 | `/plugin/lcbk_doc/cat/{id}` | `?plugin=lcbk_doc&cat={id}` | 按栏目过滤(搜索/分页保留) | | 文档详情 | `/plugin/lcbk_doc/doc/{id}` | `?plugin=lcbk_doc&doc={id}` | 正文 + 目录 + 附件 | | 附件下载 | `/plugin/lcbk_doc/download/{id}` | `?plugin=lcbk_doc&download={id}` | 强制下载并记日志 | | 附件预览 | `/plugin/lcbk_doc/preview/{id}` | `?plugin=lcbk_doc&preview={id}` | 浏览器内联输出,不计数 | | 站内搜索 | `/plugin/lcbk_doc?q=关键词` | `?plugin=lcbk_doc&q=关键词` | 标题 / 正文检索 | ## 后台使用指南 后台入口:`https://yourdomain/admin/plugin.php?plugin=lcbk_doc`(仅管理员可见),共 4 个标签页: ### 1. 基础设置(basic) | 配置项 | 说明 | | --- | --- | | 站点名称 | 文档站品牌名,显示于页头与首页 Hero 区,长度 60 | | 副标题 | 首页副标语,同时作为默认页面描述,长度 200 | | 站点简介 | 首页 Hero 大段介绍,支持换行,长度 1000 | | 显示目录 | 开关详情页基于 H2 / H3 的两级目录 | | 允许上传类型 | 附件扩展名白名单,逗号 / 空格分隔,默认 `zip,rar,7z,pdf,doc,docx,xls,xlsx,ppt,pptx,txt,md,csv,apk,mp3,mp4` | | 下载防盗链 | 开启后附件仅允许从本站页面访问 | | 允许直接访问 | 开启后空 Referer(如直接粘贴链接、下载工具)也能下载 | | 日志保留天数 | 下载日志自动保留时长,范围 0–3650(0 为不清理) | ### 2. 文档管理(docs) - 左侧为文档列表(标题、栏目、更新时间、阅读 / 附件数、可见状态),支持排序(数字越小越靠前)与**前台可见**开关。 - 新增 / 编辑文档需填写:标题(必填)、排序、所属栏目、前台可见、简介,以及核心的 **Markdown 内容**。 - Markdown 编辑框提供**导入 `.md` 文件**与**在线草稿预览**两种辅助能力:导入即把本地 Markdown 文件内容读入编辑框;预览在编辑页实时渲染查看效果(正式效果以保存后的前台为准)。 - 删除文档会**级联删除其全部附件(含物理文件)、下载日志与渲染缓存**。 ### 3. 栏目管理(cats) 新增 / 重命名 / 排序 / 删除栏目。建好栏目后回到"文档管理"为文档选择栏目,前台首页即出现栏目导航。 ### 4. 下载日志(logs) 展示最近下载记录(时间、附件名、所属文档、IP、UA),可按文档筛选,支持一键清空。 ## Markdown 写作约定 - **目录**:正文中直接使用 `##` 与 `###`,渲染后自动进入两级目录;`###` 归属其上方最近的 `##`。没有目录开关时侧栏自动隐藏。 - **页内跳转**:标题文字即锚点(保留中文),正文可写 `[点击跳转](#标题文字)`;也可用传统 `#anchor` 方式引用其它标题生成的中文锚点。 - **代码块**:用 ```加语言名(如 ` ```php `、` ```python `)即可获得语言标识、复制按钮与轻量着色。 - **HTML 混排**:支持在 Markdown 中嵌入原生 HTML,但仅白名单标签与属性会被保留,脚本类内容一律被剥离(有 DOM 扩展时;无 DOM 扩展时按纯文本转义,避免渲染异常)。 - **图片**:支持外链图片,也允许 `data:image/png;base64` 内嵌小图。 ## 附件支持范围 - **上传上限**:插件硬上限 200MB,同时受 PHP `upload_max_filesize`、`post_max_size` 约束(取三者最小值);超大附件请先在后台调整服务器 PHP 配置。 - **预览类型**(浏览器内联):`pdf` `jpg` `jpeg` `png` `gif` `webp` `mp3` `mp4` `webm` `ogg` `txt` `md`,同时提供"预览"与"下载"两个入口。 - **仅下载类型**:`zip` `rar` `7z` `tar` `gz` `doc` `docx` `xls` `xlsx` `ppt` `pptx` `csv` `apk` `ipa` 等。 - **存储安全**:文件写入 `content/plugins/lcbk_doc/files/`,目录内 `.htaccess` 禁止列目录,并对 php / phtml / phar / cgi / py / sh 等脚本扩展名**拒绝执行**(Apache 2.2 / 2.4 均覆盖),上传落盘文件名随机化,杜绝可执行文件落地。 ## 目录结构 ```text lcbk_doc/ ├── lcbk_doc.php 插件主文件:版本与常量、加载各库 ├── lcbk_doc_callback.php 启用/更新/删除回调:建表、迁移、种子配置、卸载清理 ├── lcbk_doc_setting.php 后台设置页:4 个标签页 + POST 处理 + 附件上传 ├── lcbk_doc_show.php 前台入口:路由分发(首页/文档/下载/预览) ├── css/ │ └── jc-doc.css 前台样式(浅色/深色双主题变量,无第三方依赖) ├── files/ 附件上传目录(含 .htaccess 防护) ├── cache/ 渲染结果 JSON 缓存目录(运行时自动创建) └── lib/ ├── Parsedown.php Markdown 解析器(内置副本) ├── ParsedownExtra.php Markdown Extra 扩展解析器 ├── lcbk_doc_kit.php 公共工具:配置读写、URL 生成、路由解析、输入过滤、扩展名校验、Range 解析、防盗链 ├── lcbk_doc_md.php Markdown 渲染入口:锚点/TOC 注入、HTML 净化、纯文本摘要、渲染缓存 ├── lcbk_doc_store.php 数据访问层:栏目、文档、附件、下载日志的增删改查 └── lcbk_doc_view.php 前台页面渲染、代码块交互脚本、附件下载/预览流式输出 ``` ## 数据表结构 全部表使用 `utf8mb4_unicode_ci`,表名前缀为 Emlog 的 `DB_PREFIX`(默认 `emlog_`)。 ### 栏目表 `{prefix}lcbk_doc_cat`(v1.0.2 新增) | 字段 | 类型 | 说明 | | --- | --- | --- | | id | INT UNSIGNED 自增 | 主键 | | name | VARCHAR(80) | 栏目名 | | sort_order | INT | 排序(小者靠前) | ### 文档表 `{prefix}lcbk_doc` | 字段 | 类型 | 说明 | | --- | --- | --- | | id | INT UNSIGNED 自增 | 主键 | | title | VARCHAR(255) | 标题 | | intro | VARCHAR(1000) | 简介(摘要) | | md_content | LONGTEXT | Markdown 原文 | | sort_order | INT | 排序(小者靠前) | | cat_id | INT UNSIGNED | 所属栏目,0 为未分类(v1.0.2 新增,带索引) | | hide | ENUM('n','y') | 前台可见性 | | views | INT UNSIGNED | 阅读数 | | addtime / updtime | INT UNSIGNED | 添加 / 更新时间戳 | ### 附件表 `{prefix}lcbk_doc_attach` | 字段 | 类型 | 说明 | | --- | --- | --- | | id | INT UNSIGNED 自增 | 主键 | | doc_id | INT UNSIGNED | 所属文档(带索引) | | name | VARCHAR(255) | 展示用原始文件名 | | file | VARCHAR(255) | 落盘文件名 | | ext | VARCHAR(20) | 扩展名(小写) | | size | BIGINT UNSIGNED | 字节数 | | downloads | INT UNSIGNED | 累计下载次数 | | addtime | INT UNSIGNED | 上传时间戳 | ### 下载日志表 `{prefix}lcbk_doc_log` | 字段 | 类型 | 说明 | | --- | --- | --- | | id | BIGINT UNSIGNED 自增 | 主键 | | doc_id | INT UNSIGNED | 所属文档(带索引,用于筛选与级联删除) | | attach_id | INT UNSIGNED | 附件(带索引) | | name | VARCHAR(255) | 附件名快照 | | ip | VARCHAR(45) | 访客 IP(兼容 IPv6) | | ua | VARCHAR(255) | User-Agent | | addtime | INT UNSIGNED | 下载时间戳 | ## 安全设计摘要 - **双保险扩展名校验**:上传与输出环节同时校验白名单 + 危险脚本扩展名黑名单,即使后台白名单被改动,脚本文件也无法经插件下发。 - **HTML 白名单净化**:DOM 逐标签清理未知标签(剥壳留文本)、剥离 `on*` 事件属性、封禁 `javascript:` 伪协议;`class` 仅保留代码高亮所需的 `language-*`。 - **防注入**:所有 SQL 均经 `intval` / `Database::escape_string`;前台标题、内容、URL 一律 `htmlspecialchars` 输出。 - **附件目录防护**:`files/.htaccess` 禁目录列表 + 禁脚本执行 + 落盘随机名。 - **缓存安全**:渲染缓存 JSON 只做纯文本读取,绝不 include / eval;缓存 key 绑定内容哈希,正文变化自然失效,删除文档时清理对应文件。 - **下载输出安全**:清空输出缓冲后再流式输出二进制,避免页面污染;`Content-Disposition` 同时给出 ASCII 与 RFC 5987 编码文件名,兼容中文文件名下载。 ## 常见问题 **Q1:前台访问提示 404?** 确认 Emlog 是否开启伪静态。开启后地址为 `/plugin/lcbk_doc`;未开启用 `?plugin=lcbk_doc`。仍不行请检查 `系统 → 设置 → SEO` 的伪静态规则是否生效。 **Q2:文档里有表格 / 复杂 HTML,为什么显示成纯文本或变样?** Markdown 中嵌入的原生 HTML 需要 PHP 的 `DOMDocument` 扩展解析(白名单净化);缺 DOM 扩展时会按纯文本转义处理。建议装好 `dom` 扩展(同时强烈建议启用 `mbstring`),可获得完整渲染体验。 **Q3:大附件上传失败?** 先确认未超过 200MB 插件硬上限,再检查服务器 `upload_max_filesize` 与 `post_max_size`(需大于附件大小,必要时同步调大 `max_execution_time`)。 **Q4:下载的中文文件名乱码?** 已按标准做法同时输出 `filename` 与 `filename*=UTF-8''`,现代浏览器正常;个别老旧下载工具可能退化,可改后端附件名为 ASCII 后上传。 **Q5:会不会生成一堆静态文件拖慢站点?** 不会。插件是纯动态渲染,只在 `cache/` 写少量 JSON 渲染缓存(正文不变即命中,正文一改自动失效),不产生任何静态 HTML。 **Q6:删除插件会留残留数据吗?** 删除插件时回调会删除全部 4 张数据表与 Storage 配置;插件目录(含附件)由 Emlog 一并清理。建议删除前确认不再需要已有文档与附件。 ## 更新日志 ### v1.0.3 **新增** - 后台文档列表分页(每页 30) - 后台写操作加入 CSRF 校验 **修复** - 断点续传/流媒体重复计数下载 - 上/下篇无法跨栏目串联 - 阅读数刷新重复累加 - 搜索 `%` `_` 被当通配符 **安全** - 扩充禁止上传扩展名黑名单 - 收紧 `files/.htaccess` 脚本拦截 - 附件输出加 `nosniff` 头 ### v1.0.2 - 新增文档分类/栏目 - 新增代码块,高亮/一键复制 - 新增站内搜索 - 优化文档「上一篇 / 下一篇」仅在当前栏目内相邻,栏目切换后导航不串栏目。 - 修复若干渲染细节 ### v1.0.1 - 优化标题锚点 - 新增文档详情页底部上一篇 / 下一篇 - 新增返回顶部 - 优化返回文档列表移至页面顶部面包屑右侧 ### 1.0.0 - 首发版本 ## 许可说明 插件作者为 LAO.CHEN,通过 Emlog 官方插件市场分发。使用前请阅读 Emlog 插件分发页相关条款,本文件仅作使用说明。