DOMDocument удаляет теги сценариев из источника HTML

Я использовал подход @ Alex здесь, чтобы удалить теги сценариев из HTML-документа, используя встроенный DOMDocument. Проблема в том, что если у меня есть тег скрипта с содержимым Javascript, а затем другой тег скрипта, который ссылается на внешний исходный файл Javascript, не все теги скриптов удаляются из HTML.

$result = ' <!doctype html> <html> <head> <meta charset="utf-8"> <title> hey </title> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script> alert("hello"); </script> </head> <body>hey</body> </html> '; $dom = new DOMDocument(); if($dom->loadHTML($result)) { $script_tags = $dom->getElementsByTagName('script'); $length = $script_tags->length; for ($i = 0; $i < $length; $i++) { if(is_object($script_tags->item($i)->parentNode)) { $script_tags->item($i)->parentNode->removeChild($script_tags->item($i)); } } echo $dom->saveHTML(); } 

Вышеуказанные выходы кода:

 <html> <head> <meta charset="utf-8"> <title>hey</title> <script> alert("hello"); </script> </head> <body> hey </body> </html> 

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

Ваша ошибка на самом деле тривиальна. Объект DOMNode (и все его потомки – DOMElement , DOMNodeList и некоторые другие!) Автоматически обновляется при изменении его родительского элемента, особенно когда изменяется его количество. Это написано на нескольких строках в PHP-документе, но в основном проносится под ковер.

Если вы используете цикл ($k instanceof DOMNode)->length и впоследствии удаляете элементы из узлов, вы заметите, что свойство length действительно изменяется! Я должен был написать свою собственную библиотеку, чтобы противодействовать этому и еще нескольким причудам.

Решение:

 if($dom->loadHTML($result)) { while (($r = $dom->getElementsByTagName("script")) && $r->length) { $r->item(0)->parentNode->removeChild($r->item(0)); } echo $dom->saveHTML(); 

Я на самом деле не зацикливаюсь, просто вытаскивая первый элемент по одному. Результат: http://sebrenauld.co.uk/domremovescript.php

Чтобы избежать этого, вы получаете сюрпризы списка живых узлов, который становится короче, когда вы удаляете узлы, – вы можете работать с копией в массив с помощью iterator_to_array :

 foreach(iterator_to_array($dom->getElementsByTagName($tag)) as $node) { $node->parentNode->removeChild($node); };