PHP MD.Viewer

Оглавление
  1. 1. Быстрый старт
  2. 2. Описание и назначение
  3. 3. Требования
  4. 4. Установка
  5. 5. Структура файлов
  6. 6. Использование
  7. 7. Возможности
  8. 8. Настройка констант
  9. 9. Безопасность
  10. 10. Синтаксис Markdown

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+)
  • Веб-сервер: ApacheNginx или 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 Ручная установка

  1. Скачайте архив с GitHub Releases
  2. Распакуйте в директорию веб-сервера
  3. Убедитесь, что 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

![Альтернативный текст](https://example.com/image.png "Подпись")
  • Атрибуты loading="lazy" и decoding="async" добавляются автоматически
  • При ошибке загрузки изображение скрывается, показывается текстовый fallback
  • Включаются константой FEATURE_IMAGES = true

7.10 Тёмная тема

Переключатель тёмной/светлой темы расположен в хедере страницы. Выбор сохраняется в localStorage и восстанавливается при следующем открытии. Цветовая схема применяется через CSS-атрибут data-theme на <html>.

7.11 Адаптивная ширина контента

В режиме просмотрщика доступны три ширины контентной колонки:

РежимШиринаНазначение
Reading72chОптимально для чтения длинных текстов
Article90chДокументация с кодом
Wide120chШирокие таблицы и диаграммы

Выбор сохраняется в 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=:

  1. Проверка длины параметра (лимит MAX_FILE_PARAM_LENGTH)
  2. Блокировка нулевых байтов (\0)
  3. Отклонение управляющих символов (ASCII 0–31, 127, backspace)
  4. URL-декодирование и повторная проверка (защита от %2e%2e%2f)
  5. Отклонение абсолютных путей (Unix /, Windows C:\, UNC \\)
  6. Нормализация разделителей и отклонение path traversal (../)
  7. Строгий whitelist символов (только A-Za-z0-9._-/)
  8. Ограничение глубины директорий (MAX_SCAN_DEPTH)
  9. Разрешение только .md-файлов (без учёта регистра)
  10. Разрешение realpath для базовой директории
  11. Разрешение realpath для целевого файла
  12. Проверка принадлежности целевого файла базовой директории
  13. Проверка, что файл является обычным файлом (не директорией, не устройством)
  14. Повторная проверка расширения после разрешения симлинков

Операции 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 "Подпись")
![Alt текст](https://example.com/img.png)
![Alt текст](https://example.com/img.png "Подпись к картинке")

10.4 Списки

MARKDOWNCopy

- Маркированный пункт
- Ещё один пункт

1. Нумерованный пункт
2. Ещё один

- [x] Выполненная задача    (FEATURE_TASK_LISTS)
- [ ] Невыполненная задача  (FEATURE_TASK_LISTS)

10.5 Цитаты

MARKDOWNCopy

> Это цитата.
> Продолжение цитаты.

10.6 Горизонтальные разделители

MARKDOWNCopy

---
***
___

10.7 Ссылки-сноски на источники

MARKDOWNCopy

Текст документа со ссылкой [1,2] на источники.


Добавить комментарий

Разработка и продвижение сайтов webseed.ru
Прокрутить вверх