Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
PHP 5/6. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В. Объектно-ориентированное программирование на PHP. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум Регулярные Выражения

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Очистить html от лишних тегов и атрибутов
 
 автор: Eugene77   (17.01.2008 в 15:15)   письмо автору
 
 

Вот есть список допустимых тегов и допустимых атрибутов.
Как отбросить все остальные теги и атрибуты?

$AllowedTags = array("a", "b", "blink", "blockquote", "br", "caption", "center", "col", "colgroup", "comment",
"em", "font", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "img", "li", "marquee", "ol", "p", "pre", "s",
"small", "span", "strike", "strong", "sub", "sup", "table", "tbody", "td", "tfoot", "th",
"thead", "tr", "tt", "u", "ul");


$AllowedAttr = array("abbr", "align", "alt", "axis", "background", "behavior", "bgcolor", "border", "bordercolor",
"bordercolordark", "bordercolorlight", "bottompadding", "cellpadding", "cellspacing", "char",
"charoff", "cite", "clear", "color", "cols", "direction", "face", "font-weight", "headers",
"height", "href", "hspace", "leftpadding", "loop", "noshade", "nowrap", "point-size", "rel",
"rev", "rightpadding", "rowspan", "rules", "scope", "scrollamount", "scrolldelay", "size",
"span", "src", "start", "summary", "target", "title", "toppadding", "type", "valign",
"value", "vspace", "width", "wrap");

   
 
 автор: Loki   (17.01.2008 в 16:12)   письмо автору
 
   для: Eugene77   (17.01.2008 в 15:15)
 

Как вариант, воспользоваться каким-нибудь xml парсером, а потом собрать документ обратно использую только разрешенные теги и аттрибуты.

Ну или просто брать все что внутри <>, выбирать оттуда все что имеет структуру attr="var" и выкидывать все что не проходит проверку.

   
 
 автор: Eugene77   (17.01.2008 в 20:57)   письмо автору
 
   для: Loki   (17.01.2008 в 16:12)
 

C xml парсером - это пока мне не понятно.
Может быть ссылочку подкинете?

А вот регулярные выражения что-то туго подбираются.
Для простоты я разбил на унарные теги и двойные:

<?
$AllowedTags1 
= array("br""col""hr""img");

$AllowedTags2 = array("a""b""blink""blockquote""caption""center""col""colgroup",
                      
"em""font""h1""h2""h3""h4""h5""h6""hr""li""marquee""ol""p""pre""s",
                      
"small""span""strike""strong""sub""sup""table""tbody""td""tfoot""th",
                      
"thead""tr""tt""u""ul");


$AllowedAttr = array("abbr""align""alt""axis""background""behavior""bgcolor""border""bordercolor",
                      
"bordercolordark""bordercolorlight""bottompadding""cellpadding""cellspacing""char",
                      
"charoff""cite""clear""color""cols""direction""face""font-weight""headers",
                      
"height""href""hspace""leftpadding""loop""noshade""nowrap""point-size""rel",
                      
"rev""rightpadding""rowspan""rules""scope""scrollamount""scrolldelay""size",
                      
"span""src""start""summary""target""title""toppadding""type""valign",
                      
"value""vspace""width""wrap");



$t1='/<['.implode('|',$AllowedTags1).'].*>/i';
$t2='/<('.implode('|',$AllowedTags2).')([\s\t\n]*)(.*)([\s\t\n]*)>(.*)<\/('.implode('|',$AllowedTags2).')([\s\t\n]*)>/is';
$a='['.implode ('|',$AllowedAttr).']';
function 
ins($match){
    echo 
'<br>';
    echo 
htmlspecialchars($match[0]);

preg_replace_callback($t2'ins'$html);


В принципе, такая функция вычленяет теги и если её вызывать рекурсивно, то наверно и с вложенностью можно разобраться, но кажется мне, что я не на верном пути. Слишком уж замысловато...

   
 
 автор: kasmanaft   (17.01.2008 в 21:28)   письмо автору
 
   для: Eugene77   (17.01.2008 в 20:57)
 

$t1='/<['.implode('|',$AllowedTags1).'].*>/i'; - это выражение у Вас получилось "жадным". Вследствие чего, под .* попадет как можно больше символов. Т.е. из "text <br> text <br> text" под .* попадет "> text <br". Добавте модификатор U или "?" (квантификатор) после .*

$t2='/<('.implode('|',$AllowedTags2).')([\s\t\n]*)(.*)([\s\t\n]*)>(.*)<\/('.implode('|',$AllowedTags2).')([\s\t\n]*)>/is';
Здесь аналогичные проблемы с жадностью... И некоторые поправки:
([\s\t\n]*)(.*)([\s\t\n]*) во-первых, \s содержит в себе и \t, и \n. Т.е. достаточно \s*. Ну и во-вторых, под вторую ([\s\t\n]*) ничего не попадет из-за жадной .*
Вот так правильнее будет, наверное: $t2='/<('.implode('|',$AllowedTags2).')(.*?)>(.*?)<\/\\1\s*>/is';

$a='['.implode ('|',$AllowedAttr).']'; - только с круглыми скобками по краям... Правда толку от этого выражения не будет, наверное...

   
 
 автор: Eugene77   (18.01.2008 в 17:56)   письмо автору
 
   для: kasmanaft   (17.01.2008 в 21:28)
 

Спасибо за совет!
Только он всех проблем не решает.
Ведь вложенность тегов никто не отменял.
Значит определённыя жадность мне на пользу : )
С другой стороны, со своей жадностью я вылетаю за пределы отдельных тегов.
То есть если пойти таким путём, то придётся чередовать жадные и не жадные запросы, сравнивать результаты и рекурсивно вызывать функцию.

Пар из ушей гарантирован.

Тут видно не тот подход я выбрал. Надо смотреть куда-то в сторону XML & XSLT.

Пока ничего не нашёл подходящего, хотя книги в поиске встречаются, читать целые книги мне сейчас некогда.
А статьи приводят примеры слишком далёкие от моей задачки.

   
 
 автор: kasmanaft   (18.01.2008 в 18:54)   письмо автору
 
   для: Eugene77   (18.01.2008 в 17:56)
 

>> Ведь вложенность тегов никто не отменял.
А вообще-то.... закрывающие теги Вам и не нужны, наверное. Обработать сначала открывающие, а там, если надо, и с закрывающими можно что-нибудь наделать....

PS С помощью рег. выражений можно и вложенные теги обойти с помощью рекурсии (именно рекурсивных рег. выражений (?R) ). Но это не лучшее решение судя по всему...

   
 
 автор: Eugene77   (19.01.2008 в 18:44)   письмо автору
 
   для: kasmanaft   (18.01.2008 в 18:54)
 

>А вообще-то.... закрывающие теги Вам и не нужны, наверное. Обработать сначала открывающие, а там, если надо, и с закрывающими можно что-нибудь наделать....
>
Так будет проще, конечно.
Вообще реальный выриант...
Но что-то я боюсь его использовать. Мнится мне в нём какая-то опасность, уязвимость.
Разные браузеры будут по-разному реагировать но нарушения в порядке тегов. Через это можно запустить какой угодно код вредоносный в некоторые из браузеров.
Впрочем, можно решить проблему, проверив в начале нет ли нарушения в порядке следования тегов. Тогда уже смело можно всё распарсить.

Как бы такую проверочку изобрести?
То есть как проверить что внутри каждого тега только пары парных тегов?

Может быть, как раз ваша рекурсия и подойдёт:

>PS С помощью рег. выражений можно и вложенные теги обойти с помощью рекурсии (именно рекурсивных рег. выражений (?R) ). Но это не лучшее решение судя по всему...

У вас нет на примете статьи по рекурсивным рег. выраж.?

   
 
 автор: kasmanaft   (22.01.2008 в 18:41)   письмо автору
 
   для: Eugene77   (19.01.2008 в 18:44)
 

>> Разные браузеры будут по-разному реагировать но нарушения в порядке тегов.
Ну это другой вопрос.. Порядок тегов можно и без этого всего нарушить. Главное его не нарушить, удаляя лишние теги :)
Но это не проблема, вроде как: удаляя атрибуты порядок тегов не нарушите, удаляя запрещенные теги, удалите и закрывающие..

> Через это можно запустить какой угодно код вредоносный в некоторые из браузеров.
Это врядли.. Вы код для чего чистите? Ничего опасного туда проникнуть не должно, вроде.

> У вас нет на примете статьи по рекурсивным рег. выраж.?
Нет, рекурсию вообще-то не часто используют (тут на форуме так вообще ни одного примера не встречал).. Наверное, поэтому и статей нет... Хотя, я не интересовался. (сам по мануалу разобрался на php.net)

> Как бы такую проверочку изобрести?
>То есть как проверить что внутри каждого тега только пары парных тегов?
>Может быть, как раз ваша рекурсия и подойдёт:
Нет, тут рекурсию вряд ли возможно прикрутить.. С помощью нее удобно выдрать парный тег, а проверить все ли они парные, думаю, не получится.
Вот так, наверное, можно сделать: удалять постепенно самые вложенные теги, внутри которых нет других тегов.. удалять, удалять.. пока есть чего. Потом: остался какой из тегов (открывающий/закрывающий) - значит теги были расставлены неверно. Единственное: придется удалить перед этим непарные теги.
Если проводить эту процедуру только при обновлении записи, нагрузки будут не очень большие, наверное....
Приблизительно так можно выдрать самый вложенный тег:
#<([a-z]+)[^>]*>((?!</?[a-z]+[^>]*>).)*?</\\1[^>]*>#is (не проверял)

   
 
 автор: Eugene77   (23.01.2008 в 19:41)   письмо автору
 
   для: kasmanaft   (22.01.2008 в 18:41)
 

Да, такое выражение решало бы мою проблему.
(Остальное я, кажется, сам всилах дописать)

Только вот не понимаю я вашей регулярки #<([a-z]+)[^>]*>((?!</?[a-z]+[^>]*>).)*?</\\1[^>]*>#is
Объясните, пожалуйста, как работает: ((?!</?[a-z]+[^>]*>).)*?

   
 
 автор: kasmanaft   (24.01.2008 в 13:35)   письмо автору
 
   для: Eugene77   (23.01.2008 в 19:41)
 

<([a-z]+)[^>]*> - с этим, наверное, нет вопросов?..


(?!str) - три символа после текущего должны быть не "str".

(?!</?[a-z]+[^>]*>) - аналогично: некоторое количество символов после текущего не должны подходить под этот шаблон. То есть не: "<", после которой, возможно, "/", обязательно несколько букв, возможно, несколько "не >" и, наконец, закрывающая ">". Иначе говоря, строка после текущего символа не должна быть тегом.
. - и после всего этого любой символ (который "не тег").

*? - произвольное, минимально возможное, количество символов (которые "не тег" :) ).

</\\1[^>]*> - закрывающий тег (\\1).

   
 
 автор: Eugene77   (24.01.2008 в 20:53)   письмо автору
 
   для: kasmanaft   (24.01.2008 в 13:35)
 

Нет, не работает
<?
$html 
'<td>&nbsp;<td></td>';
$expr '#<([a-z]+)[^>]*>((?!</?[a-z]+[^>]*>).)*?</\\1[^>]*>#is';
$r preg_replace($expr''$html);
echo 
$r;

Даёт пустую строку.

   
 
 автор: kasmanaft   (24.01.2008 в 20:59)   письмо автору
 
   для: Eugene77   (24.01.2008 в 20:53)
 

Хм.. у меня "<td>&nbsp;"

   
 
 автор: Eugene77   (25.01.2008 в 19:34)   письмо автору
 
   для: kasmanaft   (24.01.2008 в 20:59)
 

Прошу прощения, что-то не то ляпнул!
Вот что даёт пустую строку:
$html = '<td>&nbsp;</tr>';

   
 
 автор: kasmanaft   (25.01.2008 в 20:14)   письмо автору
 
   для: Eugene77   (25.01.2008 в 19:34)
 

А что оно должно давать? :)

Если хотите "самый вложенный тег" выбрать, используйте preg_match()..

   
 
 автор: Eugene77   (26.01.2008 в 20:34)   письмо автору
 
   для: kasmanaft   (25.01.2008 в 20:14)
 

>А что оно должно давать? :)
>
>Если хотите "самый вложенный тег" выбрать, используйте preg_match()..

Вероятно я что-то не понял, но строка вроде как не соответствует шаблону.
Закрыающий и открывающий теги различны. Поэтому оно не должно было бы быть затронуто функцией. Вот я и сделал вывод, что выражение работает не так как ожидалось.

То есть я ожидал, что при каждом применении preg_replace к строке, из строки будут исчезать самые вложенные теги, но лишь те, которые действительно парные, а не разные.

   
 
 автор: kasmanaft   (27.01.2008 в 14:53)   письмо автору
 
   для: Eugene77   (26.01.2008 в 20:34)
 

Упс, прошу прощения, не доглядел... Всё верно, это глюк.

Получилось что в этом выражении: <([a-z]+)[^>]*>; под [a-z]+ попали не все буквы, а часть попала под [^>]*. То есть "t" у тегов совпали, оно решило, что теги одинаковые...

Можно вот так испраить выражение: #<([a-z]+)\b[^>]*>((?!</?[a-z]+[^>]*>).)*?</\\1\b[^>]*>#is

\b означает границу "слова", что гарантирует, что теги больше рваться не будут.

   
 
 автор: Eugene77   (27.01.2008 в 20:33)   письмо автору
 
   для: kasmanaft   (27.01.2008 в 14:53)
 

Ура!
Торжество КА[смических технологий теперь не вызывает сомнений!

Только я не понял зачем b во втором случае?!

   
 
 автор: kasmanaft   (27.01.2008 в 21:05)   письмо автору
 
   для: Eugene77   (27.01.2008 в 20:33)
 

:)

Да всё ради того же... Будет, например, открывающий тег "a" и закрывающий "applet". Опять та же бяка будет ("pplet" попадеть под [^>]*).

   
 
 автор: kasmanaft   (28.01.2008 в 09:40)   письмо автору
 
   для: kasmanaft   (27.01.2008 в 21:05)
 

Ещё маленькая поправка: забыл про теги h1, h2 и др... в общем, к [a-z]+ еще надо бы цифры добавить ([a-z0-9]+).

PS спецификация еще "_" разрешает.. может быть, и его туда же.

   
 
 автор: Eugene77   (28.01.2008 в 17:30)   письмо автору
 
   для: kasmanaft   (28.01.2008 в 09:40)
 

>Ещё маленькая поправка: забыл про теги h1, h2 и др... в общем, к [a-z]+ еще надо бы цифры добавить ([a-z0-9]+).
Здорово! И я проглядел.
>
>PS спецификация еще "_" разрешает.. может быть, и его туда же.
Мне не надо все теги. Хотя в каких тегах есть "_"? =О

Вот так пишу:
function check_pair_tegs($html){
    $singlets = array("br", "hr", "img");
              $html = preg_replace('#</?('.implode('|', $singlets).')(\s+.*|\s*)>#isU', '', $html);
    $expr = '#<([a-z][a-z1-9]+)\b[^>]*>((?!</?[a-z]+[^>]*>).)*?</\\1\b[^>]*>#is';
    while($html != $html1 = preg_replace($expr, '', $html)) $html = $html1;
    if($html=='') return true; else return false;
}


Но почему-то пропускает < br> и даже <_br>

   
 
 автор: kasmanaft   (28.01.2008 в 19:00)   письмо автору
 
   для: Eugene77   (28.01.2008 в 17:30)
 

В каком смысле пропускает?

var_dump(check_pair_tegs("<td>s</td>")); - true
var_dump(check_pair_tegs("<td> <br> </td>")); - true
var_dump(check_pair_tegs("<td> <brrr> </td>")); - false
var_dump(check_pair_tegs("<br> <br>")); - false, потому что после замены остается " " (а не пустая строка)
var_dump(check_pair_tegs("<a></a>")); - false, потому что после буквы "a" нет обязательных букв/цифр ([a-z][a-z1-9]+)

А "< br>", "<_br>" не являются HTML тегами.. заменять их ни на что не надо.

PS всё же tag, а не teg.

   
 
 автор: Eugene77   (28.01.2008 в 20:19)   письмо автору
 
   для: kasmanaft   (28.01.2008 в 19:00)
 

var_dump(check_pair_tags("<td><_img></td>")); -true
var_dump(check_pair_tags("<td>< img></td>")); -true
Вот это меня и смущает
Тоесть пробел или символ подчёркивания перед именем непарного тега не выдаёт мне ошибки, хотя это должно быть ошибкой. Загадка!

Насчёт teg -извините, я думал в касмосе, как раз-таки tag не актуален : )

   
 
 автор: kasmanaft   (28.01.2008 в 20:28)   письмо автору
 
   для: Eugene77   (28.01.2008 в 20:19)
 

Почему это должно быть ошибкой?

Тег это: открывающая <, идентификатор (вроде они так зовутся), начинающийся с буквы, может содержить буквы,цифры,знак подчеркивания. Через пробел идут атрибуты, потом ">".

< img> - это не тег! и ваше выражение его попросту не трогает (а не заменяет).
что "<td>< img></td>", что "<td>blablabla</td>"...

PS я не касмонафт ;-)

   
 
 автор: Eugene77   (29.01.2008 в 17:47)   письмо автору
 
   для: kasmanaft   (28.01.2008 в 20:28)
 

>
>< img> - это не тег! и ваше выражение его попросту не трогает (а не заменяет).
>что "<td>< img></td>", что "<td>blablabla</td>"...
>
Если бы..
В том-то и дело, что трогает и удаляет, Иначе функция возвратила бы false!
True она возвращает только если удалось удалить всё начисто.

   
 
 автор: kasmanaft   (29.01.2008 в 18:50)   письмо автору
 
   для: Eugene77   (29.01.2008 в 17:47)
 

Она удаляет <td>..</td> и всё, что попало между ними. Попал не_тег ( =] ) "< img>" - удалила и его.

var_dump(check_pair_tags("< img>")) вернет false.. Всё верно.
var_dump(check_pair_tags("<img>")) - true....

   
 
 автор: Eugene77   (31.01.2008 в 17:10)   письмо автору
 
   для: kasmanaft   (29.01.2008 в 18:50)
 

Логично.
Спасибо!
Здорово помогли!
Ещё бы статью про "!?" порекомендовали...

   
 
 автор: kasmanaft   (01.02.2008 в 19:09)   письмо автору
 
   для: Eugene77   (31.01.2008 в 17:10)
 

Да, было бы совсем неплохо :))
Да только я сам не читал ни одной.... Мануал да Фридла чуть-чуть...
(Добавил: и форум! понимание приходит с практикой..)

Может быть, стоит вот это прочитать:
http://www.phpclub.ru/detail/article/regexp_1
http://www.phpclub.ru/detail/article/regexp_2

   
 
 автор: Eugene77   (10.02.2008 в 10:04)   письмо автору
 
   для: kasmanaft   (01.02.2008 в 19:09)
 

Начитавшись статей(спасибо за замечательные ссылки) я стал пробовать размышлять.
Но никак не пойму почему бы не упростить вашу регулярку, например до такого состояния:
'#(.*)<([a-z][a-z1-6]*)\b[^>]*>([^<>]*)</\\2\b[^>]*>(.*)#is'

?

   
 
 автор: kasmanaft   (10.02.2008 в 11:41)   письмо автору
 
   для: Eugene77   (10.02.2008 в 10:04)
 

В таком случае пользователи не смогут использовать "<>".
Ну, можете "попросить" их использовать &lt; &gt; .. А может вообще перебьются :)

Может быть, вручную заменить все "<>" (не являющиеся частью тегов) перед проверкой. Всё равно заменять ведь придется.. Так что можно и упростить выражение.

PS "(.*)" по краям - лишнее..

   
 
 автор: Eugene77   (12.02.2008 в 13:35)   письмо автору
 
   для: kasmanaft   (10.02.2008 в 11:41)
 

Да,пожалуй, я мог бы и сам догадаться.
Просто ещё не совсем привычные материи - поэтому мысли туго в голове шевелятся. Спасибо!
Лучше вашего варианта мне ничего не придумать!

   
 
 автор: rombikr   (07.02.2008 в 17:02)   письмо автору
 
   для: Eugene77   (17.01.2008 в 15:15)
 

Во так работает:

 
$h = fopen("http://marketing.rbc.ru/","r");
while (!feof ($h)) { 
$content = fgetss($h,1024,'<br><col><hr><img><h1></h1><h2></h2><h3></h3><h4></h4><h5>
</h5><h6></h6><a></a><b></b><blink></blink><blockquote></blockquote><caption>
</caption><center></center><col></col><colgroup></colgroup><em></em><font></font><hr>
</hr><li></li><marquee></marquee><ol></ol><p></p><pre></pre><s></s><small></small><span>
</span><strike></strike><strong></strong><sub></sub><sup></sup><table></table><tbody></tbody><td></td><tfoot></tfoot><th></th><thead></thead><tr></tr><tt></tt><u></u><ul></ul>'); 
echo $content;
  } 

   
 
 автор: Eugene77   (08.02.2008 в 18:48)   письмо автору
 
   для: rombikr   (07.02.2008 в 17:02)
 

Да, дальше уж не сложно...
Если парность тегов проверена, то лишние можно откинуть или так или strip_tags()
Ну а атрибуты регуляркой, но она совсем простая

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования