1. Быстрый старт
BASHCopy
# 1. Клонируйте репозиторий в директорию веб-сервера
git clone https://github.com/paulmann/MD.Viewer.git /var/www/html/docs
# 2. Создайте Markdown-файл рядом со скриптом
cp /var/www/html/docs/index.md.example /var/www/html/docs/index.md
# 3. Откройте в браузере
# https://your-domain.com/docs/
Минимальный вариант: положите
index.phpиindex.mdв одну директорию, откройтеindex.phpв браузере — MD.Viewer автоматически найдёт и отобразитindex.md.
2. Описание и назначение
2.1 Проблематика
Стандартный способ хранить техническую документацию — Markdown-файлы в репозитории. Однако их сырой вид неудобен для конечных пользователей: нет навигации, нет нумерации, нет красивого форматирования. Существующие решения либо требуют сложной инфраструктуры (Node.js, генераторы статических сайтов), либо зависят от внешних SaaS-платформ.
MD.Viewer решает эту задачу радикально просто: один PHP-файл превращает любой Markdown-файл в профессиональную HTML-страницу без зависимостей, без базы данных и без сборочного процесса.
2.2 Для кого подходит
- Разработчики, публикующие техническую документацию на собственном сервере
- Команды, использующие внутренние вики на базе Markdown
- DevOps-инженеры, которым нужен быстрый просмотр README и runbook’ов
- Авторы технических статей и инструкций
- Все, кто хочет красиво отображать
.md-файлы без тяжёлых фреймворков
2.3 Варианты применения
| Сценарий | Описание |
|---|---|
| Документация проекта | Положите index.md рядом со скриптом — получите красивую страницу документации |
| Файловый браузер | Откройте директорию без .md-файла — получите сортируемый список всех .md-файлов |
| Мультифайловая документация | Передавайте ?file=path/to/doc.md для навигации между файлами |
| Внутренняя вики | Разместите набор .md-файлов и скрипт на внутреннем сервере |
| Самохостируемый блог | Каждый пост — отдельный .md-файл, скрипт с именем поста автоматически его находит |
3. Требования
- PHP 8.0 или выше (рекомендуется 8.2+)
- Веб-сервер: Apache, Nginx или PHP built-in server
- Расширения PHP:
mbstring(стандартно включено в большинстве дистрибутивов) - Доступ к интернету на стороне браузера (CDN для Tailwind CSS, Google Fonts, Mermaid)
Оффлайн-режим: если доступ к CDN недоступен, замените ссылки на локальные копии библиотек в
<head>скрипта.
4. Установка
4.1 Через Git
BASHCopy
git clone https://github.com/paulmann/MD.Viewer.git
cd MD.Viewer
4.2 Ручная установка
- Скачайте архив с GitHub Releases
- Распакуйте в директорию веб-сервера
- Убедитесь, что
index.phpдоступен через браузер
4.3 PHP встроенный сервер (для разработки)
BASHCopy
cd /path/to/MD.Viewer
php -S localhost:8080
# Откройте http://localhost:8080
4.4 Apache
Стандартная конфигурация .htaccess не требуется. Убедитесь, что mod_php или php-fpm подключены и директория доступна для чтения.
4.5 Nginx
NGINXCopy
server {
listen 80;
server_name docs.example.com;
root /var/www/html/docs;
index index.php;
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
5. Структура файлов
CODECopy
MD.Viewer/
├── index.php # Основной скрипт (весь рендеринг)
├── index.md # Ваш Markdown-файл (по умолчанию)
├── assets/
│ ├── css/
│ │ └── md.css # Дополнительные стили
│ └── js/
│ └── md.js # JavaScript: темы, ширина, копирование, Mermaid lazy-load
├── LICENSE
└── README.md
Скрипт автоматически ищет
.md-файл с тем же именем, что и PHP-скрипт. Если скрипт называетсяdocs.php— он ищетdocs.md. Это позволяет размещать несколько независимых просмотрщиков в одной директории.
6. Использование
6.1 Режим просмотрщика
Когда рядом со скриптом или в директории найден .md-файл, скрипт переходит в режим viewer:
- Рендерится заголовок страницы (
<h1>первого заголовка из Markdown) - Выводится мета-описание (первый абзац)
- Формируется автоматическое содержание (TOC)
- Рендерится весь Markdown в красивый HTML
6.2 Режим файлового браузера
Если ни один .md-файл не найден, скрипт переходит в режим browser:
- Рекурсивно сканируется текущая директория
- Отображается таблица с колонками: File, Dir, Created, Modified, Size
- Все колонки кликабельны для сортировки
- Встроенный поиск с debounce по имени файла и директории
- Клик по строке открывает файл в новой вкладке
6.3 URL-параметры
| Параметр | Описание | Пример |
|---|---|---|
?file=path/to/doc.md | Открыть конкретный файл | ?file=docs/api.md |
Путь должен быть относительным и указывать на файл внутри директории скрипта. Абсолютные пути, path traversal (../), нулевые байты и управляющие символы отклоняются.
7. Возможности
7.1 Автоматическое содержание
MD.Viewer автоматически собирает все заголовки ##–###### и строит навигационное содержание перед телом статьи. TOC:
- Отображает иерархию заголовков с отступами
- Генерирует якорные ссылки (
slug) из текста заголовка - Поддерживает дублирующиеся заголовки (добавляет суффикс
-2,-3и т.д.) - Включается/выключается константой
AUTO_TOC
PHPCopy
const AUTO_TOC = true; // Включить автоматическое содержание
7.2 Нумерация заголовков
Все заголовки автоматически нумеруются в формате 1., 1.1., 1.1.1. и т.д. Скрипт умно определяет ручную нумерацию (например, 1. Раздел) и не дублирует номера.
PHPCopy
const AUTO_NUMBERING = true; // Включить нумерацию заголовков
Тонкость: ручная нумерация в стиле
1. Заголовок,1.1 Подраздел,I. Введениедетектируется автоматически — автонумерация для таких заголовков пропускается, но счётчик не сбивается для последующих ненумерованных заголовков.
7.3 Диаграммы Mermaid
Блоки кода с указанием языка `mermaid или `mmd рендерятся как интерактивные диаграммы Mermaid.
graph TD A[Клиент] --> B[MD.Viewer] B --> C[Markdown-файл] B --> D[HTML-страница]
Библиотека Mermaid загружается лениво — только если на странице есть хотя бы одна диаграмма. Страницы без диаграмм не загружают Mermaid CDN вообще, что ускоряет их открытие.
7.4 Блоки кода с копированием
Все блоки кода оформляются в editor-стиле:
- Шапка с «traffic-light» кнопками (macOS-стиль) и меткой языка
- Кнопка Copy — копирует содержимое в буфер обмена
- После копирования кнопка меняется на Copied! с зелёной галкой
- Поддерживается подсветка синтаксиса через CSS-классы
language-*
7.5 Таблицы
Стандартный синтаксис GFM-таблиц с поддержкой выравнивания:
MARKDOWNCopy
| Левый | Центр | Правый |
|:------|:-----:|-------:|
| Ячейка | Ячейка | Ячейка |
Таблицы оформляются с горизонтальной прокруткой на мобильных устройствах.
7.6 Сноски и ссылки-источники
Источники — особый синтаксис MD.Viewer для нумерованных ссылок на источники в конце документа:
MARKDOWNCopy
Текст с ссылкой на источник [1] и ещё один источник [2].
Ссылки рендерятся как надстрочные цифры со ссылкой, в конце документа добавляется список источников.
Сноски — стандартный синтаксис footnotes:
MARKDOWNCopy
Текст с примечанием.[^1]
Включаются константой FEATURE_FOOTNOTES = true.
7.7 Задачи (task lists)
MARKDOWNCopy
- [x] Выполненная задача
- [ ] Невыполненная задача
Рендерятся как отключённые чекбоксы (только для чтения). Включаются константой FEATURE_TASK_LISTS = true.
7.8 Эмодзи
Текстовые коды эмодзи заменяются на Unicode-символы:
MARKDOWNCopy
:check: задача выполнена
:warning: внимание
:rocket: запуск
:bulb: идея
Поддерживаемые коды: :smile:, :joy:, :heart:, :thumbsup:, :thumbsdown:, :warning:, :error:, :check:, :x:, :star:, :fire:, :bulb:, :rocket:, :link:, :info:.
Включаются константой FEATURE_EMOJI = true.
7.9 Изображения
MARKDOWNCopy

- Атрибуты
loading="lazy"иdecoding="async"добавляются автоматически - При ошибке загрузки изображение скрывается, показывается текстовый fallback
- Включаются константой
FEATURE_IMAGES = true
7.10 Тёмная тема
Переключатель тёмной/светлой темы расположен в хедере страницы. Выбор сохраняется в localStorage и восстанавливается при следующем открытии. Цветовая схема применяется через CSS-атрибут data-theme на <html>.
7.11 Адаптивная ширина контента
В режиме просмотрщика доступны три ширины контентной колонки:
| Режим | Ширина | Назначение |
|---|---|---|
| Reading | 72ch | Оптимально для чтения длинных текстов |
| Article | 90ch | Документация с кодом |
| Wide | 120ch | Широкие таблицы и диаграммы |
Выбор сохраняется в localStorage.
7.12 Универсальные паттерны
MD.Viewer поддерживает визуализацию узлов, связей и паттернов прямо в инлайн-тексте при помощи специального синтаксиса:
MARKDOWNCopy
`(Узел A)--[связь]->(Узел B){заметка}`
Включаются константой UNIVERSAL_PATTERNS = true и CYPHER_PATTERNS = true.
8. Настройка констант
Все настройки расположены в начале файла index.php в блоке Feature toggles.
8.1 Функциональные переключатели
PHPCopy
const AUTO_NUMBERING = true; // Автонумерация заголовков
const AUTO_TOC = true; // Автоматическое содержание
const AUTO_FOOTNOTES_LINKS = true; // Список источников в конце страницы
const DOUBLE_LINE_BREAKS = true; // Двойной перенос строки как <br>
const CYPHER_PATTERNS = true; // Визуализация Cypher/graph-паттернов
const UNIVERSAL_PATTERNS = true; // Визуализация универсальных паттернов
const FEATURE_IMAGES = true; // Рендеринг изображений
const FEATURE_REF_LINKS = true; // Reference links [label][ref]
const FEATURE_TASK_LISTS = true; // Списки задач с чекбоксами
const FEATURE_FOOTNOTES = true; // Сноски [^1]
const FEATURE_SUB_SUP = true; // Подстрочный~текст~ и надстрочный^текст^
const FEATURE_EMOJI = true; // Замена текстовых кодов эмодзи
8.2 Лимиты безопасности
PHPCopy
const MAX_FILE_PARAM_LENGTH = 255; // Максимальная длина параметра ?file=
const MAX_SCAN_DEPTH = 3; // Максимальная глубина рекурсии при сканировании
const MAX_FILES_SCAN = 10000; // Максимальное количество файлов при сканировании
Рекомендация: уменьшите
MAX_SCAN_DEPTHиMAX_FILES_SCANна серверах с большим количеством файлов, чтобы избежать замедления файлового браузера.
8.3 Стиль переносов строк
PHPCopy
const PARAGRAPH_BREAK_STYLE = 'double-br'; // Варианты: 'double-br', 'paragraph', 'space', 'nbsp'
| Значение | Поведение |
|---|---|
double-br | Двойной перенос строки → <br><br> |
paragraph | Двойной перенос → новый <p> с отступом |
space | Двойной перенос → пробел |
nbsp | Двойной перенос → неразрывный пробел |
9. Безопасность
MD.Viewer реализует 14-уровневую защиту параметра ?file=:
- Проверка длины параметра (лимит
MAX_FILE_PARAM_LENGTH) - Блокировка нулевых байтов (
\0) - Отклонение управляющих символов (ASCII 0–31, 127, backspace)
- URL-декодирование и повторная проверка (защита от
%2e%2e%2f) - Отклонение абсолютных путей (Unix
/, WindowsC:\, UNC\\) - Нормализация разделителей и отклонение path traversal (
../) - Строгий whitelist символов (только
A-Za-z0-9._-/) - Ограничение глубины директорий (
MAX_SCAN_DEPTH) - Разрешение только
.md-файлов (без учёта регистра) - Разрешение
realpathдля базовой директории - Разрешение
realpathдля целевого файла - Проверка принадлежности целевого файла базовой директории
- Проверка, что файл является обычным файлом (не директорией, не устройством)
- Повторная проверка расширения после разрешения симлинков
Операции POST игнорируются — скрипт обрабатывает только GET.
10. Синтаксис Markdown
10.1 Заголовки
MARKDOWNCopy
# Заголовок 1 уровня
## Заголовок 2 уровня
### Заголовок 3 уровня
#### Заголовок 4 уровня
##### Заголовок 5 уровня
###### Заголовок 6 уровня
Альтернативный синтаксис (Setext):
Заголовок 1
===========
Заголовок 2
-----------
10.2 Форматирование текста
MARKDOWNCopy
**Жирный текст**
__Тоже жирный__
*Курсив*
_Тоже курсив_
~~Зачёркнутый~~
==Выделенный (highlight)==
~Подстрочный~ (FEATURE_SUB_SUP)
^Надстрочный^ (FEATURE_SUB_SUP)
`inline код`
10.3 Ссылки и изображения
MARKDOWNCopy
[Текст ссылки](https://example.com)
[Ссылка с подписью](https://example.com "Подпись")


10.4 Списки
MARKDOWNCopy
- Маркированный пункт
- Ещё один пункт
1. Нумерованный пункт
2. Ещё один
- [x] Выполненная задача (FEATURE_TASK_LISTS)
- [ ] Невыполненная задача (FEATURE_TASK_LISTS)
10.5 Цитаты
MARKDOWNCopy
> Это цитата.
> Продолжение цитаты.
10.6 Горизонтальные разделители
MARKDOWNCopy
---
***
___
10.7 Ссылки-сноски на источники
MARKDOWNCopy
Текст документа со ссылкой [1,2] на источники.