## 對于簡單的數據凈化,使用?[htmlentities()](http://php.net/manual/zh/function.htmlentities.php)?函數, 復雜的數據凈化則使用[HTML Purifier](http://htmlpurifier.org/)?庫
**經 HTML Purifier 4.4.0 測試**
在任何 wbe 應用中展示用戶輸出時,首先對其進行“凈化”去除任何潛在危險的 HTML 是非常必要的。 一個惡意的用戶可以制作某些 HTML,若被你的 web 應用直接輸出,對查看它的人來說會很危險。
雖然可以嘗試使用正則表達式來凈化 HTML,但不要這樣做。HTML是一種復雜的語言,試圖使用正則表達式來凈化 HTML 幾乎總是失敗的。
你可能會找到建議你使用?[strip_tags()](http://php.net/manual/zh/function.strip-tags.php)?函數的觀點。 雖然 strip_tags() 從技術上來說是安全的,但如果輸入的不合法的 HTML(比如, 沒有結束標簽),它就成了一個「愚蠢」的函數,可能會去除比你期望的更多的內容。 由于非技術用戶在通信中經常使用`<` 和` >` 字符,`strip_tags()`?也就不是一個好的選擇了。
如果閱讀了[驗證郵件地址](http://phpbestpractices.justjavac.com/#validating-emails)一節, 你也許也會考慮使用?[filter_var()](http://php.net/manual/zh/function.filter-var.php)?函數。 然而?[filter_var() 函數在遇到斷行時會出現問題](http://stackoverflow.com/questions/3150413/filter-sanitize-special-chars-problem-with-line-breaks), 并且需要不直觀的配置以接近?[htmlentities()](http://php.net/manual/zh/function.htmlentities.php)?函數的效果, 因此也不是一個好的選擇。
## 對于簡單需求的凈化
如果你的 web 應用僅需要完全地轉義(因此可以無害地呈現,但不是完全去除) HTML, 則使用 PHP 的內建[htmlentities()](http://php.net/manual/zh/function.htmlentities.php)?函數。 這個函數要比 HTML Purifier 快得多,因此它不對 HTML 做任何驗證---僅轉義所有東西。
htmlentities() 不同于類似功能的函數[htmlspecialchars()](http://php.net/manual/zh/function.htmlspecialchars.php), 它會編碼所有適用的 HTML 實體,而不僅僅是一個小的子集。
### 示例
~~~
<?php
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = '<div onclick="xss();">Mua-ha-ha! Twiddling my evil mustache...</div>';
// Use the ENT_QUOTES flag to make sure both single and double quotes are escaped.
// Use the UTF-8 character encoding if you've stored the text as UTF-8 (as you should have).
// See the UTF-8 section in this document for more details.
$safeHtml = htmlentities($evilHtml, ENT_QUOTES, 'UTF-8');
// $safeHtml is now fully escaped HTML. You can output $safeHtml to your users without fear!
?>
~~~
## 對于復雜需求的凈化
對于很多 web 應用來說,簡單地轉義 HTML 是不夠的。 你可能想完全去除任何HTML,或者允許一小部分子集的 HTML 存在。 若是如此,則使用?[HTML Purifier](http://htmlpurifier.org/)?庫。
HTML Purifier 是一個經過充分測試但效率比較低的庫。 這就是為什么如果你的需求并不復雜就應使用[htmlentities()](http://php.net/manual/zh/function.htmlentities.php), 因為它的效率要快得多。
HTML Purifier 相比?[strip_tags()](http://php.net/manual/zh/function.strip-tags.php)?是有優勢的, 因為它在凈化 HTML 之前會對其校驗。 這意味著如果用戶輸入無效 HTML,HTML Purifier 相比 strip_tags() 更能保留 HTML 的原意。 HTML Purifier 高度可定制,允許你為 HTML 的一個子集建立白名單來允許這個 HTML 子集的實體存在輸出中。
但其缺點就是相當的慢,它要求一些設置,在一個共享主機的環境里可能是不可行的。 其文檔通常也復雜而不易理解。 以下示例是一個基本的使用配置。 查看[文檔](http://htmlpurifier.org/docs)閱讀 HTML Purifier 提供的更多更高級的特性。
### 示例
~~~
<?php
// Include the HTML Purifier library
require_once('htmlpurifier-4.4.0/HTMLPurifier.auto.php');
// Oh no! The user has submitted malicious HTML, and we have to display it in our web app!
$evilHtml = '<div onclick="xss();">Mua-ha-ha! Twiddling my evil mustache...</div>';
// Set up the HTML Purifier object with the default configuration.
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
$safeHtml = $purifier->purify($evilHtml);
// $safeHtml is now sanitized. You can output $safeHtml to your users without fear!
?>
~~~
## 陷阱
* 以錯誤的字符編碼使用 htmlentities() 會造成意想不到的輸出。 在調用該函數時始終確認指定了一種字符編碼,并且該編碼與將被凈化的字符串的編碼相匹配。 更多細節請查看?[UTF-8 一節](http://phpbestpractices.justjavac.com/#utf-8)。
* 使用 htmlentities() 時,始終包含 ENT_QUOTES 和字符編碼參數。 默認情況下,htmlentities() 不會對單引號編碼。多愚蠢的默認做法!
* HTML Purifier 對于復雜的 HTML 效率極其的低。可以考慮設置一個緩存方案如APC來保存經過凈化的結果以備后用。
## 進一步閱讀
* [PHP HTML 凈化工具對比](http://htmlpurifier.org/comparison)(英文)
* [Laruence:PHP Taint – 一個用來檢測 XSS/SQL/Shell 注入漏洞的擴展](http://www.laruence.com/2012/02/14/2544.html)
* [Stack Overflow: 使用 strip_tags() 來防止 XSS?](http://stackoverflow.com/questions/3605629/php-prevent-xss-with-strip-tags)
* [Stack Overflow: PHP中凈化用戶輸入的最佳方法是什么?](http://stackoverflow.com/questions/129677/whats-the-best-method-for-sanitizing-user-input-with-php)
* [Stack Overflow: 斷行時的 FILTER_SANITIZE_SPECIAL_CHARS 問題](http://stackoverflow.com/questions/3150413/filter-sanitize-special-chars-problem-with-line-breaks)