PHP+Tidy-完美的XHTML糾錯(cuò)+過濾
Jun 13, 2016 pm 12:32 PM
輸入和輸出
輸入和輸出應(yīng)該說是很多網(wǎng)站的基本功能。用戶輸入數(shù)據(jù),網(wǎng)站輸出數(shù)據(jù)供其他人瀏覽。
拿目前流行的Blog為例,這里的輸入輸出就是作者編輯文章后生成博客文章頁面供他人閱讀。
這里有一個(gè)問題,即用戶輸入通常是不受控制的,它可能包含不正確的格式亦或者含有有安全隱患的代碼;而最終網(wǎng)站輸出的內(nèi)容卻必須是正確的HTML代碼。這就需要對(duì)用戶輸入的內(nèi)容進(jìn)行糾錯(cuò)和過濾。
永遠(yuǎn)不要相信用戶的輸入
你可能會(huì)說:現(xiàn)在到處都是所見即所得的編輯器(WYSIWYG),F(xiàn)CKeditor、TinyMCE...你可能會(huì)舉出一大堆。是的,它們都可以自動(dòng)生成標(biāo)準(zhǔn)的XHTML代碼,但是作為web開發(fā)人員,你肯定聽過"永遠(yuǎn)不要相信用戶遞交的數(shù)據(jù)"。
因此對(duì)用戶輸入數(shù)據(jù)進(jìn)行糾錯(cuò)和過濾是必需的。
需要更好的糾錯(cuò)和過濾
目前為止我還沒見過有讓我滿意的相關(guān)實(shí)現(xiàn),能接觸到的通常都是效率低下、效果不太理想,有這樣那樣的明顯缺陷。舉個(gè)比較知名的例子:WordPress是一種使用非常廣泛的blog系統(tǒng),操作簡(jiǎn)單功能強(qiáng)大且有豐富的插件支持,但是它集成的TinyMCE和后臺(tái)一堆有些自作聰明的糾錯(cuò)過濾代碼卻令人相當(dāng)頭痛,對(duì)半角字符的強(qiáng)制替換,過于保守的替換規(guī)則等等.....導(dǎo)致像貼一段代碼讓它正確顯示這種需求都很難做到。
這里順便抱怨一下,這個(gè)blog是用WordPress架的,為了讓這幾篇文章能正確顯示代碼,網(wǎng)上搜了很多也試用了一些插件,最終還是翻了它的代碼把一些過濾規(guī)則注釋掉才勉強(qiáng)可以顯示得體面一點(diǎn)?-.-b?
當(dāng)然,我不想過多的指責(zé)它(wordpress),只是想說明它還可以做的更好。
Tidy是什么,它如何工作?
摘自Tidy?ManPage的說明這樣描述:
Tidy?reads?HTML,?XHTML?and?XML?files?and?writes?cleaned?up?markup.?For?HTML?variants,?it?detects?and?corrects?many?common?coding?errors?and?strives?to?produce?visually?equivalent?markup?that?is?both?W3C?compliant?and?works?on?most?browsers.?A?common?use?of?Tidy?is?to?convert?plain?HTML?to?XHTML.?For?generic?XML?files,?Tidy?is?limited?to?correcting?basic?well-formedness?errors?and?pretty?printing.?
簡(jiǎn)單說Tidy是清理HTML代碼的,生成干凈的符合W3C標(biāo)準(zhǔn)的HTML代碼,支持HTML,XHTML,XML。Tidy提供一個(gè)庫TidyLib,以方便在其他應(yīng)用中利用Tidy的強(qiáng)大功能。非常幸運(yùn),PHP有相應(yīng)的tidy模塊可以使用。
老兄,為什么又是PHP?
呃,這個(gè)問題...?慚愧,因?yàn)槲抑粫?huì)那么點(diǎn)PHP而已?-.-v
不過還好,我這里講的都不是純粹的代碼,好歹也有些分析的過程,分享這些東西比貼代碼有用多了。
PHP中使用Tidy
要在PHP中使用Tidy需要安裝Tidy模塊,也就是加載tidy.so這個(gè)PHP?extension,具體過程就略了,純粹是體力活。最后能在phpinfo()中看到"Tidy?support?enabled"?就OK。
在這個(gè)模塊的支持下,PHP中就可以使用Tidy提供的幾乎所有的功能。常用的HTML清理是異常輕松的事情,甚至可以生成文檔的解析樹,像在客戶端操作DOM那樣的操作HTML的各個(gè)Node。下面將會(huì)有具體的代碼說明,也可以看看PHP官方的相關(guān)手冊(cè)。
糾錯(cuò)和過濾的PHP+Tidy實(shí)現(xiàn)
上面說了這么多背景素材,似乎太羅唆了,具體的解決問題的代碼才最最直接。
1.?簡(jiǎn)單的糾錯(cuò)實(shí)現(xiàn)
function?HtmlFix($html)
{
??if(!function_exists('tidy_repair_string'))
????return?$html;
??//use?tidy?to?repair?html?code
??//repair
??$str?=?tidy_repair_string($html,
???????????????????array('output-xhtml'=>true),
???????????????????'utf8');
??//parse
??$str?=?tidy_parse_string($str,
??????????????????array('output-xhtml'=>true),
??????????????????'utf8');
??$s?=?'';
??$nodes?=?@tidy_get_body($str)->child;
??if(!is_array($nodes)){
????$returnVal?=?0;
????return?$s;
??}
??foreach($nodes?as?$n){
????$s?.=?$n->value;
??}
??return?$s;
}
上面的代碼就是對(duì)可能不規(guī)范的XHTML代碼進(jìn)行清理糾錯(cuò),輸出標(biāo)準(zhǔn)的XHTML代碼(輸入輸出都是UTF-8編碼)。實(shí)現(xiàn)代碼不是最精簡(jiǎn)的,因?yàn)闉榱伺浜舷旅娴倪^濾功能,我寫的盡可能細(xì)致了一些。
2.?高級(jí)實(shí)現(xiàn):?糾錯(cuò)+過濾
功能:?
XHTML的糾錯(cuò),輸出標(biāo)準(zhǔn)的XHTML代碼。?
過濾不安全的代碼但是不影響內(nèi)容展示,只是對(duì)style/javascript中不安全代碼進(jìn)行清除。?
對(duì)超長(zhǎng)字符串插入
function?HtmlFixSafe($html)
{
??if(!function_exists('tidy_repair_string'))
????return?$html;
??//use?tidy?to?repair?html?code
??//?tidy?的參數(shù)設(shè)定
??$conf?=?array(
????????????????'output-xhtml'=>true
????????????????,'drop-empty-paras'=>FALSE
????????????????,'join-classes'=>TRUE
????????????????,'show-body-only'=>TRUE
????????????????);
?//repair
??$str?=?tidy_repair_string($html,$conf,'utf8');
??//生成解析樹
??$str?=?tidy_parse_string($str,$conf,'utf8');
??$s?='';
??//得到body節(jié)點(diǎn)
??$body?=?@tidy_get_body($str);
??//函數(shù)?_dumpnode,檢查每個(gè)節(jié)點(diǎn),過濾后輸出
??function?_dumpnode($node,&$s){
???//查看節(jié)點(diǎn)名,如果是<script> 和<style>就直接清除 <BR> switch($node->name){ <BR> case 'script': <BR> case 'style': <BR> return; <BR> break; <BR> default: <BR> } <br><br> if($node->type == TIDY_NODETYPE_TEXT){ <BR> /* <BR> 如果該節(jié)點(diǎn)內(nèi)是文字,做額外的處理: <BR> 過長(zhǎng)文字的自動(dòng)換行問題; <BR> 超鏈接的自動(dòng)識(shí)別(未實(shí)現(xiàn)) <BR> */ <BR> // insert <wbr> <BR> $s .= HtmlInsertWbrs($node->value,30,'','&?/\'); <br><br> // auto links ??? *** TODO *** <BR> return; <BR> } <br><br> //不是文字節(jié)點(diǎn),那么處理標(biāo)簽和它的屬性 <BR> $s .= '<'.$node->name; <br><br> //檢查每個(gè)屬性 <BR> if($node->attribute){ <BR> foreach($node->attribute as $name=>$value){ <br><br> /* <BR> 清理一些DOM事件,通常是on開頭的, <BR> 比如onclick onmouseover等.... <BR> 或者屬性值有javascript:字樣的, <BR> 比如href="javascript:"的也被清除. <BR> */ <BR> if(strpos($name,'on') === 0 <br><br> stripos(trim($value),'javascript:') ===0 <BR> ){ <BR> continue; <BR> } <br><br> //保留安全的屬性 <BR> $s .= ' '.$name.'="'.HtmlEscape($value).'"'; <br><br> } <BR> } <br><br> //遞歸檢查該節(jié)點(diǎn)下的子節(jié)點(diǎn) <BR> if($node->child){ <br><br> $s .= '>'; <br><br> foreach($node->child as $child){ <BR> _dumpnode($child,$s); <BR> } <br><br> //子節(jié)點(diǎn)處理完畢,閉合標(biāo)簽 <BR> $s .= '</'.$node->name.'>'; <BR> }else{ <br><br> /* <BR> 已經(jīng)沒有子節(jié)點(diǎn)了,將標(biāo)簽閉合 <BR> (事實(shí)上也可以考慮直接刪除掉空的節(jié)點(diǎn)) <BR> */ <BR> if($node->type == TIDY_NODETYPE_START) <BR> $s .= '></'.$node->name.'>'; <BR> else <BR> /* <BR> 對(duì)非配對(duì)標(biāo)簽,比如<hr/> <br/> <img / alt="PHP+Tidy-完美的XHTML糾錯(cuò)+過濾" >等 <BR> 直接以 />閉合之 <BR> */ <BR> $s .= '/>'; <BR> } <BR> } <BR> //函數(shù)定義end <br><br> //通過上面的函數(shù) 對(duì) body節(jié)點(diǎn)開始過濾。 <BR> if($body->child){ <br><br> foreach($body->child as $child) <BR> _dumpnode($child,$s); <BR> }else <BR> return ''; <br><br> return $s; <BR>} <BR>上面代碼中注釋應(yīng)該比較詳細(xì),工作原理就配合代碼看吧。 <BR>更嚴(yán)格的過濾也很容易擴(kuò)展,比如實(shí)現(xiàn)文中的鏈接自動(dòng)識(shí)別。 <br><br><BR>一點(diǎn)補(bǔ)充 <br><br>如果你看過我之前寫的網(wǎng)頁中超長(zhǎng)文字的斷行問題,你可能發(fā)現(xiàn)上面代碼中處理自動(dòng)換行的函數(shù)有所不同: <br><br>之前介紹的是HtmlEscapeInsertWbrs(),而上面使用的是HtmlInsertWbrs()。 <br><br>這里要做一下解釋: <BR>HtmlEscapeInsertWbrs()要求輸入的字符串未作特殊字符轉(zhuǎn)義的,也就是沒有經(jīng)過htmlspecialchars()對(duì)<>&等作<>&處理的。因?yàn)楹瘮?shù)內(nèi)部有專門的處理。 <BR>而在處理經(jīng)Tidy處理過后的文字節(jié)點(diǎn)的時(shí)候,因?yàn)門idy的關(guān)系,已經(jīng)自動(dòng)把<>&等字符作相應(yīng)的<>&轉(zhuǎn)義,因此需要用一個(gè)專門的函數(shù)避免重復(fù)的轉(zhuǎn)義,這個(gè)函數(shù)就是HtmlInsertWbrs(),從名字上就知道它只插入<wbr>標(biāo)記,不做額外工作。 <br><br>那么你可能有個(gè)問題: <BR>如果<wbr>被插入到HTML標(biāo)簽中間,比如在<div>或者>的中間插入了<wbr>,變成<d<wbr>iv>和&<wbr>gt;,那就會(huì)影響到原始信息的展示。 <br><br>沒錯(cuò),的確是個(gè)新問題,不過使用一些技巧就可以有效解決: <br><br>因?yàn)槲覀兲幚淼氖荰idy得到的文字節(jié)點(diǎn),意味著不可能碰到HTML標(biāo)簽,因此不會(huì)碰到在標(biāo)簽中間插入<wbr>的情況。 <BR>對(duì)于第二種情況,轉(zhuǎn)義后的字符都是&xxxxx;這樣的形式,那么只要在1所有&符號(hào)前面都插入<wbr>標(biāo)記就可以了(注意看調(diào)用時(shí)的第四個(gè)參數(shù)),因?yàn)橄乱粋€(gè)<wbr>標(biāo)記將會(huì)插在30(以上面代碼中實(shí)際調(diào)用的第二個(gè)參數(shù)為例)個(gè)字符之后,這個(gè)已經(jīng)2遠(yuǎn)遠(yuǎn)大于xxxxx的長(zhǎng)度。這樣由上面1、2兩點(diǎn)可以保證不會(huì)插到轉(zhuǎn)義字符的中間。 <BR>下面給出HtmlInsertWbrs()的PHP實(shí)現(xiàn): <br><br>function HtmlInsertWbrs($str, $n=10, <BR> $chars_to_break_after='',$chars_to_break_before='') <BR>{ <BR> $out = ''; <BR> $strpos = 0; <BR> $spc = 0; <BR> $len = mb_strlen($str,'UTF-8'); <BR> for ($i = 1; $i < $len; ++$i) { <BR> $prev_char = mb_substr($str,$i-1,1,'UTF-8'); <BR> $next_char = mb_substr($str,$i,1,'UTF-8'); <BR> if (_u_IsSpace($next_char)) { <BR> $spc = $i; <BR> } else { <BR> if ($i - $spc == $n <br><br> mb_strpos( $chars_to_break_after, <BR> $prev_char,0,'UTF-8' ) <BR> !== FALSE <br><br> mb_strpos( $chars_to_break_before, <BR> $next_char,0,'UTF-8') <BR> !== FALSE <BR> ) { <BR> $out .= mb_substr($str,$strpos, <BR> $i-$strpos,'UTF-8') <BR> . '<wbr>'; <BR> $strpos = $i; <BR> $spc = $i; <BR> } <BR> } <BR> } <BR> $out .= mb_substr($str,$strpos,$len-$strpos,'UTF-8'); <BR> return $out; <BR>} <BR>... <BR>Ok,先寫這么多,相關(guān)的資料在文中都有鏈接。 <BR>下次想到再補(bǔ)充。 <BR>
</script>

Alat AI Hot

Undress AI Tool
Gambar buka pakaian secara percuma

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Midea tidak lama lagi akan melepaskan penghawa dingin pertama yang dilengkapi dengan model besar DeepSeek - Midea Fresh and Clean Air Machine T6. Penghawa dingin ini dilengkapi dengan sistem memandu pintar udara maju, yang boleh menyesuaikan parameter dengan bijak seperti suhu, kelembapan dan kelajuan angin mengikut alam sekitar. Lebih penting lagi, ia mengintegrasikan model besar DeepSeek dan menyokong lebih daripada 400,000 arahan suara AI. Langkah Midea telah menyebabkan perbincangan yang hangat dalam industri, dan sangat prihatin terhadap kepentingan menggabungkan barangan putih dan model besar. Tidak seperti tetapan suhu mudah penghawa dingin tradisional, mesin udara segar dan bersih T6 dapat memahami arahan yang lebih kompleks dan samar -samar dan secara bijak menyesuaikan kelembapan mengikut persekitaran rumah, dengan ketara meningkatkan pengalaman pengguna.

Apakah mata wang GateToken(GT)? GT (GateToken) ialah aset asli pada rantaian GateChain dan mata wang platform rasmi Gate.io. Nilai syiling GT berkait rapat dengan pembangunan ekologi Gate.io dan GateChain. Apakah GateChain? GateChain dilahirkan pada 2018 dan merupakan generasi baharu rangkaian awam berprestasi tinggi yang dilancarkan oleh Gate.io. GateChain menumpukan pada melindungi keselamatan aset dalam rantaian pengguna dan menyediakan perkhidmatan transaksi terdesentralisasi yang mudah. Matlamat GateChain adalah untuk membina ekosistem penyimpanan, pengedaran dan transaksi aset digital terdesentralisasi yang selamat dan cekap peringkat perusahaan. Gatechain mempunyai asal

PowerToys adalah koleksi alat percuma yang dilancarkan oleh Microsoft untuk meningkatkan produktiviti dan kawalan sistem untuk pengguna Windows. Ia menyediakan ciri -ciri melalui modul mandiri seperti susun atur tetingkap pengurusan fancyzones dan powerrename kumpulan penamaan semula, menjadikan aliran kerja pengguna lebih lancar.

10 platform perdagangan mata wang digital teratas: 1. Okx, 2. Binance, 3. Gate.io, 4. Huobi Global, 5. Kraken, 6. Coinbase, 7. Kucoin, 8.

Pada tahun 2025, platform perdagangan mata wang maya digital global sangat kompetitif. OKX menduduki tempat pertama dengan kekuatan teknikal yang kuat dan strategi operasi global, dan Binance mengikuti rapat dengan kecairan yang tinggi dan yuran yang rendah. Platform seperti Gate.io, Coinbase, dan Kraken berada di barisan hadapan dengan kelebihan masing -masing. Senarai ini meliputi platform perdagangan seperti Huobi, Kucoin, Bitfinex, Crypto.com dan Gemini, masing -masing dengan ciri -cirinya sendiri, tetapi pelaburan harus berhati -hati. Untuk memilih platform, anda perlu mempertimbangkan faktor -faktor seperti keselamatan, kecairan, yuran, pengalaman pengguna, pemilihan mata wang dan pematuhan peraturan, dan melabur secara rasional

Artikel ini mengesyorkan aplikasi perdagangan mata wang digital: 1. Apabila memilih platform, anda perlu mempertimbangkan faktor -faktor seperti keselamatan, kecairan, yuran transaksi, pemilihan mata wang, antara muka pengguna, sokongan perkhidmatan pelanggan dan pematuhan peraturan, dan menilai dengan teliti risiko dan tidak pernah membabi buta mengikuti trend.

Platform perdagangan dan analisis cryptocurrency terbaik termasuk: 1. OKX: Nombor Satu Dunia dalam Jumlah Perdagangan, menyokong pelbagai transaksi, menyediakan analisis pasaran AI dan pemantauan data rantaian. 2. Binance: Pertukaran terbesar di dunia, menyediakan keadaan pasaran yang mendalam dan penawaran mata wang pertama yang baru. 3. Pintu Terbuka Sesame: Dikenali untuk perdagangan tempat dan saluran OTC, ia menyediakan strategi perdagangan automatik. 4. Coinmarketcap: Platform data pasaran yang berwibawa, meliputi 20,000 mata wang. 5. Coingecko: Dikenali untuk analisis sentimen komuniti, ia menyediakan pemantauan trend DEFI dan NFT. 6. Akaun bukan kecil: Platform pasaran domestik, menyediakan analisis hubungan antara pasaran A dan pasaran mata wang. 7. Kewangan On-Rantaian: Fokus pada berita blockchain dan mengemas kini laporan mendalam setiap hari. 8. Kewangan Emas: 24 Kecil

Platform mata wang digital yang boleh dipercayai termasuk: 1.
