Блог → PHP класс для фильтрации HTML кода

В свое время я писал функцию для фильтрации введенного пользователем HTML кода на языке Perl. Если кому интересно почитать можно здесь. Но так, как Perl уже давно не мейнстрим я решил переписать все это дело на PHP.

Пользоваться фильтром нужно следующим образом. Сначала подключаем класс и создаем объект представляющий из себя фильтр.

require_once "html_filter_class.php";
$html_filter = new html_filter();

Далее следует задать тэги для фильтрации. Например вот так:

$tags = array(
		
     'h1'		=> array('id', 'class'),
     'h2'		=> array('id', 'class'),
     'h3'		=> array('id', 'class'),
     'h4'		=> array('id', 'class'),
     'h5'		=> array('id', 'class'),
     'h6'		=> array('id', 'class'),
		
     'p'		=> array('id', 'class'),
     'span'		=> array('id', 'class'),
     'a'		=> array('id', 'class', 'href'),
     'img'		=> array('id', 'class', 'src', 'alt', FALSE),
     'br'		=> array(FALSE),
     'hr'		=> array(FALSE),
		
     'pre'		=> array('id', 'class'),
     'code'		=> array('id', 'class'),
		
     'ul'		=> array('id', 'class'),
     'ol'		=> array('id', 'class'),
     'li'		=> array('id', 'class'),
		
     'table'	=> array('id', 'class'),
     'tr'		=> array('id', 'class'),
     'td'		=> array('id', 'class'),
     'th'		=> array('id', 'class'),
     'thead'	=> array('id', 'class'),
     'tbody'	=> array('id', 'class'),
     'tfoot'	=> array('id', 'class'),
		
     'cut'		=> array('text', FALSE),
     'video'	=> array()
);

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

Затем нужно установить эти тэги, при помощи метода set_tags.

$html_filter->set_tags($tags);

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

$html_filter->del_invalid_tags(TRUE)

Все, наш фильтр настроен и можно им пользоваться.

$filtered_code = $html_filter->filter('Ваш HTML код');

Обратите внимание, на то, что фильтр работает с кодировкой UTF-8. Если вы используете CP1251, то сначала надо преобразовать код в UTF-8, затем прогнать его через фильтр, а после (полученный результат будет в UTF-8) перекодировать обратно в CP1251.

Вот список возможностей фильтра:

  • Экранирует или удаляет все недопустимые тэги.
  • Удаляет все недопустимые атрибуты тэгов.
  • Экранирует спец. символы HTML в атрибутах тэгов и в тексте.
  • Закрывает все незакрытые тэги.
  • Все тэги заключенные в конструкцию <code></code> рассматривает как простой текст.

Ссылки
Исходный код с примером
Демонстрация работы фильтра


Комментарии (20)

Волька
Отличный фильтр, легко приспособил его для фильтрации после Markdown, и вставил типограф. Возможно выпустить версию, работающую только с UTF-8 и не требующую iconv?
Ответить
Savvateev
Так фильтр и работает только с UTF-8.
Ответить
Вадим
При фильтрации после PHP Markdown есть один нюанс, который не позволяет использовать приведенный здесь фильтр: если вызвать Markdown("<info@pik-tv.com>"), то будет распечатано <a href="&#x6d;&#x61;&#105;&#108;t&#x6f;&#x3a;&#109;&#97;&#114;&#x6b;&#x65;&#116;&#105;&#110;&#x67;&#x40;&#x70;&#105;&#107;-&#x74;&#x76;&#46;&#99;o&#x6d;">&#109;&#97;&#114;&#x6b;&#x65;&#116;&#105;&#110;&#x67;&#x40;&#x70;&#105;&#107;-&#x74;&#x76;&#46;&#99;o&#x6d;</a>, а не <a href="mailto:info@pik-tv.com">info@pik-tv.com</a>, как предполагалось...

С точки зрения HTML, это полностью валидный код! Но этот код делает невозможным использование приведенного здесь фильтра, просто потому что фильтр заменяет & на &. Есть идеи как это побороть?

З.Ы. Думаю такая же ситуация с ссылками на домены в национальных зонах вроде .рф...
Ответить
Вадим
Вот, в этом фильтре этой ошибки нет: http://sourceforge.net/projects/kses/
Ответить
Волька
Упс, я ошибся, это в типографе используется iconv.
Ответить
borin
А можно сразу с чтоб ваш класс с windows-1251 работал?
Ответить
Savvateev
Класс предназначен только для работы с utf-8. Если хотите, можете его изменить под cp1251, но я лично в этом не вижу смысла.
Ответить
Ars
Пользовался классом, но почему-то он обрезает лишнее, т.е. <img src="http://site.com/img.png" onLoad="javascript:window.alert('12345')" ##++&^%$$# alt="картинка" title=qqqq32> он обрезает до: <img>
Ответить
Savvateev
Вообще так обрезаться не должно. Смотрите как работает фильтр на демо страничке. В вашем случае, скорее всего, причина в следующем. Данные в фильтр передаются из формы, например через POST, а в настройках PHP включен режим Magic Quotes. Этот режим экранирует кавычки, и вследствие этого фильтр не может обработать атрибуты тэгов. Чтобы отключить этот режим напишите в .htaccess:

php_flag magic_quotes_gpc off
php_flag magic_quotes_runtime off

Ответить
Ars
Большое спасибо, помогло. А насчет класса хорош.. сам пока на такое не способен)
Ответить
вася
вроде пашет
Ответить
не очень в php
Здравствуйте! А можно как-нибудь разрешить добавлять iframe только с определенного сайта?
Ответить
Savvateev
В данном фильтре такой возможности нет (т.е не предусмотрена возможность проверки аттрибутов тэгов). Нужно делать дополнительную проверку.
Ответить
не очень в php
А не могли бы Вы подсказать куда и как дописать дополнительную проверку?)
Ответить
Savvateev
Я имел в виду, что нужно делать проверку дополнительно от данного фильтра, своими силами (либо расширять мой класс). Конечно, без знаний PHP тут не обойтись. В более ранней версии фильтра, написанного на perl была возможность проверки аттрибутов, а в этой версии, я решил от нее отказаться.
Ответить
Эрик Акопян
Спасибо большое, сэкономили мне время :)
Ответить
Саша
Здравствуйте! Как сделать так чтобы не прописывать атрибуты? То есть чтобы разрешалось заполнять любые атрибуты какие захочу. Например: Ведь мало ли какие атрибуты появятся у ютуб
Ответить
Savvateev
Этот фильтр я писал сто лет назад. На самом деле есть более лучшие решения. Посмотрите HTML Purifier. Надеюсь эта ссылка окажется полезной.
Ответить
Арчик
Отличный класс, автору респект огромный. Сэкономил мне время и деньги. Сейчас дописываю возможность отключения фильтрации по тэгам в админке ЦМСки... не скажу какой, я ее только разрабатываю, скоро представлю в свет, и еще много полезных свойств уже дописал к этому классу.
Ответить
Анатолий
Спасибо, класс работает как нужно.
Ответить


Оставить свой комментарий


Представтесь, пожалуйста *

Ваш комментарий

Число на картинке *

captcha

На хостинг