一个用PHP实现的UBB类
2024年02月23日
<?php/*
如有转载,请注明作者
作者:何志强
文件:ubb.php
备注:说是改进,其实核心函数parse()已经完全重写了,而且思路也是不一样的。
不过仍是受何志强的例子的启发,而且测试的例子还有URLCHECK等几个函数也是沿用的何志强的程序,谢谢何志强。
目前还没有颜色的功能,但我会加入的。
如果在程序上有什么BUG或不便的地方,请给我MAIL。
谢谢!
改进功能:
对字符串进行UBB编码,该类目前只支持下列几个简单且实用的编码:
1.URL裢接
http://www.phpexe.com/
http://头可以不需要
如phpexe.com也是可以的。
2.Email裢接
demo 163.net
3.图片裢接
同URL链接一样,前面的http也可以不要。
4.文字方面
粗体字
斜体字
加下划线
1号标题字
...
6号标题字
[tt][/tt]
[s][/s]
[em][/em]
[strong][/strong]
[samp][/samp]
[kbd][/kbd]
[var][/var]
[dfn][/dfn]
[cite][/cite]
注意以下几点:
1.url,email,img等标签是不分大小写的.
2.在标签中不允许有TAB键出现,但空格允许。
3.该类要调用htmlencode,htmlencode4textarea,emailcheck函数和urlcheck类.
4.修改后支持嵌套,但url,email,img这三个标签不是允许嵌套的。
技术资料:
Ultimate Bulletin Board
http://www.ultimatebb.com/
What is UBB Code
http://www.scriptkeeper.com/ubb/ubbcode.html
*/
include("urlcheck.php");
include("otherfunc.php");//这两个文件的内容,附在最后。
//ubbcode类
class ubbcode{
var$call_time=0;
//可处理标签及处理函数对应表
var$tags=array(//小写的标签=>对应的处理函数
'url'=>'$this->url',
'email'=>'$this->email',
'img'=>'$this->img',
'b'=>'$this->simple',
'i'=>'$this->simple',
'u'=>'$this->simple',
'tt'=>'$this->simple',
's'=>'$this->simple',
'strike'=>'$this->simple',
'h1'=>'$this->simple',
'h2'=>'$this->simple',
'h3'=>'$this->simple',
'h4'=>'$this->simple',
'h5'=>'$this->simple',
'h6'=>'$this->simple',
'sup'=>'$this->simple',
'sub'=>'$this->simple',
'em'=>'$this->simple',
'strong'=>'$this->simple',
'code'=>'$this->simple',
'samp'=>'$this->simple',
'kbd'=>'$this->simple',
'var'=>'$this->simple',
'dfn'=>'$this->simple',
'cite'=>'$this->simple',
'small'=>'$this->simple',
'big'=>'$this->simple',
'blink'=>'$this->simple'
);
//url裢接属性
var$attr_url;
//url合法性检查对象
var$urlcheck;
function ubbcode($attr_url){
$this->attr_url=''.$attr_url;
$this->urlcheck=new urlcheck();
}
//对$str进行UBB编码解析
function parse($str){
$this->call_time++;
$parse=''.htmlencode($str);
$ret='';
while(true){
$eregi_ret=eregi("\{#]{0,1}{:alnum:}{1,7}\]",$parse,$eregi_arr);//查找[xx]
if(!$eregi_ret){
$ret.=$parse;
break;//如果没有,返回
}
$pos= strpos($parse,$eregi_arr[0]);
$tag_len=strlen($eregi_arr[0])-2;//标记长度
$tag_start=substr($eregi_arr[0],1,$tag_len);
$tag=strtolower($tag_start);
if((($tag=="url")or($tag=="email")or($tag=="img"))and($this->call_time>1)){
echo$this->call_time."<br>";
return$parse;//如果不能是不能嵌套的标记,直接返回
}
$parse2=substr($parse,0,$pos);//标记之前
$parse=substr($parse,$pos+$tag_len+2);//标记之后
if(!isset($this->tags[$tag])){
echo"$tag_start<br>";
$ret.=$parse2.'['.$tag_start.']';
continue;//如果是不支持的标记
}
//查找对对应的结束标记
$eregi_ret=eregi("\[\/".$tag."\]",$parse,$eregi_arr);
if(!$eregi_ret){
$ret.=$parse2.'['.$tag_start.']';
continue;//如果没有对应该的结束标记
}
$pos=strpos($parse,$eregi_arr[0]);
$value=substr($parse,0,$pos);//这是起止标记之间的内容
$tag_end=substr($parse,$pos+2,$tag_len);
$parse=substr($parse,$pos+$tag_len+3);//结束标记之后的内容
if(($tag!="url")and($tag!="email")and($tag!="img")){
$value=$this->parse($value);
}
$ret.=$parse2;
eval('$ret.='.$this->tags[$tag].'("'.$tag_start.'","'.$tag_end.'","'.$value.'");');
}
$this->call_time--;
return$ret;
}
function simple($start,$end,$value){
return'<'.$start.'>'.$value.'</'.$end.'>';
}
function url($start,$end,$value){
$trim_value=trim($value);
if(strtolower(substr($trim_value,0,7))!="http://")
$trim_value="http://".$trim_value;
if($this->urlcheck->check($trim_value))return'<a href="'.$trim_value.'"'.$this->attr_url.'>'.$value.'</a>';
else return'['.$start.']'.$value.'[/'.$end.']';
}
function email($start,$end,$value){
if(emailcheck($value))return'<a href="mailto:'.$value.'">'.$value.'</a>';
else return'['.$start.']'.$value.'[/'.$end.']';
}
function img($start,$end,$value){
$trim_value=trim($value);
if((strtolower(substr($trim_value,0,7))!="http://")or($this->urlcheck->check($trim_value)))
return'<img src="'.$trim_value.'"></img>';
else return'['.$start.']'.$value.'[/'.$end.']';
}
}
//测试
echo'<html>';
echo'<head><title>测试</title></head>';
echo'<body>';
echo'<form action="'.str2url($PATH_INFO).'"method="post">';
echo'<textarea cols="100"rows="10"name="ubb">'.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>';
?>
文件urlcheck.php的内容
<?php
//urlcheck.php
class urlcheck{
var$regex=array(//协议名(注意在这里必须写成小写)=>对应的正则表达式
'ftp'=>'$this->ftpurl',
'file'=>'$this->fileurl',
'http'=>'$this->httpurl',
'https'=>'$this->httpurl',
'gopher'=>'$this->gopherurl',
'news'=>'$this->newsurl',
'nntp'=>'$this->nntpurl',
'telnet'=>'$this->telneturl',
'wais'=>'$this->waisurl'
);
var$lowalpha;
var$hialpha;
var$alpha;
var$digit;
var$safe;
var$extra;
var$national;
var$punctuation;
var$reserved;
var$hex;
var$escape;
var$unreserved;
var$uchar;
var$xchar;
var$digits;
var$urlpath;
var$password;
var$user;
var$port;
var$hostnumber;
var$alphadigit;
var$toplabel;
var$domainlabel;
var$hostname;
var$host;
var$hostport;
var$login;
//ftp
var$ftptype;
var$fsegment;
var$fpath;
var$ftpurl;
//file
var$fileurl;
//http,https
var$search;
var$hsegment;
var$hpath;
var$httpurl;
//gopher
var$gopher_string;
var$selector;
var$gtype;
var$gopherurl;
//news
var$article;
var$group;
var$grouppart;
var$newsurl;
//nntp
var$nntpurl;
//telnet
var$telneturl;
//wais
var$wpath;
var$wtype;
var$database;
var$waisdoc;
var$waisindex;
var$waisdatabase;
var$waisurl;
function check($url){
$pos= strpos($url,':',1);
if($pos<1)return false;
$prot=substr($url,0,$pos);
if(!isset($this->regex[$prot]))return false;
eval('$regex='.$this->regex[$prot].';');
return ereg('^'.$regex.'$',$url);
}
function urlcheck(){
$this->lowalpha='[a-z]';
$this->hialpha='[A-Z]';
$this->alpha='('.$this->lowalpha.'|'.$this->hialpha.')';
$this->digit='[0-9]';
$this->safe='[$.+_-]';
$this->extra='[*()\'!,]';
$this->national='([{}|\^~`]|\\[|\\])';
$this->punctuation='[<>#%"]';
$this->reserved='[?;/: &=]';
$this->hex='('.$this->digit.'|[a-fA-F])';
$this->escape='(%'.$this->hex.'{2})';
$this->unreserved='('.$this->alpha.'|'.$this->digit.'|'.$this->safe.'|'.$this->extra.')';
$this->uchar='('.$this->unreserved.'|'.$this->escape.')';
$this->xchar='('.$this->unreserved.'|'.$this->reserved.'|'.$this->escape.')';
$this->digits='('.$this->digit.'+)';
$this->urlpath='('.$this->xchar.'*)';
$this->password='(('.$this->uchar.'|[?;&=]'.')*)';
$this->user='(('.$this->uchar.'|[?;&=]'.')*)';
$this->port=$this->digits;
$this->hostnumber='('.$this->digits.'.'.$this->digits.'.'.$this->digits.'.'.$this->digits.')';
$this->alphadigit='('.$this->alpha.'|'.$this->digit.')';
$this->toplabel='('.$this->alpha.'|('.$this->alpha.'('.$this->alphadigit.'|-)*'.$this->alphadigit.'))';
$this->domainlabel='('.$this->alphadigit.'|('.$this->alphadigit.'('.$this->alphadigit.'|-)*'.$this->alphadigit.'))';
$this->hostname='(('.$this->domainlabel.'\\.)*'.$this->toplabel.')';
$this->host='('.$this->hostname.'|'.$this->hostnumber.')';
$this->hostport='('.$this->host.'(:'.$this->port.')?)';
$this->login='(('.$this->user.'(:'.$this->password.')? )?'.$this->hostport.')';
$this->ftptype='[aidAID]';
$this->fsegment='(('.$this->uchar.'|[?: &=])*)';
$this->fpath='('.$this->fsegment.'(/'.$this->fsegment.')*)';
$this->ftpurl='([fF][tT][pP]://'.$this->login.'(/'.$this->fpath.'(;[tT][yY][pP][eE]='.$this->ftptype.')?)?)';
$this->fileurl='([fF][iI][lL][eE]://('.$this->host.'|[lL][oO][cC][aA][lL][hH][oO][sS][tT])?/'.$this->fpath.')';
$this->search='(('.$this->uchar.'|[;: &=])*)';
$this->hsegment='(('.$this->uchar.'|[;: &=])*)';
$this->hpath='('.$this->hsegment.'(/'.$this->hsegment.')*)';
$this->httpurl='([hH][tT][tT][pP][sS]?://'.$this->hostport.'(/'.$this->hpath.'([?]'.$this->search.')?)?)';
$this->gopher_string='('.$this->xchar.'*)';
$this->selector='('.$this->xchar.'*)';
$this->gtype=$this->xchar;
$this->gopherurl='([gG][oO][pP][hH][eE][rR]://'.$this->hostport.'(/('.$this->gtype.'('.$this->selector.'(%09'.$this->search.'(%09'.$this->gopher_string.')?)?)?)?)?)';
$this->article='(('.$this->uchar.'|[;/?:&=])+ '.$this->host.')';
$this->group='('.$this->alpha.'('.$this->alpha.'|'.$this->digit.'|[-.+_])*)';
$this->grouppart='([*]|'.$this->group.'|'.$this->article.')';
$this->newsurl='([nN][eE][wW][sS]:'.$this->grouppart.')';
$this->nntpurl='([nN][nN][tT][pP]://'.$this->hostport.'/'.$this->group.'(/'.$this->digits.')?)';
$this->telneturl='([tT][eE][lL][nN][eE][tT]://'.$this->login.'/?)';
$this->wpath='('.$this->uchar.'*)';
$this->wtype='('.$this->uchar.'*)';
$this->database='('.$this->uchar.'*)';
$this->waisdoc='([wW][aA][iI][sS]://'.$this->hostport.'/'.$this->database.'/'.$this->wtype.'/'.$this->wpath.')';
$this->waisindex='([wW][aA][iI][sS]://'.$this->hostport.'/'.$this->database.'[?]'.$this->search.')';
$this->waisdatabase='([wW][aA][iI][sS]://'.$this->hostport.'/'.$this->database.')';
$this->waisurl='('.$this->waisdatabase.'|'.$this->waisindex.'|'.$this->waisdoc.')';
}
}
?>
文件otherfunc.php的内容
<?php
//otherfunc.php
function htmlencode($str){
$str=(string)$str;
$ret='';
$len=strlen($str);
$nl=false;
for($i=0;$i<$len;$i++){
$chr=$str[$i];
switch($chr){
case'<':
$ret.='<';
$nl=false;
break;
case'>':
$ret.='>';
$nl=false;
break;
case'"':
$ret.='"';
$nl=false;
break;
case'&':
$ret.='&';
$nl=false;
break;
/*
case'':
$ret.='';
$nl=false;
break;
*/
case chr(9):
$ret.='';
$nl=false;
break;
case chr(10):
if($nl)$nl=false;
else{
$ret.='<br>';
$nl=true;
}
break;
case chr(13):
if($nl)$nl=false;
else{
$ret.='<br>';
$nl=true;
}
break;
default:
$ret.=$chr;
$nl=false;
break;
}
}
return$ret;
}
function htmlencode4textarea($str){
$str=(string)$str;
$ret='';
$len=strlen($str);
for($i=0;$i<$len;$i++){
$chr=$str[$i];
switch($chr){
case'<':
$ret.='<';
break;
case'>':
$ret.='>';
break;
case'"':
$ret.='"';
break;
case'&':
$ret.='&';
break;
case'':
$ret.='';
break;
case chr(9):
$ret.='';
break;
default:
$ret.=$chr;
break;
}
}
return$ret;
}
function emailcheck($email){
$ret=false;
if(strstr($email,' ')&&strstr($email,'.')){
if(eregi("^([_a-z0-9]+([\\._a-z0-9-]+)*) ([a-z0-9]{2,}(\\.[a-z0-9-]{2,})*\\.[a-z]{2,3})$",$email)){
$ret=true;
}
}
return$ret;
}
function str2url($path){
return eregi_replace("%2f","/",urlencode($path));
}
?>