PHP — preg_replace — HTML-теги и атрибуты

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

вот мой пример:

$allowed=array("img", "p", "style");
$text='<img src = "image.gif" onerror = "myFunction()" style = "background:red" onclick = "myFunction()">

<p>A function is triggered if an error occurs when loading the image. The function shows an alert box with a text.
In this example we refer to an image that does not exist, therefore the onerror event occurs.</p>

<script>
function myFunction() {
  alert(\'The image could not be loaded.\');
}
</script>';

используя $text= preg_replace('#<script(.*?)>(.*?)</script>#is', '', $text); Я мог бы удалить тег script с содержимым, но мне нужно удалить все, что не входит в массив $allowed

Вы можете использовать этот минификатор HTML, который я написал, с небольшой доработкой его можно сделать для удаления определенных тегов. Он имеет возможность не минимизировать определенные теги. Таким образом, вы можете изменить это, удалив их (вероятно) github.com/ArtisticPhoenix/MISC/blob/master/Lexers/… Он использует регулярное выражение в стиле Lexer/Parser.

ArtisticPhoenix 12.03.2019 04:28

@ArtisticPhoenix ini_set('display_errors', 1); не следует использовать в производственных средах, возможно, вы захотите добавить комментарий в этот GIT.

user3783243 12.03.2019 04:32

На самом деле это не предназначено для производственного кода, на самом деле это был другой ответ здесь. Вот почему это в MISC. и это говорит //For debugging

ArtisticPhoenix 12.03.2019 04:34

Есть ли вложенные теги? например <div><p>text</p><img />more text<p>text</p></div>

Nick 12.03.2019 04:45

Да, содержимое из текстового редактора

ferhado 12.03.2019 04:47

Один из этих ответов решил вашу проблему? Если нет, не могли бы вы предоставить больше информации, чтобы помочь ответить на него? В противном случае, пожалуйста, подумайте о том, чтобы отметить принятый ответ, который лучше всего решил вашу проблему (галочка под стрелками вверх/вниз). См. stackoverflow.com/help/someone-answers

Nick 14.03.2019 03:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
6
114
3

Ответы 3

Я бы предложил использовать DOMParser для лучшей читаемости, если вы смешиваете скрипты с html в целом, как это, позаботьтесь о производительности, если производительность имеет значение.

http://php.net/manual/en/class.domdocument.php

Эта функция должна делать то, что вы хотите. Учитывая DOMDocument ($doc) и узел ($node) для поиска, он рекурсивно перебирает дочерние элементы этого узла, удаляя все теги, которых нет в массиве $allowed_tags, и для тех тегов, которые сохраняются, удаляя все атрибуты, которые не в массиве $allowed_attributes:

function remove_nodes_and_attributes($doc, $node, $allowed_tags, $allowed_attributes) {
    $xpath = new DOMXPath($doc);
    foreach ($xpath->query('./*', $node) as $child) {
        if (!in_array($child->nodeName, $allowed_tags)) {
            $node->removeChild($child);
            continue;
        }
        $a = 0;
        while ($a < $child->attributes->length) {
            $attribute = $child->attributes->item($a)->name;
            if (!in_array($attribute, $allowed_attributes)) {
                $child->removeAttribute($attribute);
                // don't increment the pointer as the list will shift with the removal of the attribute
            }
            else {
                // allowed attribute, skip it
                $a++;
            }
        }
        // remove any children as necessary
        remove_nodes_and_attributes($doc, $child, $allowed_tags, $allowed_attributes);
    }
}

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

$doc = new DOMDocument();
$doc->loadHTML("<html>$text</html>", LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$html = $doc->getElementsByTagName('html')[0];
remove_nodes_and_attributes($doc, $html, $allowed_tags, $allowed_attributes);
echo substr($doc->saveHTML(), 6, -8);

Вывод (для ваших образцов данных):

<img style = "background:red">
<p>A function is triggered if an error occurs when loading the image. The function shows an alert box with a text. In this example we refer to an image that does not exist, therefore the onerror event occurs.</p>

Демо на 3v4l.org

Использование DOMDocument — всегда лучший способ манипулировать HTML, он понимает структуру документа.

В этом решении я использую XPath для поиска любых узлов, которых нет в списке разрешенных, выражение XPath будет выглядеть примерно так...

//body//*[not(name() = "img" or name() = "p" or name() = "style")]

Это ищет любой элемент в теге <body> (loadHTML автоматически поместит этот тег для вас), имя которого отсутствует в списке разрешенных тегов. XPath строится динамически из списка $allowed, поэтому вы просто меняете список тегов, чтобы обновить его...

$allowed=array("img", "p", "style");
$text='<img src = "image.gif" onerror = "myFunction()" style = "background:red" onclick = "myFunction()">

<p>A function is triggered if an error occurs when loading the image. The function shows an alert box with a text.
In this example we refer to an image that does not exist, therefore the onerror event occurs.</p>

<script>
function myFunction() {
  alert(\'The image could not be loaded.\');
}
</script>';

$doc = new DOMDocument();
$doc->loadHTML($text);
$xp = new DOMXPath($doc);
$find = '//body//*[not(name() = "'.implode ('" or name() = "', $allowed ).
    '")]';
echo "XPath = ".$find.PHP_EOL;
$toRemove = $xp->evaluate($find);
print_r($toRemove);
foreach ( $toRemove as $remove )    {
    $remove->parentNode->removeChild($remove);
}

// recreate HTML
$outHTML = "";
foreach ( $doc->getElementsByTagName("body")[0]->childNodes as $tag )  {
    $outHTML.= $doc->saveHTML($tag);
}
echo $outHTML;

Если вы также хотите удалить атрибуты, вы можете сделать тот же процесс, используя @* как часть выражения XPath...

$allowedAttribs = array();

$find = '//body//@*[not(name() = "'.implode ('" or name() = "', $allowedAttribs ).
'")]';
$toRemove = $xp->evaluate($find);
foreach ( $toRemove as $remove ) {
    $remove->parentNode->removeAttribute($remove->nodeName);
}

Можно было бы объединить эти два, но это делает код менее разборчивым (ИМХО).

Это не удаляет атрибуты (src, onclick и onerror) из тега img: 3v4l.org/1RR3A

Nick 12.03.2019 09:04

@Ник - я добавил это. Было бы интересно, если бы они хотели определенные атрибуты от определенных типов элементов - или я не должен упоминать об этом :-/

Nigel Ren 12.03.2019 09:20

Я думаю, что всегда безопаснее не задавать такие вопросы, вы просто можете получить ответ! :-)

Nick 12.03.2019 10:15

Другие вопросы по теме