Началась работа над новой версией Intellect Board. Увы, приходится признать, что традиционные форумы слишком плохо совместимы с современными условиями жизни, где постоянно присутствует перегруз информацией. Поэтому новая версия будет строится вокруг идеи «интерфейс должен экономить когнитивные усилия, а не требовать дополнительных», а контент — максимально легкодоступным. Для этого планируется с нуля сверстать новый стиль на основе макета, сгенерированного с помощью нейросети, с меньшей визуальной перегрузкой, и написать новый модуль для главной страницы, а основной упор будет сделан на развитие разделов блогов и микроблогов. За основу будет взят подход, применяемый в проекте Zulip: категории находятся в боковой колонке (с индикатором новых тем после последнего захода), и там же расположено то, что в Zulip называется views, — ссылки для выборки последних тем, активно обсуждаемых тем, «выбора редакции» (рекомендованных сообщений), темы, созданные или просмотренные текущим пользователем, закладки и т.п. При этом на главной будет выводиться список последних тем/статей (примерно то, что сейчас в разделе «последние сообщения»).
Вторая существенная переделка — это изменение подхода к использованию HTML. В выпущенных версиях предполагается, что HTML используют только некоторые доверенные пользователи (обычно администраторы и модераторы), а обычные пользователи для форматирования используют теги BoardCode. Однако из-за этого приходилось использовать WYSIWG-редактор SCeditor, обладающий многими недостатками, так как он — один из немногих, которые поддерживают BoardCode. В новой версии планируется разрешить HTML для всех, однако теги и их атрибуты будут фильтроваться по белому списку в целях безопасности. Это позволит использовать другие WYSIWYG-редакторы. В частности, сейчас рассматриваются варианты Quill (основной кандидат), Pell и Trix.
Ещё одним существенным изменением будет возможность загружать прикреплённые файлы на этапе редактирования, а не одновременно с отправкой страницы на сервер, как сейчас.
На данный момент уже реализовано следующее (доступно в ветке current на GitHub):
1. Рефакторинг кода с целью избавиться от загрузки библиотек через функцию load_lib. Реализована автозагрузка классов с помощью штатных средств PHP и создание их экземпляров через new Library_<libname>. Это позволит нормально использовать дополнения в IDE. Для тех же целей произведён рефакторинг класса Database: те методы, которые реализуются только в потомках (например, insert_ignore), в нём теперь объявлены как абстрактные.
2. Очистка HTML-кода (на данный момент пока с фиксированным списком тегов, потом планируется выделить его в отдельный файл конфигурации).
3. Автоматическое распознавание ссылок наиболее на популярные в Рунете видеохостинги (кроме Дзена), которые автоматически преобразовываются в код для вставки проигрывателя в страницу. На данный момент это сделано для ссылок в тегах [video] или [youtube], рассматривается вопрос автоматического распознавания таких ссылок в том случае, если они вставлены отдельной строкой.
4. Улучшение читаемости ссылок, вставленных без поясняющего текста: расшифровка кириллицы в доменах и путях, сокрытие префикса http/https, скрытие слишком длинной строки с параметрами URL.
В заключение остаётся добавить, что все эти изменения будут делаться как дополнительные возможности: в виде нового стиля, нового модуля главной страницы и т.п. А у тех, кому нужен форум в его традиционном виде, останется возможность настроить всё как было.
Новости проекта и блог разработки
О том, как идёт разработка скрипта форума
- 1
- 2
Началась работа над новой версией
Создан репозиторий на GitHub
Теперь у Intellect Board есть и репозиторий в GitHub. Так что присылайте ваши pull requests!
Там же опубликована копия дистрибутива 3.05 в разделе Releases.
Теперь при желании вы можете попробовать установить самую последнюю сборку IntB из ветки current.
Для этого сделайте git clone --branch current https://github.com/XXXXPro/IntellectBoard и затем скопируйте файл install/install.php в каталог www.
Вышла версия 3.05
Состоялся выпуск версии 3.05 — самого крупного обновления за всю историю проекта. Теперь Intellect Board может работать не только с MySQL, но и с двумя другими СУБД — PostgreSQL и SQLite, а также много новых возможностей. Добавлен новый тип разделов — фотогалерея, в которой можно выложить фотоальбом и сопроводить его пояснительной историей, а также подписать отдельные фотографии. Появилась поддержка ряда протоколов IndieWeb: IndieAuth (только серверная часть), WebMention (клиент и сервер), MicroPub и разметки h-feed и h-card. Добавлена возможность отправлять уведомления о новых темах в Telegram, а новые сообщения в блогах и микроблогах — в ВК и LiveJournal.
Добавлено несколько новых тегов:
[math] и [mathblock] — для формул в TeX-формате, [asciimath] — для формул в формате ASCIIMath, [blocklink=URL] — для блочных ссылок с автоматической загрузкой изображения и краткого описания, если сайт поддерживает OpenGraph [attach=номер] и [attachblock=номер] — для ссылок на прикреплённые файлы в тексте сообщения.[/li]
Также появилась возможность сортировать сообщения в темах по их рейтингу и исправлен ряд мелких ошибок.
Скачать новую версию можно на странице «О проекте», инструкции по обновлению с предыдущих версий — см. в соответствующей теме.
Решён вопрос с конвертацией на Postgres
Благодаря утилите pgloader удалось автоматизировать конвертацию базы данных из MySQL в Postgres. В процессе выяснилось, что ENUMы преобразуются не самым лучшим образом: для каждого ENUM из MySQL создаётся уникальный именованный тип в Postgres. Не сказать, чтобы это было хорошим решением, но перевод всей базы с ENUM на TINYINT — это ещё хуже. Но в любом случае, это дало возможность добавить в инсталлятор поддержку установки на Postgres. Теперь ещё несколько дней тестирования, и состоится выпуск Intellect Board 3.05 с поддержкой Postgres и, возможно, SQLite (это пока под вопросом).
Добавлен морфологический поиск
На официальном сайте Intellect Board появился поиск с учётом словоформ с помощью Sphinx Search. Кроме того, это дало возможность искать Как выяснилось, Native Sphinx API, которая использовалась с версии 3.00, теперь считается устаревшей (deprecated), поэтому пришлось переписать библиотеку работы со Sphinx на SphinxQL и использование функций mysqli_*. Кроме того, в окончательную версию 3.05 будет добавлена возможность указывать в настройках имена индексов, что может быть полезно, если на одном сервере запущено несколько форумов IntB. Также написана документация о том, как настраивать Sphinx.
Обновлён демонстрационный форум
Обновлён демонстрационный сайт Intellect Board. Теперь на него установлена версия 3.05. На него добавлены новые типы разделов: блог, микроблог и фотогалерея. Кроме этого, создана категория «Разделы с необычными настройками», где показано, как с помощью изменения настроек получить раздел-хранилище знаний с автоматическим присвоением статусов «флуд» и «ценное», раздел с анонимной отправкой сообщений и раздел, где каждый автор темы будет автоматически получать права куратора в ней.
Кроме того, изменился режим доступа: теперь после регистрации присваиваются права обычного пользователя, а чтобы получить администраторские права, нужно зайти под пользователем Admin с паролем demo.
Началось открытое тестирование IntB 3.05 RC1
Началось открытое тестирование Release Candidate версии 3.05, которая станет самым крупным обновлением за всю историю Intellect Board. В частности, в этой версии было сделано следующее:
- Обеспечена совместимость с последними версиями PHP, включая 8.2.
- Обновлены основные сторонние зависимости: шаблонизатор Twig, библиотека jQuery и CKEditor. В результате обновления Twig удалось достигнуть более экономного расхода памяти: некешированные запросы теперь требуют от 1.6 до 2 Мб памяти, кешированные — 600-800 Кб (по данным функции memory_get_peak_usage под PHP 8.2 на 64-битной платформе).
- Добавлен самый долгожданный тип раздела — фотогалерея с тремя режимами просмотра фото: обычный, показ всех фото в полный размер и показ EXIF-данных фото. Также галерея поддерживает автоматический поворот фото на основе EXIF-данных и извлечение геометок.
- Добавлены несколько новых тегов:
[math] и [mathblock] — для формул в TeX-формате, [asciimath] — для формул в формате ASCIIMath, [blocklink=URL] — для блочных ссылок с автоматической загрузкой изображения и краткого описания, если сайт поддерживает OpenGraph [attach=номер] и [attachblock=номер] — для ссылок на прикреплённые файлы в тексте сообщения. - Реализована поддержка протоколов IndieWeb: IndieAuth (только серверная часть), WebMention (клиент и сервер), MicroPub. Это упрощает возможность делать публикации автоматически или использовать сторонние мобильные приложения, в частности, IndiePass. Также добавлена поддержка разметки h-feed и h-card.
- Для блог-разделов и микроблогов сделана интеграция с Telegram, VK.com и LiveJournal: можно настроить автоматическую отправку записей из таких разделов в группы или каналы в указанных социальных сетях. Это даёт возможность реализовать IndieWeb-принцип POSSE. Для обычных разделов существует возможность отправлять уведомления о новых темах и обычных сообщениях в Telegram-бот.
- Сделана единая точка входа для большинства запросов — файл index.php, что значительно упрощает настройку IntB в конфигурации nginx+php-fpm, без Apache.
- Добавлено понятие кураторов тем — модераторов, права которых распространяются только на одну тему (а также без доступа к IP-адресам). Предусмотрено два режима: либо либо кураторы назначаются модераторами вручную, либо куратором автоматически становится создатель темы (раньше это называлось режимом самомодерации).
- Приняты дополнительные меры для защиты от DDoS-атак: теперь CAPTCHA не сохраняется в файл, а выводится как base64-изображение (это позволяет избежать исчерпания inode или места на диске),
- Немного переработан интерфейс форума: изменён внешний вид кнопок действий, сделано всплывающее меню для быстрого цитирования и возможности поделиться выделенным текстом, добавлена подгрузка страниц форума и комментариев с помощью AJAX-запросов без обновления страницы целиком.
- Добавлена проверка размеров загружаемых файлов на стороне пользователя, чтобы избежать неудачной отправки сообщения при превышении лимитов, установленных на сервере.
- Убрана поддержка Share42, так как проект, похоже, давно не поддерживается его создателями.
- В дистрибутив включены все исправления, которые были выложены как патчи после последней сборки версии 3.02.
Скачать 3.05 RC1 и принять участие в тестировании можно уже сейчас. Сделать это можно в соответствующей теме: https://intbpro.ru/support-305/rc1-305/
Патч для отправки почтовых уведомлений
Недавно перенёс свои сервера на новый VDS, где вместо привычного Postfix в качестве MTA использовался Exim4. У него обнаружилась весьма неприятная особенность: если письмо содержало слишком длинные строки, Dovecot просто отклонял его отправку. Из-за этого не уходили рассылки, текст для которых был написан в WYSIWIG-редакторе, где получившийся HTML-код представляет собой одну длинную строку.
Пришлось искать решение, что с этим делать. Оно оказалось достаточно простым: разрезаем весь текст сообщения на куски определённой длины (я в качестве таковой использовал 70 символов) и в каждом из них после самого первого пробела добавляем символ перевода строки. После этого склеиваем всё обратно. Патч уже доступен для версии 3.02 в соответствующей теме.
Асинхронные задания в IntB
Как я уже писал в предыдущем сообщении, в разрабатываемой в данный момент версии IntB появилась такая возможность, как асинхронные задания (они же tasks). Впервые необходимость в них возникла тогда, когда я задумал добавить в Intellect Board поддержку протокола ActivityPub для взаимодействия с fediverse. Этот протокол работает по PUSH-модели, когда сервер сам отправляет уведомления подписчикам. При этом спецификация протокола требует, чтобы в случае ошибки попытка отправки уведомления повторялась ещё раз через какое-то время.
Технически асинхронные задания во многом аналогичны заданиям обычного планировщика, но есть ряд отличий. В частности, выполняемый код также должен лежать в библиотеке в каталоге lib в классе, унаследованном от Library, но название дожлно начинаться не с cron_, а с task_. Асинхронное задание считается выполненным, если функция возвращает либо 0, либо 200. Если же возвращается другое задание или выбрасывается исключение (exception), задание считается невыполненным. В этом случае оно будет повторно запущено через некоторое время. Это время определяется как количество минут, равное количеству предыдущих неудачных попыток запуска. То есть после первой неудачи задание будет перезапущено через минуту, после второй — через две и так далее. После 127 неудачных попыток задание считается невыполнимым и удаляется.
В базе данных информация о заданиях хранится не в таблице prefix_crontab, а в prefix_task. Там же находится счётчик попыток выполнения и время следующей попытки. Важное отличие: если для задач планировщика параметры хранятся в обычной строке, так как предполагают возможность редактирования из Центра Администрирования, то для асинхронных заданий — сериализуются через PHP-функцию serialize. Это даёт больше гибкости для передачи параметров.
Добавить новую задачу можно с помощью метода create_task в библиотеке misc. Он принимает следующие параметры: $library — имя библиотеки, где лежит выполняемый код, $proc — имя вызываемого метода (без task_ в начале),$params — параметры в произвольном виде (сериализация делается внутри самого create_task), $nextrun — время следующего выполнения (по умолчанию равно нулю, что означает выполнить как только будет возможность).
Сам запуск осуществляется из файла www/cron.php после выполнения задач обычного планировщика. При этом скрипт учитывает, сколько времени осталось до конца его выполнения и выбирает задачи из расчёта на то, что каждая будет выполнена за 5 секунд. (Если скрипт запускается через системный cron, то время выполнения считается равным 60 секундам).
Сейчас, как уже говорилось, асинхронные задания используются только для протокола WebMention (реализация ActivityPub отложена на неопределённое время). Но сейчас также рассматриваю возможность сделать тег blocklink для вывода ссылки с картинкой и развёрнутым описанием (аналогично тому, как это сделано ВКонтакте и Facebook). Для него также потребуются асинхронные запросы (чтобы закешировать информацию OpenGraph для этого предпросмотра).
Есть поддержка протокола WebMention
В пятницу доделал поддержку протокола WebMention. Это один из протоколов IndieWeb, который используется для того, чтобы уведомить автора публикации о том, что на этот материал отреагировали на другом сайте, например, написали ответную статью или просто сделали репост с указанием первоисточнка. Работает он так: WebMention-клиент заходит на страницу с исходной публикацией, обнаруживает там на специальный URL для уведомлений (он называется Webmention endpoint), и делает на него самый обычный HTTP-запрос, в котором указан адрес исходной публикации и страницы с реакцией. WebMention-сервер проверяет наличие ссылки на странице с реакцией и в том или ином виде фиксирует это у себя.
Серверную часть WebMention я реализовал достаточно давно, ещё в 2021 году. Это было достаточно просто: добавил в stdforum отдельный метод action_webmention, который делает все необходимые проверки, и если они проходят, в соответствующей теме создаётся сообщение от пользователя System о том, что по такому-то адресу упомянули наш материал. А в action topic_view добавил вывод тега link с rel="webmention" со ссылкой на этот action, для того, чтобы клиенты могли его обнаружить.
Клиентскую часть, на первый взгляд, тоже реализовать просто: при отправке сообщения выбрать в нём все ссылки, и для каждой сделать необходимый запрос. Сложности, как всегда, начинаются в деталях. В частности, в определении WebMention endpoint, куда нужно отправлять запрос (этот процесс называется endpoint discovery). Дело в том, протокол WebMention стремится к максимальной гибкости и допускает указание этого URL в разных местах: в HTTP-заголовках Link, в теге <link> в секции head и даже в обычной гиперссылке c тегом <a>, если для неё прописано rel="webmention". Чтобы надёжно находить такое в коде страниц, пришлось задействовать модуль dom. Но даже с этим модулем оказалось, что не всё так просто. Во-первых, в rel, кроме webmention, может быть что-то ещё, например, rel="webmention nofollow". Для корректной работы в таких ситуациях пришлось написать довольно сложное XPath-выражение:
//link[contains(concat(' ',normalize-space(@rel),' '),' webmention ')][@href]|//a[contains(concat(' ',normalize-space(@rel),' '),' webmention ')][@href]
Второй проблемой стало то, что ссылки могут быть как абсолютными URL, так и относительными (причём как от корня, так и от текущего каталога), и даже вовсе пустыми, и нужно обрабатывать все эти ситуации. Встроенных функций для работы с относительными URL в PHP почему-то нет, сторонние зависимости я стараюсь минимизировать, поэтому сделал своё решение.
И только после того, как всё перечисленное было сделано, удалось пройти все 23 теста на сайте webmention.rocks!
Кроме того, поскольку ссылок в сообщении может быть много, а запросы — дело достаточно долгое, есть шанс не успеть выполнить их все до окончания времени выполнения скрипта (того самого max_execution_time из настроек PHP). Поэтому для реализации клиента WebMention я впервые задействовал механизм taskов — одноразовых асинхронных задач, которые запускаются из скрипта cron.php после выполнения основных заданий. Но о них подробнее расскажу позже.
- 1
- 2

