Qevix — Jevix-подобный автоматический фильтр HTML/XHTML разметки в текстах пользователей

qevixQevix — Jevix-подобный автоматический фильтр HTML/XHTML разметки в текстах.

Применяя наборы правил, контролирует перечень допустимых тегов и атрибутов, предотвращает возможные XSS-атаки.

Qevix основывается на идеях и исходном коде PHP версии Jevix (средства для фильтрации HTML/XHTML разметки и автоматического типографирования текста).



Привет, меня зовут Александр и я здесь, что бы дать вам возможность отказаться от Jevix.

Жаль, что Jevix не развивается и не поддерживается даже сообществом, которое его использует. Я долгое время использовал Jevix входящий в состав LiveStreet для своих проектов, хоть он и был немного доработан, но все же в нем оставался рад неприятных проблем.

Мне не нравилось:

  1. Что парсер вырезает тег BR из моих CODE. Довольно неприятная ситуация если нужно размещать HTML код в посте;
  2. Два раза преобразовывались спец. символы в HTML-сущности в атрибутах тегов;
  3. Невероятно жадная подсветка ссылок, забирала в себя знаки пунктуации после ссылки, из-за чего ссылки получались битыми;
  4. Невозможность заключать ссылки в кавычки или скобки из-за предыдущего пункта;
  5. Не верное определение символов новой строки при их пропуске. Под символом новой строки понимались и \n и \r. В связи с чем, если на входе путаница с переводами строк, то и на выходе корректной расстановки тегов BR не получалось.

Я ещё не учитываю официальную PHP версию, в которой нет некоторых полезных конфигов, таких как полный callback тега и пропуск символов новой строки после блочных тегов.

Уже около года я использую Qevix в своих проектах и могу полагать, что он достиг некоторой зрелости. Я постарался сохранить стилистику конфигурации, как и в оригинальной версии, но с добавлением некоторых новых возможностей.

Что нового:

  1. Можно напечатать тег BR в CODE. Что довольно важно, если требуется публиковать HTML код;
  2. Ссылки можно заключать в скобки и двойные кавычки, а так же могут быть завершены знаком пунктуации;
  3. Нормализация символов перевода строки на входе и возможность установить то, что хотим получить на выходе;
  4. Новая настройка cfgSetTagBlockType указывает, после каких тегов стоит пропустить один перевод строки, например, это могут быть блочные теги. Она есть в LiveStreet, но отсутствует в официальной PHP версии Jevix;
  5. Новая настройка cfgSetTagGlobal указывает, какие теги не должны быть дочерними к другим тегам. Например, для тега CUT это может быть очень полезно;
  6. Новая настройка cfgSetTagBuildCallback устанавливает на тег callback-функцию для ручной сборки тега. Это аналог cfgSetTagCallbackFull из LiveStreet. Функция получает 3 параметра: название тега, массив с атрибутами тега и содержимое тега. Например, можно разрешить пользователям использовать только тег CODE, а на выходе собирать PRE CODE;
  7. Новая настройка cfgSetTagEventCallback устанавливает на тег callback-функцию для сбора информации. В отличие от callback-функций, установленных с помощью cfgSetTagBuildCallback, этот обработчик не вносит изменения в текст, а может быть использован для сбора какой-либо информации об используемых тегах. Например, можно посчитать, какое количество изображений в тексте, есть ли они вообще, и сформировать массив из их URL для последующего использования, скажем, в meta-описании станицы;
  8. Новая настройка cfgSetSpecialCharCallback устанавливает на строку, предваренную спец. символом callback-функцию. По умолчанию Qevix работает с тремя спец. символами #, @, $. Как можно догадаться, эта настройка позволяет получить хештег (#hashtag) или имя пользователя (@username), или ключевое слово ($keyword) и оформить его в виде ссылки или того, что вам нужно. Подробнее об этом в документации.
  9. В Qevix сохранена только часть типографии Jevix. В Qevix нет понятия русский или латинский алфавит, есть служебные и просто печатные символы. Поэтому нельзя сказать, что этот продукт только для русскоязычных текстов. Qevix следит только за дефисами, кавычками, HTML мнемониками, может подсвечивать ссылки и устанавливать переводы строки.

Благодарю за внимание, надеюсь кому-нибудь Qevix послужит хорошую службу. Пример работы и конфигурации вы можете посмотреть в README на GitHub.

GitHub: github.com/AlexanderGrom/Qevix
Документация: github.com/AlexanderGrom/Qevix/blob/master/DOCUMENTATION.md
README: github.com/AlexanderGrom/Qevix/blob/master/README.md

Лицензия MIT.

38 комментариев

avatar
Интересно. А вот эти проблемы решены?
github.com/livestreet/livestreet/issues/295
github.com/livestreet/livestreet/issues/10
avatar
Первое это наверно проблема двойного экранирования спец. символов, это простая ошибка, там вначале экранирование идет при распознавании тега, а потом ещё при его сборке.
Второе с автозаменами, я их исключил вообще. Я не всю типографику сохранил, в первую очередь нужно фильтровать теги.
avatar
Спасибо, кстати, что напомнили об 7 летней ошибке с автозаменой © и ® в теге «code», сегодня исправил:
github.com/livestreet/livestreet-framework/issues/62
avatar
Браво, будем пробовать!
  • dev
  • 0
avatar
Если вы пишете про суто системный продукт, не для обычного пользователя, а для технарей, то очень важно рассказать про устройство. В данном случае код основан на Jevixе? Это все тот же конечный автомат? Уже посмотрел, да, это он.

Кстати, я вижу что он полностью построен на Жевиксе, только переформатирован и приупорядочен немного, но вот никаких упоминаний в коде об этом не нашел.

А вообще — в Jevix вносилось очень много правок как по безопасности так и настройке, например, разрешенных протоколов. Плюс, парсер — это очень, очень важная часть цмс, если в ней будут бреши, то весь сайт взломать — дело техники. Поэтому вот так просто перескочить на новый парсер без его тестирования — верх легкомыслия, тем более что преимущества, описываемые в топике, есть только относительно «чистого» Жевикса, а в лс он уже значительно допилен и имеет большую часть того, что вы описываете. Плюс Жевикс проверен временем и используется много где, например, на том же Хабре.

Я ещё не учитываю официальную PHP версию, в которой нет некоторых полезных конфигов, таких как полный callback тега
Вот я о чем выше — в лс это есть.

Новая настройка cfgSetTagBlockType указывает, после каких тегов стоит пропустить один перевод строки, например, это могут быть блочные теги. Она есть в LiveStreet, но отсутствует в официальной PHP версии Jevix;
Вот я выше все о том же.

Уже около года я использую Qevix в своих проектах и могу полагать, что он достиг некоторой зрелости.
«Ваши проекты» не означают отсутствие проблем в безопасности, например, если на них публиковать контент может только админ. А на лс много сайтов и проверить на прочность парсер есть желающие.

Плюс вы новичок (чистый аккаунт даже на гите) и к вам, естественно, будет некоторая доля недоверия т.к. в коде может быть допущена в определенных комбинациях тегов/атрибутов ошибка что приведет к проблемам в безопасности и в новой лс, которую так долго делали, будет такая дыра, если его туда принять.

Честно и открыто расписал. Поэтому я против замены парсера в лс.

З.Ы. Я знаю что я консерватор и иногда ретроград, но во многих ситуациях как и в этой — это здравый смысл.
avatar
Сложно судить о профессиональный навыках человека по новому аккаунту на GitHub )

Я не призываю сесть и заменить парсер. Я дал возможность выбора. Я же не сделал порт для быстрой замены, в надежде поймать новичков. Кто грамотен и хочет попробовать, пожалуйста.

Насчет похожести. Идея та же. Нужен детальный осмотр.

Под своими проектами я имел ввиду и свою работу. Я был бы рад, если нашлись желающие проверить его на прочность.

По поводу конечного автомата. Не могу сказать, что это конечный автомат, тут не используются состояния, больше похоже на перебор символьного массива с некоторыми условиями. Я и про Jevix не могу сказать, что это прям идеальный конечный автомат, хоть там и есть пара состояний.

Я писал, что долгое время использовал Jevix из состава LiveStreet и упомянул о некоторых доработках. Там их не так много.
avatar
Сложно судить о профессиональный навыках человека по новому аккаунту на GitHub )
Если человек пишет свой парсер текста, то у него за плечами должен быть какой-то опыт и явно гит не может быть пустым т.к. не может человек первое что сделать это парсер, а у вас там только он и никакой другой активности. А если гит пустой, то может это анонимизация такая?

Насчет похожести. Идея та же. Нужен детальный осмотр.
Нет, там как раз Jevix, который хорошо порефакторили и исправили, но это он. Не хотите же вы сказать что тот весь код вы написали сами?

Под своими проектами я имел ввиду и свою работу.
Но вы не говорите где это используется, снова какая-то анонимизация.

Я был бы рад, если нашлись желающие проверить его на прочность.
И вот именно это опасно — о вас ничего не известно, где используется — тоже, аккаунт новый и нулевой. Зачем секретничать если вам нечего скрывать?

Все это я к тому — если вы не преследуете нехорошие цели — вы можете дать больше информации. Никто не будет использовать неизвестно что от неизвестно кого, что проверено где-то на неизвестных проектах, которые известны лишь неизвестному автору ).
avatar
Я асоциальный тип.

Опять на счет похожести. Это как кабачок и баклажан. Разумеется я использовал Jevix, дописывал его, изучил его вдоль и поперек, знал каждую строчку. В итоге мне очень нравилась идея и очень не нравилась реализация.

1. Классификация символов — хорошая идея.
2. Рекурсивный перебор символьного массива с запоминанием позиции — хорошая идея.

Что тут можно придумать нового, если я уже так подружился с этим кодом и проникся им.

Да и другим людям мароки меньше, кто знаком в Jevix, тому будет не проблема разобраться. По этому целенаправленно придумывать другой подход и изобретать синтаксический анализатор нет смысла.

Кстати на счет Хабра. Вот у них у же давно не тот Jevix и всех его проблем у них нет. При разработке я сравнивал свой вывод с выдачей Хабра на предмет тех и ли иных нюансов.
avatar
Но код обеих парсеров более чем просто похож.

У хабра Jevix на перле, который они дописывают и который все ещё поддерживается.
avatar
Откуда информация, что он там на перле?

Вот Вы пишите:

Плюс Жевикс проверен временем и используется много где, например, на том же Хабре.

Противоречите себе?


Конечно можно бесконечно обсуждать, что Qevix это копия Jevix и отличаются они одной буквой, а я подозрительная личность… но я ожидаю чего-то более конструктивного.

в Jevix вносилось очень много правок как по безопасности

Сколько за последние 7 лет? Если открыть 2 окна с голым Jevix и JLS, можно найти только добавление разрешенных протоколов для ссылок и новый тип атрибута #domain с возможность перечисления доменов для вставок видеороликов, что должно вообще решатся в калбэке.

Но это только касаемо безопасности.
avatar
Откуда информация, что он там на перле?
Где-то находил ранее, что они ушли от пхп-шного Жевикса на оригинальный перловый.
Противоречите себе?
В чем?
Конечно можно бесконечно обсуждать, что Qevix это копия Jevix и отличаются они одной буквой, а я подозрительная личность… но я ожидаю чего-то более конструктивного.
Не утрируйте, я все предельно точно написал выше.
Сколько за последние 7 лет? Если открыть 2 окна с голым Jevix и JLS, можно найти только добавление разрешенных протоколов для ссылок и новый тип атрибута #domain с возможность перечисления доменов для вставок видеороликов, что должно вообще решатся в калбэке.
если дифф не умеете делать — разговор ни о чем.
avatar
Ну это уже придеретесь, diff я делал или распечатал и карандашом обвел, тут никакой разницы.
avatar
Qevix основывается на идеях PHP версии Jevix (средства для фильтрации HTML/XHTML разметки и автоматического типографирования текста).
Qevix основывается на коде PHP версии Jevix
avatar
Единственное что можно было бы перенести — это cfgSetSpecialCharCallback, хотя он на данный момент полностью реализуется через плагины/регулярку.
avatar
А насколько сложно научить Jevix заворачивать абзацы в ?
avatar
Есть много нюансов и получается костылеобразно. Мне кажется только пользователь точно знает, где у него должен быть абзац. Парсер может догадываться, но если на входе плохо оформленный текст, то ничего хорошего не получается.

Не усложняя локигу так, что потом было непонятно, что и зачем, у меня в сожалению не вышло.
avatar
А чего тут сложного? В TineMCE абзацы выделяются. Нажал enter — получил абзац. Скрипту нужно вставлять P в начале и /P вместо двойного BR
avatar
Так же Параграф должен закрываться перед блочным тегом, в параграфе не должно быть других параграфов, нужно знать где закрыть параграф если закрывающего тега не нашлось, нужно учитывать вложенность элементов, нужно учитывать, что в некоторых тегах параграф просто не нужен, например это может быть список.

Я сейчас всего и не вспомню.
avatar
в текущей реализации Жевикса по-нормальному этого реализовать невозможно. только хаками вроде тех, что вы написали внизу.
avatar
Странная реакция, у само собой весьма уважаемого за вклад в ls, Сергея.

Разве топикстартер в своём посте утверждал что-то вроде «Джевикс — фигня, берите мой парсер и будет всё супер»?

За это решение не требуется платить денег, и не утверждается, что обязательно надо его использовать.
Мне кажется, сама суть сообщества (любого) именно в том, чтобы делиться мнениями по улучшению продукта. И дружелюбное отношение к новым решениям будет только способствовать развитию.

Вот Вам пример. Только благодаря этому посту вдруг вспомнилось:

Спасибо, кстати, что напомнили об 7 летней ошибке с автозаменой © и ® в теге «code», сегодня исправил:

и про cfgSetSpecialCharCallback тоже самое.

Стало быть сообщение уже полезно. Разве нет?

ps. про пустой гитхаб — смешно ;) Вот оказывается в чём заключается уровень. В «под завязку» заполненном гитхабе.

ps.ps. Дабы не нервировать Вас своим пустым профилем, объясню. Давно интересуюсь LS и как правило в основном читаю всевозможные интересные заметки и сообщения. А тут топекстартер посоветовал ознакомится с данной дискуссией.

Это личное мнение. Всем добра! ;)
avatar
Стало быть сообщение уже полезно. Разве нет?
Возможно, кому-то полезно, я выразил точку зрения почему прямая поставка этого парсера в лс — сомнительное решение и привел целый список доводов «почему».
ps. про пустой гитхаб — смешно ;) Вот оказывается в чём заключается уровень. В «под завязку» заполненном гитхабе.
Не аппроксимируйте все написанное. Если последовательно читать без ангажированности становится ясно почему я акцентировал внимание на том, что нонейм пользователь не вызывает доверия.

И гит на сегодняшний день не обязательно должен быть «забит» своими репами, там ещё активность есть по другим. И вам это должно быть известно.
avatar
Мне кажется, сама суть сообщества (любого) именно в том, чтобы делиться мнениями по улучшению продукта.
Так а что, мнения должны быть только хвалебного плана?
И дружелюбное отношение к новым решениям будет только способствовать развитию.
Автор отрефакторил обычный Жевикс, переименовал методы, переменные, кое-что несомненно улучшил но это все тот же Жевикс, но автор прямо уклоняется от ответа использовал он код Жевикса или нет:
Разумеется я использовал Jevix, дописывал его, изучил его вдоль и поперек, знал каждую строчку. В итоге мне очень нравилась идея и очень не нравилась реализация.

Что тут можно придумать нового, если я уже так подружился с этим кодом и проникся им.
При этом в коде нет никаких комментариев что использован код Жевикса — это тоже нормально?

Qevix github.com/AlexanderGrom/Qevix/blob/master/qevix.php
Jevix github.com/livestreet/livestreet-framework/blob/master/libs/vendor/Jevix/jevix.class.php

т.е. автор:
Что тут можно придумать нового, если я уже так подружился с этим кодом и проникся им
что написал очень-очень похожий код.

Разве топикстартер в своём посте утверждал что-то вроде «Джевикс — фигня, берите мой парсер и будет всё супер»?
не утверждал, но предлагал:
я здесь, что бы дать вам возможность отказаться от Jevix.
а раз предлагает, я выразил свою точку зрения по этому поводу, это называется дискуссия или как вы сказали:
делиться мнениями
поэтому повторю вопрос, с которого начался этот комментарий: так а что, мнения должны быть только хвалебного плана?
avatar
Что же Вам так это покоя то не дает. Указано же, что это «Jevix-подобный автоматический ....»
Подобный — аналогичный, схожий, совершенно похожий.

Если бы он не был хоть немножко похож, стал ли я это указывать?

Целый день разговор ни о чем. Надо что бы он был написал вверх ногами справа налево и был вообще не похож ни на что другое написанное человечеством? Или что бы он работал и делал то что должен?

Я предполагал, что придут умные ребята, скажут мол «мы тут 6 лет с ним работаем и знаем все его недостатки, а у тебя тут косяк и тут косяк...»

Если вам не дает покоя, что это отрефактореный Jevix, что же никто этого не сделал раньше? Почему у меня 6 лет нет BR'ов в моих CODE? Почему у меня ссылки не правильно подсвечиваются?
avatar
Что же Вам так это покоя то не дает.
Это называется культура — правильно оформлять описание, где можно обозначить что код основан на коде других разработчиков.
Подобный — аналогичный, схожий, совершенно похожий.

Если бы он не был хоть немножко похож, стал ли я это указывать?
Вот снова. Вы долго будете ходить вокруг да около? Вопрос стоял так: вы написали весь код сами, без копипасты или даже не рефакторили код Жевикса для использования в своем Кевиксе?

Целый день разговор ни о чем.
Повторяю: разговор о том, что вы не признаетесь в использовании кода Жевикса и принимаете форму шланга. Причем если вы признались бы, что да, это был код Жевикса, рассказали почему нет ссылок на пред. авторов и добавили их — вот было бы хорошо.
Надо что бы он был написал вверх ногами справа налево и был вообще не похож ни на что другое написанное человечеством? Или что бы он работал и делал то что должен?
Код похож на код из Jevixа. Измененный ли это код? да. отрефакторенный? да. улучшенный? да. Но не бывает таких близких совпадений если вы все написали с головы.

Я предполагал, что придут умные ребята, скажут мол «мы тут 6 лет с ним работаем и знаем все его недостатки, а у тебя тут косяк и тут косяк...»
какой разговор с человеком:
— который о себе ни слова, но пишет:
Уже около года я использую Qevix в своих проектах и могу полагать, что он достиг некоторой зрелости.
на основе чего? статистика? примеры использования? сайты? что это за сайты по доступу к генерированию контента (пользователями/админами)?
— человек не признается в использовании кода другого парсера
— не сохраняет предыдущее авторство в комментариях к проекту

о чем с таким человеком говорить?

Если вам не дает покоя, что это отрефактореный Jevix
вы неправильно причинно-наследственную связь ставите. это вас должно беспокоить что вы выдаете продукт как полностью свой, хотя он по наибольшей вероятности основан на стороннем коде. также вы до сих пор не написали ни "что весь код написан полностью мной" ни "что в Qevixе использован код Jevixа". вместо этого вы уже который раз уходите от ответа.
что же никто этого не сделал раньше?
потому что это никого не интересовало? не было надобности? не было кому? какая разница. вы — сделали и все комментарии сводяться к ожидани вашего ответа на поставленный выше вопрос.

Резюмируя: я сказал что ваш код говно или что-то в этом роде? нет. я сказал что он в лес никому не нужен? нет. я сказал что вы такой неизвестный, а значит вы плохой код априори будете писать? нет.

я написал:
— что код похож на Жевикс и спросил было ли прямое использование его кода? ответа нет, а комментариев ваших много.
— я сказал что ваша анонимность настораживает в ситуации если этот код будут использовать пользователи т.к. они поставят себе его от неизвестно кого.

объясняешь-обьясняешь — все мимо.
avatar
Раз уж так получилось, специально для Вас и что бы в дальнейшем не было прецедентов.

Qevix основывается на идеях и исходном коде PHP версии Jevix


И в Read Me на GitHub.
avatar
стоимость этого — всего 25 комментариев!

а теперь — обсуждение!
как вы думаете, зачем раньше парсинг литералов делился на латинский алфавит и кириллический? что дало вам от упрощения данного механизма и унификации символов?
avatar
Определение, что символ является кириллическим нужно было только для осуществления типографирования пунктуации. Например, ставить пробел после запятой, если его там нет. Но это работало только если в после запятой стоял кириллический символ, латиницу этим обделили.

В Qevix этого типографирования нет. Два восклицательных знака не заменяется на один, а четыре на три. Может показаться, что это не очень хорошо, но бывают разные обозначения. Например .htaccess, после точки не нужен пробел, есть много обозначений использующих в себе знаки пунктуации.
avatar
Но это работало только если в после запятой стоял кириллический символ, латиницу этим обделили.
это было возможно до того, как сделали отключаемое типографирование в некоторых тегах, например, code? поэтому считали что парсер будут использовать на кириллических сайтах, а англ. текст может быть кодом. как вам такая теория?
Два восклицательных знака не заменяется на один, а четыре на три.
Кстати, хорошая штука, которая исправляет речь возмущенных пользователей.
Может показаться, что это не очень хорошо, но бывают разные обозначения. Например .htaccess, после точки не нужен пробел
Жевикс, кстати, к этому, при всем своем исправлении текста и пунктуации, был приучен.

думаю что автоисправление нужно.
avatar
Я не знаю, в друг его захотят использовать китайцы, а у них типографика какая-то другая. Да и от не адекватов он не очень ПоМАГАет!!..!!! !!111… (простите)
avatar
Курсивом, курсивом хорошо выделяется такое.
Может на китайцев пока не смотреть?
avatar
проводились ли какие-либо сравнительные тесты по скорости обработки с одинаковыми наборами правил больших хорошо отформатированных текстов в обеих парсерах?
avatar
Я сейчас сделал Update, и заменил методы ord и chr на более быстрые.
Отличие производительности в 2 раза.

Среднее время на моей машине:

Qevix: 0.14
Jevix: 0.07

Такая разница в том, что Qevix просматривает и запоминает символы: текущий, до него и после него. Что очень удобно для анализа.
avatar
Такая разница в том, что Qevix просматривает и запоминает символы: текущий, до него и после него.
это вы про состояния которые были у жевикса?
avatar
Состояния смотря с какой точки зрения, если представить что это автомат, то его головка сдвигается на следующий символ и Jevix узнает, текущую позицию (curPos), сам символ (curCh), код символа (curChOrd) и класс символа (curChClass).

Так вот это он знает только про текущий символ и ничего не знает что было до него и что будет после него.

Но с точки зрения автомата это не состояние.
avatar
нет, жевикс там умел сохранять и восстанавливать этот набор переменных.
avatar
И Qevix это умеет, и всеровно знает, что было до, сейчас и будет после. Без возврата головки тут никуда.
avatar
а родительские теги хранит?
avatar
parentTag передается по рекурсии, от найденного тега к следующему, тем самым можно использовать его в некоторых условиях. В Jevix он хранится в свойстве curParentTag, но обратится всеровно в нему можно только из рекурсии иначе он пустой. По-этому нет смысла засорять набор предопределенных свойств.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.