我正在使用HTML Purifier(http://htmlpurifier.org/)
我只想删除<script>
标签。我不想删除内联格式或任何其他内容。
我该如何实现?
还有一件事,它还有其他方法可以从HTML删除脚本标签
因为这个问题被标记为 正则表达式 在这种情况下,我将用穷人的解决方案来回答:
$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);
但是,正则表达式不是用于解析HTML / XML的,即使您编写了一个完美的表达式,它最终也会被破坏,这是不值得的,尽管在某些情况下,快速修复某些标记很有用,而对于快速修复,忘记安全。仅在您信任的内容/标记上使用正则表达式。
请记住,用户输入的任何内容均应视为不安全的。
更好的解决方案是使用DOMDocument
为此目的而设计的解决方案。下面的代码片段演示了如何轻松,干净(与regex相比),(几乎)可靠和(几乎)安全来实现相同目的:
<?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,因为即使这样也可能会出错。
使用PHPDOMDocument
解析器。
$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或更高版本。
$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();
通过操纵字符串的一种简单方法。
$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;
}
我一直在努力解决这个问题。我发现您只需要一个功能。explode('>',$ html); 任何标签的唯一公分母是<和>。然后,通常是引号(“)。一旦找到公分母,就可以很容易地提取信息。这就是我想出的:
$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;
我看到这实际上仅适用于脚本标签,因为您永远不会有嵌套的脚本标签。当然,您可以轻松添加更多执行相同检查并收集嵌套标记的代码。
我称它为手风琴编码。implode(); explode(); 如果有一个共同的分母,这是使逻辑流畅的最简单方法。
更短:
$html = preg_replace("/<script.*?\/script>/s", "", $html);
在执行正则表达式时,可能会出错,因此这样做更安全:
$html = preg_replace("/<script.*?\/script>/s", "", $html) ? : $html;
这样,当“事故”发生时,我们得到原始的$ html而不是空字符串。
修改ctf0答案的示例。这应该只执行一次preg_replace,而且还应该检查是否有错误,并为正斜杠阻止字符代码。
$str = '<script> var a - 1; </script>';
$pattern = '/(script.*?(?:\/|/|/)script)/ius';
$replace = preg_replace($pattern, '', $str);
return ($replace !== null)? $replace : $str;
如果您使用的是php 7,则可以使用null合并运算符进一步简化它。
$pattern = '/(script.*?(?:\/|/|/)script)/ius';
return (preg_replace($pattern, '', $str) ?? $str);
试试这个完整而灵活的解决方案。它完美,并且由设在部分一些以前的答案,但包含额外的验证检查,并摆脱额外的隐含从HTMLloadHTML(...)
功能。它分为两个独立的函数(一个具有先前的依赖性,因此请勿重新排序/重新排列),因此您可以将其与要同时删除的多个HTML标记一起使用(即不仅仅是'script'
标记)。例如,removeAllInstancesOfTag(...)
function接受一个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] */
这是一个测试用法示例:
$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);
希望我的回答对您有所帮助。请享用!
如果可用,我将使用BeautifulSoup。使这种事情非常容易。
不要尝试使用正则表达式。那就是疯狂。
- 这是ClandestineCoder和Binh WPO的合并。
脚本标记箭头的问题在于它们可以具有多个变体
例如 (<=
<
=&lt;
)&(> =>
=&gt;
)
因此,与其创建具有类似bazillion变体的模式数组,不如做一个更好的解决方案是
return preg_replace('/script.*?\/script/ius', '', $text)
? preg_replace('/script.*?\/script/ius', '', $text)
: $text;
这将删除任何script.../script
与箭头代码/变量无关的内容,您可以在此处进行测试https://regex101.com/r/lK6vS8/1
这是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');
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
使用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")
?>
文章标签:htmlpurifier , php , regex
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!
评论已关闭!