HTML вместо BB

Духовность™

Продвинутый новичок
с помощью xpath выдираем все тэги
а почему не DOM? Расскажите, а то я не знаю, что такое xpath!

-~{}~ 13.09.07 15:14:

triumvirat, основная проблема - необходимость полного анализа HTML кода на стороне сервера.
За работу ещё не брался, но идея такая:
Идём DOM-ом по всем тегам. Смотрим аттрибуты. Удаляем все не разрешённые. Все "онклики" удаляем в обязательном порядке. Если в аттрибуте href замечен протокол javascript - тупо трём содержимое атрибута и заменяем на #.

Удалять лишние теги как - не знаю ещё. Либо strip_tags использовать, либо тем же DOM-ом.


Сейчас проверил ЖЖ. Закрытие у них хромает:

Код:
<a href="#" onclick="alert(1)"><b>отрппр<b>ss<i>ssss
Код:
<a href="#"><b>отрппр<b>ss<i>ssss</a></b></b></i>
Возникает проблема незакрытых тегов. Если DOM не сможет правильно интерпретировать и загрузить в память структуру тегов, то мы не сможем удалить онклики. Это так, чисто предположения.
 

tashkentchi

Новичок
Сначала Тиди:
http://www.php.net/manual/ru/ref.tidy.php

Он избавит от проблем с неправильной вложенностью, неправильным регистром и т.п.

Затем уже ДОМ.

Автор оригинала: Qwerty
Лишнее доказательство, что визивиг - зло. :) Но, к сожалению, необходимое и вполне приемлемое для использования в админках. А посетителю - BB или его аналог в зубы.
Мне тоже ББКод больше нравится :) К сожалению не всем заказчикам он нравится также сильно :)

Автор оригинала: Qwerty
А проверять html на стороне сервера - можно, не не слишком ли сложно?
Если кто нибудь выложит открытый код для такой проверки, то она станет совсем несложной :)
 

ONK

Пассивист PHPСluba
tashkentchi, HTML надо не проверять, а автоматически приводить к приемлемому виду. Т.к. после попытки скопировать таблицу их MSword в визуальный редактор, пользователь сам никогда не добьётся того, чтобы HTML код сообщения прошёл проверку.
 

dark-demon

d(^-^)b
>а почему не DOM? Расскажите, а то я не знаю, что такое xpath!

xpath - это часть дома, позволяющая делать выборки нужных узлов

>Идём DOM-ом по всем тегам. Смотрим аттрибуты. Удаляем все не разрешённые.

в доме нет тэгов - есть только узлы дерева.

>Сначала Тиди Он избавит от проблем с неправильной вложенностью, неправильным регистром и т.п.

дом необходим и достаточен

ща тесткейс сделаю..
 

dark-demon

d(^-^)b
в данном случае нужно сделать с точностью до наоборот :) всмысле на выходе нужно получить не html-документ, а html-фрагмент

-~{}~ 13.09.07 21:53:

>после попытки скопировать таблицу их MSword в визуальный редактор, пользователь сам никогда не добьётся того, чтобы HTML код сообщения прошёл проверку.

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

tashkentchi

Новичок
http://www.php.net/manual/ru/function.tidy-get-body.php

Не думаю, что сложно получить фрагмент
 

tashkentchi

Новичок
Вот такую вещь:

<table></table><tr></tr>

твой фильтр превратил вот в такую:

<table/><tr/>
 

tashkentchi

Новичок
невидно правильного

код: <em>text1 <p>text2

стал: <em>text1 <p>text2</p></em>

-~{}~ 14.09.07 03:44:

Чтобы все работало правильно, немного изменим твой код (применим тиди):

PHP:
if ($data) {
    $data = preg_replace(array('|<\?.*?\?>|s', '|<!\[.*?\]\]>|s'), '', $data);
    $tidy = tidy_parse_string($data);
    $tidy->CleanRepair();
    $doc = new DOMDocument('1.0','utf-8');
    @$doc->loadHTML(tidy_get_output($tidy));
    $xpath = new DOMXPath($doc);
    $elems = $xpath->query('/html/body//*'); // remove all not allawed tags and attributes
    foreach ($elems as $el) {
        if (isset($allowed[$el->nodeName])) {
            foreach ($el->attributes as $attr):
                if (! in_array($attr->name, $allowed[$el->nodeName])) {
                    $el->removeAttributeNode($attr);
                }
            endforeach;
        } else {
            $par = $el->parentNode;
            while ($chi = $el->firstChild) {
                $par->insertBefore($chi, $el);
            }
            $par->removeChild( $el );
        }
    }
    $attrs = $xpath->query('//@href|//@src'); // anti-XSS
    foreach ($attrs as $attr) {
        if( preg_match( '|^\w*script:|si', $attr->value ) )
            $attr->value = uuuri('article:no_xss_please');
    }
    $data = $doc->saveXML();
    $data = preg_replace(array('|^.*?<body>|s', '|\s*</body>.*?$|s'), '', $data);
    $data = preg_replace(array('|&#13;|', '|&#xD;|'), '', $data);
    $data = preg_replace('|\n*$|s', '', $data);
}
Теперь хтмл: <table></table><tr></tr>

конвертится в:

<table><tr><td/>
</tr></table>

А хтмл: <em>text1 <p>text2

конвертится в:

<em>text1</em>
<p><em>text2</em></p>

Так лучше.
 

dark-demon

d(^-^)b
не, лучше ввести дополнительную настройку - какие теги внутри каких могут встречаться. встреченные не там - удаляются.

тогда можно будет вводить ограничения типа "нельзя внутри таблицы делать ещё одну таблицу" или "нельзя вешать ссылки на заголовки" или "нельзя вкладывать em в strong и наоборот" и тп
 

tashkentchi

Новичок
В этом случае, код: <em>text1 <p>text2

будет конвертиться в: <em>text1 text2</em>

Все таки так лучше:

<em>text1</em>
<p><em>text2</em></p>

Причем дополнительным настройкам это никак не помешает.
 

tashkentchi

Новичок
$data - это твой хтмл на входе.

Кроме того, тебе понадобится массив разрешенных тегов и атрибутов:

PHP:
$allowed= array (
		'a'=> array( 'href' ),
		'strong'=> array( ),
		'em'=> array( ),
		'img'=> array( 'src', 'alt' ),
		'p'=> array( ),
		'br'=> array( ),
		'table'=> array( ),
		'thead'=> array( ),
		'tbody'=> array( ),
		'tr'=> array( ),
		'th'=> array( ),
		'td'=> array('colspan','rowspan')
	);
В случае, если $data не пустая, нормализуем ее с помощью Tidy. Затем фильтруем с помощью DOM.

На выходе получается нормализованный и отфильтрованный хтмл в переменной $data

Более подробно копай сам
 

dark-demon

d(^-^)b
хорошо, убедил :) в контексте сабжа лучше воспользоваться тиди. в контексте визивига - пофиг.
 

peroon13

Новичок
Воспользовался вашим кодом, но вот незадача - на выходе русские символы превращаются в какую-то абракадабру.
Например строка "Test letter Тестовое письмо" превращается в
"Test letter
&#xD2;&#xE5;&#xF1;&#xF2;&#xEE;&#xE2;&#xEE;&#xE5;
&#xEF;&#xE8;&#xF1;&#xFC;&#xEC;&#xEE;"

Пробовал на входе отдавать в разных кодировках - ничего не спасало. Нет идей почему так происходит?

-~{}~ 22.11.07 14:35:

Пардон, на выходе получаю
"Test letter &amp;#xD2;&amp;#xE5;&amp;#xF1;&amp;#xF2;&amp;#xEE;&amp;#xE2;&amp;#xEE;&amp;#xE5;
&amp;#xEF;&amp;#xE8;&amp;#xF1;&amp;#xFC;&amp;#xEC;&amp;#xEE;"
 
Сверху