我正在使用HTML Purifier(http://htmlpurifier.org/)
我只想删除<script>
个标签。
我不想删除内联格式或任何其他内容。
我怎样才能做到这一点?
还有一件事,还有其他方法可以从HTML中删除脚本标记
答案 0 :(得分:119)
因为这个问题用regex标记,我将在这种情况下用穷人的解决方案回答:
$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);
然而,正则表达式不是用于解析HTML / XML,即使你编写完美表达式它最终会破坏,它也不值得,尽管在某些情况下快速修复一些是有用的标记,以及快速修复,忘记安全性。仅对您信任的内容/标记使用正则表达式。
请记住,用户输入的任何内容都应被视为不安全。
这里的 更好解决方案是使用专为此设计的DOMDocument
。
这是一个片段,演示了如何轻松,干净(与正则表达式相比),(几乎)可靠和(几乎)安全是这样做的:
<?php
$html = <<<HTML
...
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$script = $dom->getElementsByTagName('script');
$remove = [];
foreach($script as $item)
{
$remove[] = $item;
}
foreach ($remove as $item)
{
$item->parentNode->removeChild($item);
}
$html = $dom->saveHTML();
我故意删除了HTML,因为即使这样也可以 bork 。
答案 1 :(得分:36)
使用PHP DOMDocument
解析器。
$doc = new DOMDocument();
// load the HTML string we want to strip
$doc->loadHTML($html);
// get all the script tags
$script_tags = $doc->getElementsByTagName('script');
$length = $script_tags->length;
// for each tag, remove it from the DOM
for ($i = 0; $i < $length; $i++) {
$script_tags->item($i)->parentNode->removeChild($script_tags->item($i));
}
// get the HTML string back
$no_script_html_string = $doc->saveHTML();
这让我使用以下HTML文档:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>
hey
</title>
<script>
alert("hello");
</script>
</head>
<body>
hey
</body>
</html>
请记住,DOMDocument
解析器需要PHP 5或更高版本。
答案 2 :(得分:2)
$html = <<<HTML
...
HTML;
$dom = new DOMDocument();
$dom->loadHTML($html);
$tags_to_remove = array('script','style','iframe','link');
foreach($tags_to_remove as $tag){
$element = $dom->getElementsByTagName($tag);
foreach($element as $item){
$item->parentNode->removeChild($item);
}
}
$html = $dom->saveHTML();
答案 3 :(得分:1)
我一直在努力解决这个问题。我发现你真的只需要一个功能。爆炸(&#39;&gt;&#39;,$ html);任何标签的单个共同点是&lt;和&gt;。之后,它通常是引号(&#34;)。一旦找到共同点,您就可以轻松地提取信息。这就是我想出的:
$html = file_get_contents('http://some_page.html');
$h = explode('>', $html);
foreach($h as $k => $v){
$v = trim($v);//clean it up a bit
if(preg_match('/^(<script[.*]*)/ius', $v)){//my regex here might be questionable
$counter = $k;//match opening tag and start counter for backtrace
}elseif(preg_match('/([.*]*<\/script$)/ius', $v)){//but it gets the job done
$script_length = $k - $counter;
$counter = 0;
for($i = $script_length; $i >= 0; $i--){
$h[$k-$i] = '';//backtrace and clear everything in between
}
}
}
for($i = 0; $i <= count($h); $i++){
if($h[$i] != ''){
$ht[$i] = $h[$i];//clean out the blanks so when we implode it works right.
}
}
$html = implode('>', $ht);//all scripts stripped.
echo $html;
我认为这只适用于脚本标记,因为你永远不会有嵌套的脚本标记。当然,您可以轻松添加更多执行相同检查的代码并收集嵌套标记。
我称之为手风琴编码。爆();爆炸();如果你有一个共同点,那么这是让你的逻辑流动最简单的方法。
答案 4 :(得分:1)
尝试此 完整 和 灵活 解决方案。它运行良好,并且部分基于 some 先前的答案,但包含其他验证检查,并且从loadHTML(...)
函数中删除了其他隐含的 HTML 。它分为两个单独的函数(一个具有先前的依赖关系,因此请勿重新排序/重新排列),因此您可以将其与要同时删除的多个HTML标记一起使用(即,不仅'script'
标签)。例如,removeAllInstancesOfTag(...)
函数接受标记名的array
,或者仅接受一个作为string
的标记名。所以,事不宜迟,这里是代码:
/* Remove all instances of a particular HTML tag (e.g. <script>...</script>) from a variable containing raw HTML data. [BEGIN] */
/* Usage Example: $scriptless_html = removeAllInstancesOfTag($html, 'script'); */
if (!function_exists('removeAllInstancesOfTag'))
{
function removeAllInstancesOfTag($html, $tag_nm)
{
if (!empty($html))
{
$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'); /* For UTF-8 Compatibility. */
$doc = new DOMDocument();
$doc->loadHTML($html,LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NOWARNING);
if (!empty($tag_nm))
{
if (is_array($tag_nm))
{
$tag_nms = $tag_nm;
unset($tag_nm);
foreach ($tag_nms as $tag_nm)
{
$rmvbl_itms = $doc->getElementsByTagName(strval($tag_nm));
$rmvbl_itms_arr = [];
foreach ($rmvbl_itms as $itm)
{
$rmvbl_itms_arr[] = $itm;
};
foreach ($rmvbl_itms_arr as $itm)
{
$itm->parentNode->removeChild($itm);
};
};
}
else if (is_string($tag_nm))
{
$rmvbl_itms = $doc->getElementsByTagName($tag_nm);
$rmvbl_itms_arr = [];
foreach ($rmvbl_itms as $itm)
{
$rmvbl_itms_arr[] = $itm;
};
foreach ($rmvbl_itms_arr as $itm)
{
$itm->parentNode->removeChild($itm);
};
};
};
return $doc->saveHTML();
}
else
{
return '';
};
};
};
/* Remove all instances of a particular HTML tag (e.g. <script>...</script>) from a variable containing raw HTML data. [END] */
/* Remove all instances of dangerous and pesky <script> tags from a variable containing raw user-input HTML data. [BEGIN] */
/* Prerequisites: 'removeAllInstancesOfTag(...)' */
if (!function_exists('removeAllScriptTags'))
{
function removeAllScriptTags($html)
{
return removeAllInstancesOfTag($html, 'script');
};
};
/* Remove all instances of dangerous and pesky <script> tags from a variable containing raw user-input HTML data. [END] */
这是一个 test 用法示例:
$html = 'This is a JavaScript retention test.<br><br><span id="chk_frst_scrpt">Congratulations! The first \'script\' tag was successfully removed!</span><br><br><span id="chk_secd_scrpt">Congratulations! The second \'script\' tag was successfully removed!</span><script>document.getElementById("chk_frst_scrpt").innerHTML = "Oops! The first \'script\' tag was NOT removed!";</script><script>document.getElementById("chk_secd_scrpt").innerHTML = "Oops! The second \'script\' tag was NOT removed!";</script>';
echo removeAllScriptTags($html);
我希望我的回答对某人有帮助。享受吧!
答案 5 :(得分:0)
如果它可用,我会使用BeautifulSoup。使这种事情变得非常容易。
不要尝试使用regexp。那种方式就是疯狂。
答案 6 :(得分:0)
更短的:
$html = preg_replace("/<script.*?\/script>/s", "", $html);
在进行正则表达式时,事情可能会出错,所以这样做更安全:
$html = preg_replace("/<script.*?\/script>/s", "", $html) ? : $html;
这样当&#34;意外&#34;碰巧,我们得到原始的$ html而不是空字符串。
答案 7 :(得分:0)
脚本标记箭头的问题是它们可以有多个变体
离。 (&lt; =
<
=&lt;
)&amp; (&gt; =>
=&gt;
)
所以不要创建一个像bazillion变体一样的模式数组, imho是一个更好的解决方案
return preg_replace('/script.*?\/script/ius', '', $text)
? preg_replace('/script.*?\/script/ius', '', $text)
: $text;
这将删除任何看似script.../script
的内容,无论箭头代码/变体如何,您都可以在此处https://regex101.com/r/lK6vS8/1进行测试
答案 8 :(得分:0)
修改ctf0答案的示例。这应该只执行preg_replace一次,但也检查错误并阻止正斜杠的char代码。
$str = '<script> var a - 1; </script>';
$pattern = '/(script.*?(?:\/|/|/)script)/ius';
$replace = preg_replace($pattern, '', $str);
return ($replace !== null)? $replace : $str;
如果您使用的是PHP 7,则可以使用null coalesce运算符来进一步简化它。
$pattern = '/(script.*?(?:\/|/|/)script)/ius';
return (preg_replace($pattern, '', $str) ?? $str);
答案 9 :(得分:0)
这是Dejan Marjanovic答案的简化版本:
function removeTags($html, $tag) {
$dom = new DOMDocument();
$dom->loadHTML($html);
foreach (iterator_to_array($dom->getElementsByTagName($tag)) as $item) {
$item->parentNode->removeChild($item);
}
return $dom->saveHTML();
}
可用于删除任何类型的标记,包括<script>
:
$scriptlessHtml = removeTags($html, 'script');
答案 10 :(得分:0)
使用str_replace函数将其替换为空白空间或其他内容
$query = '<script>console.log("I should be banned")</script>';
$badChar = array('<script>','</script>');
$query = str_replace($badChar, '', $query);
echo $query;
//this echoes console.log("I should be banned")
?>
答案 11 :(得分:0)
一种处理字符串的简单方法。
$str = stripStr($str, '<script', '</script>');
function stripStr($str, $ini, $fin)
{
while(($pos = mb_stripos($str, $ini)) !== false)
{
$aux = mb_substr($str, $pos + mb_strlen($ini));
$str = mb_substr($str, 0, $pos).mb_substr($aux, mb_stripos($aux, $fin) + mb_strlen($fin));
}
return $str;
}
答案 12 :(得分:0)
function remove_script_tags($html){
$dom = new DOMDocument();
$dom->loadHTML($html);
$script = $dom->getElementsByTagName('script');
$remove = [];
foreach($script as $item){
$remove[] = $item;
}
foreach ($remove as $item){
$item->parentNode->removeChild($item);
}
$html = $dom->saveHTML();
$html = preg_replace('/<!DOCTYPE.*?<html>.*?<body><p>/ims', '', $html);
$html = str_replace('</p></body></html>', '', $html);
return $html;
}
Dejan的回答很好,但是saveHTML()添加了不必要的doctype和body标签,这应该摆脱它。参见https://3v4l.org/82FNP