我正在使用HTML Purifier (http://htmlpurifier.org/)。
我只想删除<script>
标记,不想删除行内格式或其他任何内容。
我该如何实现这个目的?
还有一件事,是否有其他方法可以从HTML中删除脚本标记?
我正在使用HTML Purifier (http://htmlpurifier.org/)。
我只想删除<script>
标记,不想删除行内格式或其他任何内容。
我该如何实现这个目的?
还有一件事,是否有其他方法可以从HTML中删除脚本标记?
$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);
然而,正则表达式并不适用于解析HTML/XML,即使你编写了完美的表达式,它最终也会出现问题,这不值得。尽管在某些情况下,使用正则表达式可以快速修复一些标记,但由于其只是解决临时问题,所以要忽略安全性。仅在您信任的内容/标记上使用正则表达式。
请记住,用户输入的任何内容都应被视为不安全。
在这里,一个更好的解决方案是使用专门设计用于此目的的DOMDocument
。以下是演示如何使用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,因为即使这样也会破坏它。
使用 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或更高版本。
<script src="..."></script>
,此代码将会返回'Fatal error: Call to a member function removeChild() on null'
。 - yumba$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();
$dom->loadHTML($html,LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD);
- sogerfunction 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);
if (($pos2 = mb_stripos($aux, $fin)) !== false) {
$str .= mb_substr($aux, $pos2 + mb_strlen($fin));
}
}
return $str;
}
尝试使用这个完整且灵活的解决方案。它能够完美地运行,并在某种程度上基于之前的答案,但还包含其他验证检查,并且可以去掉loadHTML(...)
函数中的其他隐含的HTML。它被分成了两个单独的函数(一个有先前的依赖关系,因此不要重新排序/重新排列),因此您可以将其用于想要同时删除的多个HTML标签(即不仅限于'script'
标签)。例如,removeAllInstancesOfTag(...)
函数接受一个标签名称的数组
,或者可选地只接受一个标签作为字符串
。所以,不再拖延,这就是代码:
/* 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);
我希望我的答案真正能帮助到某些人。祝您使用愉快!
脚本标签箭头的问题在于它们可以有多个变体。
例如(< =
<
=&lt;
)和(> =>
=&gt;
)
因此,不要创建一个具有无数变体的模式数组,我认为更好的解决方案是
return preg_replace('/script.*?\/script/ius', '', $text)
? preg_replace('/script.*?\/script/ius', '', $text)
: $text;
这将删除任何看起来像 script.../script
的内容,无论是什么箭头代码或变体,您可以在此处进行测试:https://regex101.com/r/lK6vS8/1
简化版:
$html = preg_replace("/<script.*?\/script>/s", "", $html);
在使用正则表达式时,可能会出现问题,所以最好这样做:
$html = preg_replace("/<script.*?\/script>/s", "", $html) ? : $html;
这样当“意外”发生时,我们会得到原始的 $html 而不是空字符串。
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
loadHTML(...)
函数会添加那些内容,而是它会使用LIBXML_HTML_NODEFDTD
和LIBXML_HTML_NOIMPLIED
。具体信息可以参考这里:https://www.php.net/manual/en/libxml.constants.php。 - James Anderson Jr.修改 ctf0 的回答的示例。这个代码只会执行一次 preg_replace,同时检查错误并阻止斜杠字符编码。
$str = '<script> var a - 1; </script>';
$pattern = '/(script.*?(?:\/|/|/)script)/ius';
$replace = preg_replace($pattern, '', $str);
return ($replace !== null)? $replace : $str;
$pattern = '/(script.*?(?:\/|/|/)script)/ius';
return (preg_replace($pattern, '', $str) ?? $str);
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');