- med_diag_json_error() — ошибки в формате {'error': '...'} (WP_REST_Response)
- 4 проверки лимита 100 МБ (CONTENT_LENGTH, UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE, size)
- Проверка расширения файла (mp4/avi/mov/mkv/webm/m4v)
- Имя файла только ASCII (med-diag-upload.ext) — защита multipart
- filename скачивания из Content-Disposition бэкенда
- Овал .med-scan-oval (inset 12%, затемнение вне зоны)
- escapeHtml() + parseJson() — безопасная обработка ответов (XSS, HTML-ошибки)
- README: nginx лимиты, таблица ошибок
Med Diagnostics — WordPress-плагин
Репозиторий: https://git.itguild.info/apuc/sber-med-wordpress
Интеграция сервиса «Диагностика по видео» (API-бэкенд med.my-dpr.ru) в WordPress. Плагин выводит вёрстку сервиса (загрузка видео, сканирование с камеры, результат) прямо на странице сайта — без iframe.
Установка
Вариант 1: через админку (zip)
# из корня репозитория (папка репозитория = папка плагина)
zip -r med-diagnostics.zip . -x README.md
- В админке WordPress: Плагины → Добавить новый → Загрузить плагин → выберите
med-diagnostics.zip→ Установить → Активировать.
Вариант 2: копированием файлов
- Скопируйте содержимое репозитория в
wp-content/plugins/med-diagnostics/вашего WordPress. - В админке: Плагины → Установленные → активируйте Med Diagnostics.
Использование
Вставьте шорткод в нужную страницу/запись:
[med_diagnostics]
Дополнительно можно задать заголовок:
[med_diagnostics title="Проверь своё здоровье"]
Настройки
Настройки → Med Diagnostics:
| Поле | Описание |
|---|---|
| Режим подключения | Через сервер (внутренний IP) — браузер шлёт видео на этот WordPress, PHP проксирует запрос на внутренний IP бэкенда (по умолчанию, рекомендуется когда WordPress и API на одном сервере). Напрямую из браузера (CORS) — браузер обращается к публичному URL API. |
| Внутренний URL бэкенда | Адрес API, доступный с этого сервера (по умолчанию http://127.0.0.1:18018). Используется в режиме «Через сервер». |
| Публичный URL API-бэкенда | Публичный адрес Flask-приложения (по умолчанию https://med.my-dpr.ru). Используется в режиме «Напрямую» и для ссылки «Поделиться». |
Можно также переопределить кодом:
add_filter('med_diag_api_url', fn() => 'https://другой-домен.ru');
add_filter('med_diag_internal_url', fn() => 'http://10.0.0.5:18018');
add_filter('med_diag_mode', fn() => 'direct');
Как это работает
- Режим «Через сервер» (по умолчанию): JS отправляет видео на REST-эндпоинт этого же WordPress (
/wp-json/med-diag/v1/analyze), PHP пересылает его на внутренний IP бэкенда (http://127.0.0.1:18018/analyze). Скачивания PDF/DOCX/видео идут через/wp-json/med-diag/v1/download/<id>/<type>. CORS не нужен — все запросы same-origin. - Режим «Напрямую»: JS отправляет видео на публичный URL API (
POST /analyze) — тогда нужен CORS на стороне Flask. - Результат (сводка, показатели, рекомендации, кнопки PDF/DOCX/видео/поделиться) рендерится на странице WordPress.
- Сканирование с камеры работает на мобильных (canvas 720×720 + MediaRecorder).
Требования к серверу WordPress (режим «Через сервер»)
Видео сначала загружается в PHP, поэтому в php.ini должны быть подняты лимиты:
upload_max_filesize = 100M
post_max_size = 100M
max_execution_time = 300
Проверить текущие значения: php -i | grep -E "upload_max_filesize|post_max_size|max_execution_time".
Если WordPress стоит за nginx, поднимите лимит и там — иначе nginx вернёт HTML-страницу 413 Request Entity Too Large:
client_max_body_size 100M;
client_body_timeout 300s;
proxy_read_timeout 300s;
Обработка ошибок и лимитов
Серверная часть и плагин отдают ошибки всегда в JSON ({"error": "..."}), поэтому фронтенд никогда не получает HTML-страницу
вместо данных и не падает с Unexpected token '<' (аналог обработчиков 413/404/500 во Flask-бэкенде):
| Ситуация | Ответ | Сообщение |
|---|---|---|
Файл больше 100 МБ (в т.ч. тело отброшено из-за post_max_size, UPLOAD_ERR_INI_SIZE) |
413 |
«Видео слишком большое (максимум 100 МБ)» |
| Файл не передан | 400 |
«Видео не загружено» |
Формат не из списка mp4/avi/mov/mkv/webm/m4v |
400 |
«Неподдерживаемый формат…» |
| Бэкенд недоступен | 502 |
«Бэкенд недоступен: …» |
| Бэкенд вернул не JSON (HTML-страница ошибки nginx/Flask) | 502 |
«Бэкенд вернул некорректный ответ (HTTP …)» |
| Ошибка анализа на бэкенде | статус бэкенда | текст бэкенда + video_url (ссылка «Скачать записанное видео») |
На стороне браузера ответ разбирается безопасно: если вместо JSON пришёл HTML, из него вырезаются теги и показывается короткое текстовое сообщение (и оно экранируется перед вставкой в страницу).
Требования к бэкенду (Flask)
В app.py серверного репозитория уже добавлена поддержка CORS (нужна только в режиме «Напрямую»):
Access-Control-Allow-Origin— по умолчанию*, можно ограничить через envCORS_ORIGINS(список через запятую, напримерhttps://site1.ru,https://site2.ru).- Preflight
OPTIONS /analyzeвозвращает204.
Также во Flask добавлены обработчики ошибок 413/404/500, всегда возвращающие JSON, и try/except вокруг сохранения видео —
поэтому и POST /analyze, и /download/... отдают ошибки в виде {"error": "..."}. Плагин ожидает такой же формат
(см. «Обработка ошибок и лимитов»), а на не-JSON (HTML) ответы реагирует безопасно.
Локальное тестирование
- Поднимите API-бэкенд локально (см. README серверного репозитория) или используйте прод
https://med.my-dpr.ru. - Установите плагин в локальный WordPress (например, на
http://wp.locчерез Apache vhost). - Создайте страницу с шорткодом
[med_diagnostics]и откройте её. - Проверьте в консоли браузера, что
MED_DIAG.apiUrlуказывает на нужный бэкенд, и что запросPOST /analyzeпроходит (CORS).
Ограничения
- Шорткод используйте один раз на странице (id элементов фиксированы).
- Для работы сканирования с камеры нужен HTTPS на сайте WordPress (getUserMedia требует secure context).
- В режиме «Через сервер» видео загружается в PHP — следите за лимитами
upload_max_filesize/post_max_size/max_execution_time(см. выше). - Ссылка «Поделиться» всегда ведёт на публичный URL API (
/r/<share_id>).
Структура
Корень репозитория = папка плагина:
med-diagnostics/
├── med-diagnostics.php — главный файл плагина (шорткод, настройки, ассеты)
├── README.md — этот файл (в zip не попадает)
└── assets/
├── css/med-diag.css — стили сервиса (префикс med-)
└── js/med-diag.js — логика (fetch на API, сканирование, рендер результата)