Удалить все атрибуты кроме (php)

To strip tags with HTMLParser, you have to run it multiple times.

It’s easy to circumvent the top answer to this question.


Look at this string (source and discussion):

The first time HTMLParser sees it, it can’t tell that the is a tag. It looks broken, so HTMLParser doesn’t get rid of it. It only takes out the , leaving you with

This problem was disclosed to the Django project in March, 2014. Their old was essentially the same as the top answer to this question. basically runs it in a loop until running it again doesn’t change the string:

Of course, none of this is an issue if you always escape the result of .

Update 19 March, 2015: There was a bug in Django versions before 1.4.20, 1.6.11, 1.7.7, and 1.8c1. These versions could enter an infinite loop in the strip_tags() function. The fixed version is reproduced above. More details here.

html_remove_attributes

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

$text — HTML-текст, который надо обработать;

$allowed — список разрешенных тегов.

<?php

/** * @param string $text текст в котором надо удалить теги * @param array $allowed список разрешенных тегов * * @return mixed */ function html_remove_attributes($text, $allowed = []) { $attributes = implode(‘|’, $allowed); $reg = ‘/(<+)(*)(>)/i’; $text = preg_replace_callback( $reg, function ($matches) use ($attributes) { // Если нет разрешенных атрибутов, возвращаем пустой тег if (!$attributes) { return $matches . $matches; }

$attr = $matches; $reg = ‘/(‘ . $attributes . ‘)=»*»/i’; preg_match_all($reg, $attr, $result); $attr = implode(‘ ‘, $result); $attr = ($attr ? ‘ ‘ : ») . $attr;

return $matches . $attr . $matches; }, $text );

return $text; }

Good things to copy or use

My example code doesn’t handle HTML entities — the Django and MarkupSafe packaged versions do.

My example code is pulled from the excellent MarkupSafe library for cross-site scripting prevention. It’s convenient and fast (with C speedups to its native Python version). It’s included in Google App Engine, and used by , Mako, Pylons, and more. It works easily with Django templates from Django 1.7.

Django’s strip_tags and other html utilities from a recent version are good, but I find them less convenient than MarkupSafe. They’re pretty self-contained, you could copy what you need from this file.

If you need to strip almost all tags, the Bleach library is good. You can have it enforce rules like «my users can italicize things, but they can’t make iframes.»

Understand the properties of your tag stripper! Run fuzz tests on it! Here is the code I used to do the research for this answer.

Why can’t I just strip the tags and leave it?

It’s one thing to keep people from things, without leaving s floating around. But it’s another to take arbitrary input and make it completely harmless. Most of the techniques on this page will leave things like unclosed comments () and angle-brackets that aren’t part of tags () intact. The HTMLParser version can even leave complete tags in, if they’re inside an unclosed comment.

What if your template is ? and will be let through by every tag stripper on this page (except @Medeiros!), because they’re not complete tags on their own. Stripping out normal HTML tags is not enough.

Django’s , an improved (see next heading) version of the top answer to this question, gives the following warning:


Follow their advice!

Пример

Например у нас есть HTML-файл (test_file.html) следующего содержания:

<!DOCTYPE html> <html> <head> <title>Таблица</title> </head> <body onload=»alert(‘html_remove_attributes (PHP)’)»> <table class=»my-table» style=»border-collapse: collapse; border: 1px solid;» cellpadding=»5″ cellspacing=»5″> <tr class=»row» id=»header»> <td style=»font-weight: bold;»>Идентификатор</td> <td style=»font-weight: bold;»>Имя</td> </tr> <tr class=»row» id=»row_1″ style=»background-color: #DDDDDD»> <td>1</td> <td>Андрей</td> </tr> <tr class=»row» id=»row_2″ style=»background-color: #FFFFFF»> <td>2</td> <td>Артем</td> </tr> <tr class=»row» id=»row_3″ style=»background-color: #DDDDDD»> <td>3</td> <td>Александр</td> </tr> <tr class=»row» id=»row_4″ style=»background-color: #FFFFFF»> <td>4</td> <td>Ева</td> </tr> <tr class=»row» id=»row_5″ style=»background-color: #DDDDDD»> <td>5</td> <td>Алексей</td> </tr> </table> </body> </html>

Удаление всех тегов кроме class

Удалим все теги из текста, кроме тега class.

<?php

// Получаем текст файла $content = file_get_contents(‘test_file.html’);

// Обрабатываем $content = html_remove_attributes($content, );

// Выводим echo ‘<pre>’; echo htmlspecialchars($content); echo ‘</pre>’;

Результат

В результате на экране будет выведено следующее:

<!DOCTYPE html> <html> <head> <title>Таблица</title> </head> <body> <table class=»my-table»> <tr class=»row»> <td>Идентификатор</td> <td>Имя</td> </tr> <tr class=»row»> <td>1</td> <td>Андрей</td> </tr> <tr class=»row»> <td>2</td> <td>Артем</td> </tr> <tr class=»row»> <td>3</td> <td>Александр</td> </tr> <tr class=»row»> <td>4</td> <td>Ева</td> </tr> <tr class=»row»> <td>5</td> <td>Алексей</td> </tr> </table> </body> </html>

Если необходимо удалить все теги, вызываем следующим образом: $result = html_remove_attributes($content, []);

Поиск текста функцией «preg_match_all»

Для поиска текста внутри тегов воспользуемся функцией «preg_match_all». Зададим маску поиска и посмотрим, что она возвращает в качестве результата.

$sContent = "... <xx>наташа</xx> ... <xx>даша</xx> ... <xx>настя</xx> ...";
if (preg_match_all('|<xx>(.+)</xx>|isU', $sContent, $arr)) { 
  echo $arr . " " . $arr . " " . $arr . "<br />";
  echo $arr . " " . $arr . " " . $arr;
}

//на выходе получаем:
//<xx>наташа</xx> <xx>даша</xx> <xx>настя</xx>
//наташа даша настя

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

Функция preg_match_all возвращает «1» в случае нахождения в тексте соответствия с указанной маской или «0», если соответствий не найдено. В качестве параметров принимает маску, строку где ищем и переменную, в которую будут записаны найденные совпадения.

Маска поиска обрамляется символами «|». За ними идут директивы — «isU» обозначает регистронезависимый поиск в многострочном тексте с кодировкой «UTF-8»

|<xx>(.+)</xx>|isU

В самом правиле содержатся теги, между которыми требуется заменить текст — «(.+)». Точка символизирует любой символ, а плюс — что он может повторяться один или больше раз. Скобки говорят о том, что содержимое между ними нужно записать в переменную с результатом.

Использование нумирации в заменах и другие продвинутые возможности

Теперь немного о продвинутых возможностях функции «preg_replace_callback». Ранее я упоминал что у неё есть два необязательных параметра. Первый (по умолчанию равен «-1») содержит максимальное количество замен, которое должна произвести функция. Второй — переменная, в которую будет записано количество произведенных замен.

$sContent = preg_replace_callback('|(<xx>)(.+)(</xx>)|iU', 
    function($matches){ //тут код }
,$sContent,2,$count);

Задав эти два параметра в предыдущем примере, замена главной буквы будет произведена только у первых двух имён. Соответственно, переменная «$count» будет содержать — 2. Если установить первый дополнительный параметр в «-1», то «$count» будет — 3.

И в конце о том, как узнать какая по счету замена происходит в данный момент. Это может потребоваться если появилась необходимость произвести замену между пятым и десятым найденным элементом строки или требуется для каких-то тегов прописать уникальные идентификаторы.

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

<?php
$str = '<h2>Марина</h2> <b>Алёша</b> <h2>Наташа</h2> <h2>Катя</h2>';

$str = preg_replace_callback('|<h2>(.+)</h2>|iU', function($matches){
	static $id = 0;
	$id++;
	return '<h2 id="uniq-'.$id.'">'.$matches.'</h2>';
}, $str,-1,$count);

echo $str.' Количество замен: '.$count;
?>

Объявляя статическую переменную нужно помнить что она сохраняет своё значение между вызовами функции, поэтому идеально подходит для решения нашей задачи.

Описание

htmlspecialchars

В HTML некоторые символы имеют специальное значение и для

сохранения своего значения должны быть преобразованы в HTML сущности.

Эта функция возвращает строку, над которой проведены некоторые из


таких преобразований. Этих преобразований достаточно для большинства

задач веб-программирования. Если вам нужно преобразовать все

возможные сущности, используйте htmlentities().

Эта функция полезна при отображении данных, введенных пользователем,

которые могут содержать нежелательные HTML тэги, например в форуме

или гостевой книге. Необязательный второй аргумент

quote_style определяет режим обработки

одиночных и двойных кавычек.

В режиме по умолчанию, ENT_COMPAT, преобразуются

двойные кавычки, одиночные остаются без изменений. В режиме

ENT_QUOTES преобразуются и двойные, и одиночные

кавычки. а в режиме ENT_NOQUOTES и двойные, и

одиночные кавычки остаются без изменений.

Производятся следующие преобразования:

  • ‘&’ (амперсанд) преобразуется в ‘&amp;’

  • ‘»‘ (двойная кавычка) преобразуется в ‘&quot;’ when ENT_NOQUOTES

    is not set.

  • »’ (одиночная кавычка) преобразуется в ‘&#039;’ только в

    режиме ENT_QUOTES.

  • ‘<‘ (знак «меньше чем») преобразуется в ‘&lt;’

  • ‘>’ (знак «больше чем») преобразуется в ‘&gt;’

Пример 1. Пример использования htmlspecialchars()

Обратите внимание, что функция не производит других преобразований

кроме описанных выше. Для преобразования всех HTML сущностей

используйте htmlentities(). Поддержка


необязательного второго аргумента была добавлена в PHP 3.0.17 и PHP

4.0.3.

Необязательный третий аргумент charset

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

используется кодировка ISO-8859-1. Поддержка этого аргумента была

добавлена в PHP 4.1.0.

Начиная с PHP 4.3.0 поддерживаются следующие кодировки.

Таблица 1. Поддерживаемые кодировки

Кодировка Псевдонимы Описание
ISO-8859-1 ISO8859-1

Западно-европейская Latin-1

ISO-8859-15 ISO8859-15

Западно-европейская Latin-9. Добавляет знак евро, французские и

финские буквы к кодировке Latin-1(ISO-8859-1).

UTF-8  

8-битная Unicode, совместимая с ASCII.

cp866 ibm866, 866

Кириллическая кодировка, применяемая в DOS.

Поддерживается в версии 4.3.2.

cp1251 Windows-1251, win-1251, 1251

Кириллическая кодировка, применяемая в Windows.

Поддерживается в версии 4.3.2.

cp1252 Windows-1252, 1252

Западно-европейская кодировка, применяемая в Windows.

KOI8-R koi8-ru, koi8r

Русская кодировка.

Поддерживается в версии 4.3.2.

BIG5 950

Традиционный китайский, применяется в основном на Тайване.

GB2312 936

Упрощенный китайский, стандартная национальная кодировка.

BIG5-HKSCS  

Расширенная Big5, применяемая в Гонг-Конге.

Shift_JIS SJIS, 932

Японская кодировка.

EUC-JP EUCJP

Японская кодировка.

См. также описание функций get_html_translation_table(),

strip_tags(), htmlentities()

и nl2br().

Обработка и замена при помощи «preg_replace_callback»

Переходим к самому интересному. Если нужно над найденным фрагметом произвести какие-то действия и только потом осуществить замену, то следует использовать «preg_replace_callback». Рассмотрим как с помощью этой функции в именах сделать первую букву заглавной.

<html>
<head> <meta charset="utf-8"> </head>
<body>

<?php 
$sContent = "<xx>наташа</xx> ... <xx>даша</xx> ... <xx>настя</xx>";

echo htmlspecialchars($sContent); echo "<br />";

$sContent = preg_replace_callback('|(<xx>)(.+)(</xx>)|iU', function($matches){
	$matches = mb_substr(mb_strtoupper($matches, 'UTF-8'),0,1,'UTF-8').substr($matches, 2);
	return $matches.$matches.$matches;
}
,$sContent);

echo htmlspecialchars($sContent);
?>

</body>
</html>

В качестве параметров передаём маску поиска, функцию с кодом обработки и строковую переменную в которой осуществляем поиск. Дополнительно могут ещё быть заданы два необязательных параметра. О них в следующем разделе статьи.

Переменная «$matches» это массив, содержащий элементы регулярного выражения. В нулевом элементе будет содержаться вся исходная строка, а в остальных — содержимое скобок.

Код обработки не описываю, но отмечу что для замены первой буквы на заглавную я использую PHP функции для работы со строками в UTF-8 кодировке. Если у Вас кодировка cp1251, то нужно отбросить префикс «mb_» и удалить последний параметр у функций.

ВНИМАНИЕ! Код в примере будет работать только при использовании PHP версии 5.3 и выше. Для более поздних версий требуется доработка


С этим читают