В PHP это самый быстрый и простой способ удалить все теги HTML из строки, кроме тех, которые находятся в разрешенном списке, но путем удаления всех атрибутов HTML.
Встроенная функция strip_tags справилась бы с этой задачей, но атрибуты тегов в разрешенном списке сохраняются.
Я не знаю, является ли использование регулярных выражений лучшим способом, и я также не знаю, не будет ли анализ строки жадным.
Извините, но я не могу понять решение, которое вы предложили. Разве это не было бы так же, как если бы я просто использовал strip_tags с разрешенными тегами? Также не могли бы вы объяснить, почему вы не используете strip_tags из соображений безопасности?
В коде WordPress имеется проверенный в боевых условиях очиститель HTML FWIW. Developer.wordpress.org/reference/functions/wp_kses
В этом вопросе отсутствует минимальный воспроизводимый пример и попытка кодирования.






Регулярное выражение может привести к сбою, если атрибут имеет > в качестве значения атрибута.
Более безопасным способом было бы использовать DomDocumment, но учтите, что входные данные должны быть действительными HTML, а выходные данные могут быть стандартизированы.
<?php
$htmlString = '<span>777</span><div class = "hello">hello <b id = "12">world</b></div>';
$stripped = strip_tags($htmlString, '<div><b>');
$dom = new DOMDocument; // init new DOMDocument
$dom->loadHTML($stripped); // load the HTML
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//@*');
foreach ($nodes as $node) {
$node->parentNode->removeAttribute($node->nodeName);
}
$cleanHtmlString = '';
foreach ($dom->documentElement->firstChild->childNodes as $node) {
$cleanHtmlString .= $dom->saveHTML($node);
}
echo $cleanHtmlString;
Выход:
<p>777</p>
<div>hello <b>world</b>
</div>
Я собирался написать аналогичное решение, но стоит ли мне беспокоиться о стоимости производительности? Если, например, анализируется несколько строк HTML различной длины, будет ли это тем или иным образом наказываться?
Я думаю, что буду использовать это решение с системой кэширования.
Прежде всего, strip_tags не предотвращает XXS-атаки, поэтому с точки зрения безопасности я бы не рекомендовал его, см. здесь.
Однако вот пример решения, которое я предложил в комментариях. Хитрость заключается в том, чтобы использовать специальный символ для экранирования разрешенных тегов. Это простое решение: вы можете просто использовать strip_tags.
$string = '<b class = "hello">Hello, </b><a>world!</a>';
$allowed = array(
'b' => chr(1) . 'b_open',
'/b' => chr(1) . 'b_close',
'i' => chr(1) . 'i_open',
'/i' => chr(1) . 'i_close',
);
// Remove your special character from the input to prevent it from being injected
$result = str_replace(chr(1), '', $string);
// Escape the valid tags
foreach ($allowed as $tag => $replacement) {
$result = preg_replace('/<' . str_replace('/', '\/', $tag) . '([^>]*?)>/i', $replacement, $result);
}
// Call strip_tags
$result = strip_tags($result);
// Replace back
foreach ($allowed as $tag => $replacement) {
$result = str_replace($replacement, '<' . $tag . '>', $result);
}
echo($result);
Спасибо за разъяснения, но, по моему мнению, strip_tags не предотвращает XSS-атаки, только если вы используете второй параметр, поскольку, как я уже говорил в своем вопросе, он не удалит атрибуты из разрешенного списка, что и является сутью моего вопроса. . И еще раз извините, но я не совсем понимаю цель того, что вы предложили. Кроме того, предоставленный вами код не обрабатывает атрибуты HTML. Так что же мне не хватает?
@KlaxCuy Если функциональность атрибута важна, я добавил это. Но, как было указано, в некоторых случаях регулярное выражение может дать сбой. Это возможное решение, в котором специально используется strip_tags с меньшей сложностью.
Очень хакерское, но простое решение — заменить теги, которые вы хотите сохранить, замещающим символом или строкой, а затем вызвать
strip_tags. После этого замените разрешенные теги обратно. Но из соображений безопасности я бы вообще не использовалstrip_tags, если только ввод не проверен иным образом.