我有一个当前为纯文本的注释表单。这很好也很容易,因为我可以使用strip_tag和htmlspecialchars从中剥离出任何类似HTML的东西
然而,有计划把它变成一个HTML表单,支持几个标签<a><b><p><h3>
。。。等
我看到的问题是,即使对输入进行strip_tag标记并只保留这些标记,我仍然可以在标记中使用XSS和jscript。
我知道HTML净化器可以用来解决这个问题,但它看起来非常笨重、缓慢,我很难相信没有更好的方法吗?
我曾考虑使用BBCode编辑器,但假设这些代码以BB的形式插入数据库,我将如何将其从BB转换回HTML以显示它?
如果您有时间和精力编写自己的验证方案,请考虑另一个时间,因为这非常复杂。
首先,看看如果不使用递归会发生什么。
恶语:复制此
CopyCopyThisThis
这就剩下了
CopyThis
坏词。。。
BBCode确实是一个非常简单有用的解决方案。
我正在使用MarkItUp!编辑,但你肯定能找到很多其他人。
然后我该如何将它从BB转换回HTML以显示它?
答案很简单:你可以使用preg_replace
我自己实现了这一点,所以我可以让您使用我的解析器代码。它翻译基本标签,以及一些自定义标签,如[center]
。添加自己的标签或替换当前的标签非常容易。
该脚本包含一个包含正则表达式和替换项的巨大数组,以及一个preg_replace
调用。
function replaceBBcode($str) {
$replace = array(
// inline text formats
'/'[b'](.*?)'['/b']/is' => '<b>$1</b>',
'/'[i'](.*?)'['/i']/is' => '<i>$1</i>',
'/'[u'](.*?)'['/u']/is' => '<u>$1</u>',
'/'[s'](.*?)'['/s']/is' => '<s>$1</s>',
'/'[sup'](.*?)'['/sup']/is' => '<sup>$1</sup>',
'/'[sub'](.*?)'['/sub']/is' => '<sub>$1</sub>',
// headings
'/'[h1'](.*?)'['/h1']/is' => '<h1>$1</h1>',
'/'[h2'](.*?)'['/h2']/is' => '<h2>$1</h2>',
'/'[h3'](.*?)'['/h3']/is' => '<h3>$1</h3>',
'/'[h4'](.*?)'['/h4']/is' => '<h4>$1</h4>',
'/'[h5'](.*?)'['/h5']/is' => '<h5>$1</h5>',
// formatting tags
'/'[(?:hr|line)']/is' => '<hr />',
'/'[br'/?']/is' => '<br />',
// links
'/'[url=([^']]+)'](.*?)'['/url']/is' => '<a href="$1">$2</a>',
'/'[link=([^']]+)'](.*?)'['/link']/is' => '<a href="$1">$2</a>',
'/'[url'](.*?)'['/url']/is' => '<a href="$1" title="$1">$1</a>',
'/'[link'](.*?)'['/link']/is' => '<a href="$1" title="$1">$1</a>',
'/'[img=([^']]+)']/is' => '<img src="$1" alt="" />',
// text blocks and block formats
'/'[font=([^']]+)'](.*?)'['/font']/is' => '<span style="font-family: $1;">$2</span>',
'/'[size=([0-9]+)'](.*?)'['/size']/is' => '<span style="font-size: $1pt;">$2</span>',
'/'[color=([^']]+)'](.*?)'['/color']/is' => '<span style="color: $1;">$2</span>',
'/'[bgcolor=([^']]+)'](.*?)'['/bgcolor']/is' => '<span style="background-color: $1;">$2</span>',
'/'[p'](.*?)'['/p']/is' => '<p>$1</p>',
// alignment blocks
'/'[align=(left|center|right|justify)'](.*?)'['/align']/is' => '<div style="text-align: $1;">$2</div>',
'/'[center'](.*?)'['/center']/is' => '<div style="text-align: center;">$1</div>',
'/'[left'](.*?)'['/left']/is' => '<div style="text-align: left;">$1</div>',
'/'[right'](.*?)'['/right']/is' => '<div style="text-align: right;">$1</div>',
'/'[justify'](.*?)'['/justify']/is' => '<div style="text-align: justify;">$1</div>',
// lists
'/'[list=(disc|circle|square)'](.*?)'['/list']/is' => '<ul style="list-style-type:$1;">$2</ul>',
'/'[list'](.*?)'['/list']/is' => '<ul>$1</ul>',
'/'[list=a'](.*?)'['/list']/s' => '<ol style="list-style-type:lower-alpha;">$1</ol>',
'/'[LIST=a'](.*?)'['/LIST']/s' => '<ol style="list-style-type:lower-alpha;">$1</ol>',
'/'[list=A'](.*?)'['/list']/s' => '<ol style="list-style-type:upper-alpha;">$1</ol>',
'/'[LIST=A'](.*?)'['/LIST']/s' => '<ol style="list-style-type:upper-alpha;">$1</ol>',
'/'[list=1'](.*?)'['/list']/is' => '<ol style="list-style-type:decimal;">$1</ol>',
'/'[list=I'](.*?)'['/list']/is' => '<ol style="list-style-type:upper-roman;">$1</ol>',
'/'['*']/is' => '<li>',
// videos
'/'[(?:youtube|video|media|movie){1}'](?:https?':'/'/)?(?:www'.)?(?:youtube'.com'/watch'?v=|youtube'.com'/v'/|youtu'.be'/)?([a-z0-9'-'_]+)'['/(?:youtube|video|media|movie){1}']/is'
=> '<iframe width="560" height="315" src="http://www.youtube.com/embed/$1?wmode=opaque" frameborder="0" allowfullscreen></iframe>',
);
// do the tags
$str = preg_replace (array_keys($replace), array_values($replace), $str);
return $str;
}
然而,这对于嵌套标签来说并不好用。为了用嵌套标签替换代码,我使用了这样一个循环:
$str = "... text to process ...";
// remove unwanted tags
$str = strip_tags($str);
// make entities of special chars (not quotes)
$str = htmlentities($str, ENT_NOQUOTES, $encoding = 'UTF-8');
$str_old="";
do {
$str_old=$str;
$str=replaceBBcode($str);
} while ($str_old != $str);
// now $str contains the final html tags