Цель поста — покритикуйте.
Изучаю Django по-маленьку, посредством создания движка для блога. Появилась проблема вывода пользовательского контента, т.е. его экранирования. Написал свою функцию. Имея кое-какой опыт в создании контента для разных сайтов с разной идеологий экранирования пользовательских данных (скорее отрицательный, в основном сайты просят делать лишнюю работу), у меня выработалась философия.
Замечание. В моём блоге в базе всегда хранится никак не обработанный оригинал пользовательского ввода. Задача функции — сделать из этого ввода html, пригодный для отображения. В простейшем случае функция может вызываться во время отображении контента (в шаблоне или view). Для улучшения производительности можно завести отдельное поле в базе, которое будет результатом работы функции экранирования, и будет обновляться во время обновления контента.
Итак, философия функци:
Вот так всё просто для пользователя — пиши что хочешь, всё будет экранировано, кроме разрешённых тэгов.
Почему не готовая разметка, bbcode, markdown:
Хотя сделать свои компактные тэги, которые бы раскрывались в громоздкие html тэги, это хорошая идея. Скорее всего я сделаю так, что на каждый пользовательский ввод можно будет назначить свой фильтр.
Вот некоторые примеры, взятые из тестов:
К сожалению, у меня нет сервера где можно было бы показать работу функции. Она находится вот здесь: http://pastebin.com/f591d71e5.
Надеюсь на критику, спасибо.
Изучаю Django по-маленьку, посредством создания движка для блога. Появилась проблема вывода пользовательского контента, т.е. его экранирования. Написал свою функцию. Имея кое-какой опыт в создании контента для разных сайтов с разной идеологий экранирования пользовательских данных (скорее отрицательный, в основном сайты просят делать лишнюю работу), у меня выработалась философия.
Замечание. В моём блоге в базе всегда хранится никак не обработанный оригинал пользовательского ввода. Задача функции — сделать из этого ввода html, пригодный для отображения. В простейшем случае функция может вызываться во время отображении контента (в шаблоне или view). Для улучшения производительности можно завести отдельное поле в базе, которое будет результатом работы функции экранирования, и будет обновляться во время обновления контента.
Итак, философия функци:
- Это первооснова — любые пользовательские данные изначально считаются невалидными. Поэтому всё что не разрешено будет экранироваться.
- Минимум работы для пользователя. Если я хочу написать конструкцию с угловыми скобками, я буду писать угловые скобки, а не буду думать о "& lt;" и т.д. Функция сама преобразует неправильные символы.
- Тем не менее можно использовать некоторые тэги. Какие — задаётся параметром функции, или используется набор по-умолчанию. У каждого тэга есть набор валидных атрибутов. Функция будет оставлять валидные тэги и валидные атрибуты. Невалидные атрибуты будут просто удаляться из вывода, невалидные тэги будут экранироваться.
- Следуя первооснове (и здравому смыслу) — незакрытые тэги будут автоматически закрываться. Закрывающие тэги без открывающих будут экранироваться.
- Блог задумывается ориентированным на программерскую тематику, т.е. в блоге будут куски кода. Эти куски должны экранироваться целиком (это будет кусок кода, любого, хоть html). Для этого есть тэги <pre><code[ class="language"]>...</code></pre>. Я ориентировался на библиотеку подсветки кода highlight.js, она использует именно такой формат обрамления кода. Всё что находится внутри этого блока будет экранировано целиком. И подсвечено.
- Я люблю колобков :) Поэтому функция должна опционально заменять смайлы на изображения.
Вот так всё просто для пользователя — пиши что хочешь, всё будет экранировано, кроме разрешённых тэгов.
Почему не готовая разметка, bbcode, markdown:
- Что бы пользователям не учить эту новую разметку.
- Что бы текст поста был максимально «стандартным» (html) и переносимым. Копи-пастим оригинальный текст поста, экранируем участки с кодом, вставляем в другой блог — он корректно отображается.
Хотя сделать свои компактные тэги, которые бы раскрывались в громоздкие html тэги, это хорошая идея. Скорее всего я сделаю так, что на каждый пользовательский ввод можно будет назначить свой фильтр.
Вот некоторые примеры, взятые из тестов:
# New line test
text: 'New' + os.linesep + os.linesep + 'line'
html(text): 'New' + '<br/>' + os.linesep + '<br/>' + os.linesep + 'line')
# Simple smile test
text: ':)'
html(text): '<img src="/files/smile.gif"/>')
# Smile in code block test
text: '<pre><code>there will be no image :)</code></pre>'
html(text): '<pre><code>there will be no image :)</code></pre>')
# Plain text test
text: 'Some simple text without any tags'
html(text): 'Some simple text without any tags')
# Simple tags test
text: 'This is <b>important</b> information'
html(text): 'This is <b>important</b> information')
# Wrong tag test
text: 'This is <b>important</b> information and this is <h5>title</h5>'
html(text): 'This is <b>important</b> information and this is <h5>title</h5>')
# Wrong attributes test
text: 'This is <b onclick="javascript:alert();">probable XSS</b>'
html(text): 'This is <b>probable XSS</b>')
# Simple tags test
text: 'This is <img src="image.jpg" onclick="javascript:alert();"/>image'
html(text): 'This is <img src="image.jpg"/>image')
# Text without tags
text: 'Sample code: <?php print "Hello World"; ?>'
html(text): 'Sample code: <?php print "Hello World"; ?>')
# Code test
text: 'Sample code: <pre><code><a href="home.html">link</a></code></pre>'
html(text): 'Sample code: <pre><code><a href="home.html">link</a></code></pre>')
# Closing tag without opening tag
text: '</b>bold text ended'
html(text): '</b>bold text ended')
# Autoclosing tags test
text: '<b>bold and <i>italic</i> text'
html(text): '<b>bold and <i>italic</i> text</b>')
# Overlapping areas test
text: 'if 1 < 2 <b>only</b> then it is ok, but if 1 < 2 or 2 < 3 then <i>bad</i>'
html(text): 'if 1 < 2 <b>only</b> then it is ok, but if 1 < 2 or 2 < 3 then <i>bad</i>')
К сожалению, у меня нет сервера где можно было бы показать работу функции. Она находится вот здесь: http://pastebin.com/f591d71e5.
Надеюсь на критику, спасибо.