1
2/*
3如有转载,请注明作者
4
5原作者: 何志强
6改进: SonyMusic[ [email protected] ]
7文件: ubb.php
8备注: 说是改进,其实核心函数parse()已经完全重写了,而且思路也是不一样的。
9不过仍是受何志强的例子的启发,而且测试的例子还有URLCHECK等几个函数也是沿用的何志强的程序,谢谢何志强。
10目前还没有颜色的功能,但我会加入的。
11如果在程序上有什么BUG或不便的地方,请给我MAIL。
12谢谢!
13改进功能:
14对字符串进行UBB编码,该类目前只支持下列几个简单且实用的编码:
151\. URL裢接
16[url] http://phpuser.com/ [/url]
17http://头可以不需要
18如[url]phpuser.com[/url]也是可以的。
192\. Email裢接
20[email] [email protected] [/email]
213\. 图片裢接
22[img] http://www.phpchina.com/images/logo.gif [/img]
23同URL链接一样,前面的http也可以不要。
244\. 文字方面
25[b]粗体字[/b]
26[i]斜体字[/i]
27[u]加下划线[/u]
28[h1]1号标题字[/h1] ... [h6]6号标题字[/h6]
29[sup][/sup]
30[sub][/sub]
31[tt][/tt]
32[s][/s]
33[strike][/strike]
34[em][/em]
35[strong][/strong]
36[code][/code]
37[samp][/samp]
38[kbd][/kbd]
39[var][/var]
40[dfn][/dfn]
41[cite][/cite]
42[small][/small]
43[big][/big]
44[blink][/blink]
45注意以下几点:
461\. url,email,img等标签是不分大小写的.
472\. 在标签中不允许有TAB键出现,但空格允许。
483\. 该类要调用htmlencode,htmlencode4textarea,emailcheck函数和urlcheck类.
494\. 修改后支持嵌套,但url,email,img这三个标签不是允许嵌套的。
50技术资料:
51Ultimate Bulletin Board
52http://www.ultimatebb.com/
53What is UBB Code
54http://www.scriptkeeper.com/ubb/ubbcode.html
55*/
56
57include("urlcheck.php");
58include("otherfunc.php"); //这两个文件的内容,附在最后。
59
60//ubbcode类
61class ubbcode{
62var $call_time=0;
63//可处理标签及处理函数对应表
64var $tags = array( //小写的标签 => 对应的处理函数
65'url' => '$this->url',
66'email' => '$this->email',
67'img' => '$this->img',
68'b' => '$this->simple',
69'i' => '$this->simple',
70'u' => '$this->simple',
71'tt' => '$this->simple',
72's' => '$this->simple',
73'strike' => '$this->simple',
74'h1' => '$this->simple',
75'h2' => '$this->simple',
76'h3' => '$this->simple',
77'h4' => '$this->simple',
78'h5' => '$this->simple',
79'h6' => '$this->simple',
80'sup' => '$this->simple',
81'sub' => '$this->simple',
82'em' => '$this->simple',
83'strong' => '$this->simple',
84'code' => '$this->simple',
85'samp' => '$this->simple',
86'kbd' => '$this->simple',
87'var' => '$this->simple',
88'dfn' => '$this->simple',
89'cite' => '$this->simple',
90'small' => '$this->simple',
91'big' => '$this->simple',
92'blink' => '$this->simple'
93);
94//url裢接属性
95var $attr_url;
96//url合法性检查对象
97var $urlcheck;
98
99function ubbcode($attr_url){
100$this->attr_url = ''.$attr_url;
101$this->urlcheck = new urlcheck();
102}
103
104//对$str进行UBB编码解析
105function parse($str){
106$this->call_time++;
107$parse = ''.htmlencode($str);
108
109$ret = '';
110while(true){
111$eregi_ret=eregi("[[#]{0,1}[[:alnum:]]{1,7}]",$parse,$eregi_arr); //查找[xx]
112if(!$eregi_ret){
113$ret .= $parse;
114break; //如果没有,返回
115}
116$pos = @strpos ($parse,$eregi_arr[0]);
117$tag_len=strlen($eregi_arr[0])-2;//标记长度
118$tag_start=substr($eregi_arr[0],1,$tag_len);
119$tag=strtolower($tag_start);
120
121if((($tag=="url") or ($tag=="email") or ($tag=="img")) and ($this->call_time>1)){
122echo $this->call_time."
<br/>
1";
2return $parse;//如果不能是不能嵌套的标记,直接返回
3}
4
5$parse2 = substr($parse,0,$pos);//标记之前
6$parse = substr($parse,$pos+$tag_len+2);//标记之后
7if(!isset($this->tags[$tag])){
8echo "$tag_start
<br/>
1";
2$ret .= $parse2.'['.$tag_start.']';
3continue;//如果是不支持的标记
4}
5
6//查找对对应的结束标记
7$eregi_ret=eregi("[/".$tag."]",$parse,$eregi_arr);
8if(!$eregi_ret){
9$ret .= $parse2.'['.$tag_start.']';
10continue;//如果没有对应该的结束标记
11}
12$pos=strpos($parse,$eregi_arr[0]);
13$value=substr($parse,0,$pos);//这是起止标记之间的内容
14$tag_end=substr($parse,$pos+2,$tag_len);
15$parse=substr($parse,$pos+$tag_len+3);//结束标记之后的内容
16
17if(($tag!="url") and ($tag!="email") and ($tag!="img")){
18$value=$this->parse($value);
19}
20
21$ret .= $parse2;
22eval('$ret .= '.$this->tags[$tag].'("'.$tag_start.'","'.$tag_end.'","'.$value.'");');
23}
24$this->call_time--;
25return $ret;
26}
27
28function simple($start,$end,$value){
29return '<'.$start.'>'.$value.'
30<!--'.$end.'-->
31';
32}
33
34function url($start,$end,$value){
35$trim_value=trim($value);
36if (strtolower(substr($trim_value,0,7))!="http://")
37$trim_value="http://".$trim_value;
38if($this->urlcheck->check($trim_value)) return '
<a '.$this-="" href="'.$trim_value.'">attr_url.'>'.$value.'</a>
1';
2else return '['.$start.']'.$value.'[/'.$end.']';
3}
4
5function email($start,$end,$value){
6if(emailcheck($value)) return '
<a href="mailto:'.$value.'">'.$value.'</a>
1';
2else return '['.$start.']'.$value.'[/'.$end.']';
3}
4
5function img($start,$end,$value){
6$trim_value=trim($value);
7if ((strtolower(substr($trim_value,0,7))!="http://") or ($this->urlcheck->check($trim_value)))
8return '
<img src="'.$trim_value.'"/>
1';
2else return '['.$start.']'.$value.'[/'.$end.']';
3}
4}
5
6//测试
7echo '
<html>';
echo '<head><title>测试</title></head>';
echo '<body>';
echo '<form action="'.str2url($PATH_INFO).'" method="post">';
echo '<textarea cols="100" name="ubb" rows="10">'.htmlencode4textarea($ubb).'</textarea><br/>';
echo '<input type="submit" value="转换"/>';
echo '</form>';
if(isset($ubb)){
$ubbcode = new ubbcode('target="_blank"');
echo '<hr/>'.$ubbcode->parse($ubb);
}
echo '</body>';
echo '</html>
1';
2
文件urlcheck.php的内容:
1
2//urlcheck.php
3class urlcheck{
4var $regex = array(//协议名(注意在这里必须写成小写) => 对应的正则表达式
5'ftp' => '$this->ftpurl',
6'file' => '$this->fileurl',
7'http' => '$this->httpurl',
8'https' => '$this->httpurl',
9'gopher' => '$this->gopherurl',
10'news' => '$this->newsurl',
11'nntp' => '$this->nntpurl',
12'telnet' => '$this->telneturl',
13'wais' => '$this->waisurl'
14);
15
16var $lowalpha;
17var $hialpha;
18var $alpha;
19var $digit;
20var $safe;
21var $extra;
22var $national;
23var $punctuation;
24var $reserved;
25var $hex;
26var $escape;
27var $unreserved;
28var $uchar;
29var $xchar;
30var $digits;
31
32var $urlpath;
33var $password;
34var $user;
35var $port;
36var $hostnumber;
37var $alphadigit;
38var $toplabel;
39var $domainlabel;
40var $hostname;
41var $host;
42var $hostport;
43var $login;
44
45//ftp
46var $ftptype;
47var $fsegment;
48var $fpath;
49var $ftpurl;
50
51//file
52var $fileurl;
53
54//http,https
55var $search;
56var $hsegment;
57var $hpath;
58var $httpurl;
59
60//gopher
61var $gopher_string;
62var $selector;
63var $gtype;
64var $gopherurl;
65
66//news
67var $article;
68var $group;
69var $grouppart;
70var $newsurl;
71
72//nntp
73var $nntpurl;
74
75//telnet
76var $telneturl;
77
78//wais
79var $wpath;
80var $wtype;
81var $database;
82var $waisdoc;
83var $waisindex;
84var $waisdatabase;
85var $waisurl;
86
87function check($url){
88$pos = @strpos ($url,':',1);
89if($pos<1) return false;
90$prot = substr($url,0,$pos);
91if(!isset($this->regex[$prot])) return false;
92eval('$regex = '.$this->regex[$prot].';');
93return ereg('^'.$regex.'$',$url);
94}
95
96function urlcheck(){
97$this->lowalpha = '[a-z]';
98$this->hialpha = '[A-Z]';
99$this->alpha = '('.$this->lowalpha.'|'.$this->hialpha.')';
100$this->digit = '[0-9]';
101$this->safe = '[$.+_-]';
102$this->extra = '[*()'!,]';
103$this->national = '([{}|^~`]|\\[|\\])';
104$this->punctuation = '[<>#%"]';
105$this->reserved = '[?;/: @&= ]';
106$this->hex = '('.$this->digit.'|[a-fA-F])';
107$this->escape = '(%'.$this->hex.'{2})';
108$this->unreserved = '('.$this->alpha.'|'.$this->digit.'|'.$this->safe.'|'.$this->extra.')';
109$this->uchar = '('.$this->unreserved.'|'.$this->escape.')';
110$this->xchar = '('.$this->unreserved.'|'.$this->reserved.'|'.$this->escape.')';
111$this->digits = '('.$this->digit.'+)';
112
113$this->urlpath = '('.$this->xchar.'*)';
114$this->password = '(('.$this->uchar.'|[?;&=]'.')*)';
115$this->user = '(('.$this->uchar.'|[?;&=]'.')*)';
116$this->port = $this->digits;
117$this->hostnumber = '('.$this->digits.'.'.$this->digits.'.'.$this->digits.'.'.$this->digits.')';
118$this->alphadigit = '('.$this->alpha.'|'.$this->digit.')';
119$this->toplabel = '('.$this->alpha.'|('.$this->alpha.'('.$this->alphadigit.'|-)*'.$this->alphadigit.'))';
120$this->domainlabel = '('.$this->alphadigit.'|('.$this->alphadigit.'('.$this->alphadigit.'|-)*'.$this->alphadigit.'))';
121$this->hostname = '(('.$this->domainlabel.'\\.)*'.$this->toplabel.')';
122$this->host = '('.$this->hostname.'|'.$this->hostnumber.')';
123$this->hostport = '('.$this->host.'(:'.$this->port.')?)';
124$this->login = '(('.$this->user.'(:'.$this->password.')?@)?'.$this->hostport.')';
125
126$this->ftptype = '[aidAID]';
127$this->fsegment = '(('.$this->uchar.'|[?: @&= ])*)';
128$this->fpath = '('.$this->fsegment.'(/'.$this->fsegment.')*)';
129$this->ftpurl = '([fF][tT][pP]://'.$this->login.'(/'.$this->fpath.'(;[tT][yY][pP][eE]='.$this->ftptype.')?)?)';
130
131$this->fileurl = '([fF][iI][lL][eE]://('.$this->host.'|[lL][oO][cC][aA][lL][hH][oO][sS][tT])?/'.$this->fpath.')';
132
133$this->search = '(('.$this->uchar.'|[;: @&= ])*)';
134$this->hsegment = '(('.$this->uchar.'|[;: @&= ])*)';
135$this->hpath = '('.$this->hsegment.'(/'.$this->hsegment.')*)';
136$this->httpurl = '([hH][tT][tT][pP][sS]?://'.$this->hostport.'(/'.$this->hpath.'([?]'.$this->search.')?)?)';
137
138$this->gopher_string = '('.$this->xchar.'*)';
139$this->selector = '('.$this->xchar.'*)';
140$this->gtype = $this->xchar;
141$this->gopherurl = '([gG][oO][pP][hH][eE][rR]://'.$this->hostport.'(/('.$this->gtype.'('.$this->selector.'(%09'.$this->search.'(%09'.$this->gopher_string.')?)?)?)?)?)';
142
143$this->article = '(('.$this->uchar.'|[;/?:&=]) +@'.$this- >host.')';
144$this->group = '('.$this->alpha.'('.$this->alpha.'|'.$this->digit.'|[-.+_])*)';
145$this->grouppart = '([*]|'.$this->group.'|'.$this->article.')';
146$this->newsurl = '([nN][eE][wW][sS]:'.$this->grouppart.')';
147
148$this->nntpurl = '([nN][nN][tT][pP]://'.$this->hostport.'/'.$this->group.'(/'.$this->digits.')?)';
149
150$this->telneturl = '([tT][eE][lL][nN][eE][tT]://'.$this->login.'/?)';
151
152$this->wpath = '('.$this->uchar.'*)';
153$this->wtype = '('.$this->uchar.'*)';
154$this->database = '('.$this->uchar.'*)';
155$this->waisdoc = '([wW][aA][iI][sS]://'.$this->hostport.'/'.$this->database.'/'.$this->wtype.'/'.$this->wpath.')';
156$this->waisindex = '([wW][aA][iI][sS]://'.$this->hostport.'/'.$this->database.'[?]'$this->search.')';
157$this->waisdatabase = '([wW][aA][iI][sS]://'.$this->hostport.'/'.$this->database.')';
158$this->waisurl = '('.$this->waisdatabase.'|'.$this->waisindex.'|'.$this->waisdoc.')';
159}
160}
161
文件otherfunc.php的内容:
1
2//otherfunc.php
3function htmlencode($str){
4$str = (string)$str;
5
6$ret = '';
7$len = strlen($str);
8$nl = false;
9for($i=0;$i<$len;$i++){
10$chr = $str[$i];
11switch($chr){
12case '<':
13$ret .= '<';
14$nl = false;
15break;
16case '>':
17$ret .= '>';
18$nl = false;
19break;
20case '"':
21$ret .= '"';
22$nl = false;
23break;
24case '&':
25$ret .= '&';
26$nl = false;
27break;
28/*
29case ' ':
30$ret .= ' ';
31$nl = false;
32break;
33*/
34case chr(9):
35$ret .= ' ';
36$nl = false;
37break;
38case chr(10):
39if($nl) $nl = false;
40else{
41$ret .= '
<br/>
1';
2$nl = true;
3}
4break;
5case chr(13):
6if($nl) $nl = false;
7else{
8$ret .= '
<br/>
1';
2$nl = true;
3}
4break;
5default:
6$ret .= $chr;
7$nl = false;
8break;
9}
10}
11
12return $ret;
13}
14
15
16function htmlencode4textarea($str){
17$str = (string)$str;
18
19$ret = '';
20$len = strlen($str);
21for($i=0;$i<$len;$i++){
22$chr = $str[$i];
23switch($chr){
24case '<':
25$ret .= '<';
26break;
27case '>':
28$ret .= '>';
29break;
30case '"':
31$ret .= '"';
32break;
33case '&':
34$ret .= '&';
35break;
36case ' ':
37$ret .= ' ';
38break;
39case chr(9):
40$ret .= ' ';
41break;
42default:
43$ret .= $chr;
44break;
45}
46}
47
48return $ret;
49}
50
51function emailcheck($email){
52$ret=false;
53if(strstr($email, '@' ) && strstr($email, '.')){
54if(eregi("^([_a-z0-9]+([\\._a-z0-9-]+)*)@([a-z0-9]{2,}(\\.[a-z0-9-]{2,})*\\.[a-z]{2,3})$", $email)){
55$ret=true;
56}
57}
58return $ret;
59}
60
61function str2url($path){
62return eregi_replace("%2f","/",urlencode($path));
63}