UBB 解析类

类别:编程语言 点击:0 评论:0 推荐:

UBB 解析类

<?php
/************************************************************
*                 UBB 解析器  v1.0b
*
*  该解释器支持的是UBB的子集(标准集我也不知到啥样)
*  需要其他的可以自行扩展,
*  理论上支持任何[x=a,b,c]xxx[/x]结构的解析
*
*  源代码由zy提供,在此思路上重写了大部分代码
*
*  如果你有什么好的建议请联系 [email protected]
*  正则表达式的用法得到 [email protected] 的大力支持,在此表示感谢
*              耙子   2001/12/31
*            http://www.fogsun.com
*
*          $ 转载请完整保留此段文字 $
*
*               使用说明
*  1.本代码未对html进行任何限制,仅增加了对UBB-〉Html的转换支持,
*    如果需要请在调用本代码前自行过滤html标签,
*  2.调用代码前请用 stripslashes 函数去掉转换内容中的冗余反斜杠,
*    否则结果可能会出现问题
*  3.UBB 标签中不允许出现空格
*************************************************************/

define ("sVersion", "1.2.1.15 beta");

//ubbcode类 
class ubbcode

    var $nest;  // 递归深度,for debug
    //可处理标签及处理函数表 
    var $tags = array(
        'url' => '$this->url', 
        'email' => '$this->email', 
        'mail' => '$this->email',  // 为了容错,[mail]和[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',
        'fly' => '$this->fly',
        'move' => '$this->move',
        'glow' => '$this->CSSStyle',
        'shadow' => '$this->CSSStyle',
        'blur' => '$this->CSSStyle',
        'wave' => '$this->CSSStyle',
        'sub' => '$this->simple',
        'sup' => '$this->simple',
        'size' => '$this->size',
        'face' => '$this->face',
        'font' => '$this->face',  // 为了容错,[font]和[face]等效
        'color' => '$this->color'
        ); 
   
    function ubbcode()
    { 
      $this->$nest= 0;
      $this->$sLastModified= sprintf("%s", date("Y-m-j H:i", getlastmod()));
    } 

   
    /***********************************************************************
    *  对使用者输入的 E-Mail 作简单的检查,
    *  检查使用者的 E-Mail 字串是否有 @ 字元,
    *  在 @ 字元前有英文字母或数字,在之后有数节字串,
    *  最后的小数点后只能有二个或三个英文字母。
    *  [email protected] 就可以通过检查,[email protected] 就不能通过检查
    ************************************************************************/
    function emailcheck($str)
    {
      if (eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $str))
        return true;
      else
        return false; 
    }
   

    /***********************************************************************
    *  对使用者输入的 URL 作简单的检查,
    *  目前只能简单判断,不能自动检查fpt,finger等
    ************************************************************************/
    function checkURL($str)
    {
      $bValidURL= true;
      if (eregi("([a-z0-9-]+([\.][a-z0-9\-]+)+)", $str, $er_arr))
      {   
  /*
  printf ("0. %s <br>\n", $er_arr[0]);
  printf ("1. %s <br>\n", $er_arr[1]);
  printf ("2. %s <br>\n", $er_arr[2]);
  printf ("3. %s <br>\n", $er_arr[3]);
  printf ("4. %s <br>\n", $er_arr[4]);
  */
      }
      else
         $bValidURL= false;
      return $bValidURL;
    }
   
    /***********************************************************************
    *  对使用者输入的 图片URL 作简单的检查,
    *  目前只能简单判断结尾是否为图片文件
    *  不支持由CGI动态生成的图片,比如计数器这类的
    ************************************************************************/
    function checkImgURL($str)
    {
      if ($this->checkURL($str)) {
        if(eregi("\.(jpeg|jpg|gif|bmp|png|pcx|tiff|tga|lwf)$", $str))
          return true;
        else
          return false;
      }
      else
        return false;
    }

    /***********************************************************************
    *  自动补全URL部分,主要是协议前缀,
    *  默认是htpp://,支持https://;ftp://;finger://;gopher://等
    *  函数并不对URL的合法性作检查
    ************************************************************************/
    function formatURL($str)
    {
      if (!eregi("^(ftp|http|https|mms|gopher|finger|bbs|telnet):(\/\/|\\\\)", $str))
        $str= 'http://'.$str;
      return $str;
    }
  
    //对$str进行UBB编码解析 
    function parse($str)
    { 
        $nest ++;
        $parse = ''.($str); 
        $ret = ''; 
        while(true){ 
            //查找[xx] 或者[xx=xx] , 但不包括[xx=]
            $eregi_ret=eregi("\[([a-z][a-z0-9]{0,7})(=[a-z0-9#.:/&@|\?,%=_\+\"\']+)?\]", $parse, $eregi_arr);
            if(!$eregi_ret)
            { 
                $ret .= $parse; 
                break; //如果没有,返回 
            }
/*  for Debug
            else
            {
              printf ("$. %s<br>", $eregi_ret);
              printf ("0. %s<br>", $eregi_arr[0]);
              printf ("1. %s<br>", $eregi_arr[1]);
              printf ("2. %s<br>", $eregi_arr[2]);
              printf ("3. %s<br>", $eregi_arr[3]);
            }
*/
            $pos = @strpos($parse, $eregi_arr[0]);  // 起始位置
            $tag_start= $eregi_arr[1];
            $tag= strtolower($eregi_arr[1]);
            $tag_param= $eregi_arr[2];

            $parse2 = substr($parse, 0, $pos);//标记之前
            $parse = substr($parse, $pos + $eregi_ret);//标记之后
           
            if(!isset($this->tags[$tag]))
            { 
//                echo "$tag.@133:不支持的标记<br>";  // for debug
                $ret .= $parse2.'['.$tag_start.']'; 
                continue;    //如果是不支持的标记 
            } 
           
            //查找对应的结束标记 
            $eregi_ret=eregi("\[(/".$tag.")\]", $parse, $eregi_arr); 
            if(!$eregi_ret)
            { 
//                echo ('没有对应该的结束标记'.$rrr);  //for debug
                $ret .= $parse2.'['.$tag_start.$tag_param.']'; 
                continue;//没有对应该的结束标记 
            } 
           
            $pos= strpos($parse, $eregi_arr[0]); 
            $value= substr($parse, 0, $pos);   //起止标记之间的内容
            $tag_end= $eregi_arr[1];
            $parse= substr($parse, $pos + $eregi_ret);//结束标记之后的内容 
           
            // 允许嵌套标记,递归分析
            if (!(($tag == 'code') or ($tag=="url") or ($tag=="email") or ($tag=="img"))){
                $value= $this->parse($value); 
            }
            $ret.= $parse2;
            $parseFun= sprintf('$ret .= %s($tag_start, $tag_param, $tag_end, $value);', $this->tags[$tag]);
            eval($parseFun); 
        } 
        $nest --;
        return $ret; 
    } 

   
    /*****************************************************
    * 简单替换,类似[b]变为<b>
    * 标签内容不便,只是替代括号为<>
    *****************************************************/
    function simple($start, $para, $end, $value){
        if (strlen($para) > 0)
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
        else
          return sprintf("<%s>%s<%s>", $start, $value, $end);
 


    /*****************************************************
    * 如下认为合法可以没有“http://”;ftp一定要自己加“ftp://”
    * [URL=http://www.fogsun.com]93611[/URL]
    * [URL=http://www.fogsun.com][/URL]
    * [URL]http://www.fogsun.com[/URL]
    *****************************************************/
    function url($start, $para, $end, $value){ 
        $sA= $value;
        $sURL= substr(trim($para), 1);
        if (strlen($sURL) > 0)
        {
          if (strlen($value) == 0)
            $sA= $sURL;
        }
        else
        {
          $sURL= trim($value);
        }
        $sURL= $this->formatURL($sURL);
        if($this->checkURL($sURL))
          return "<a href=\"$sURL\">$sA</a>"; 
        else {
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
        }
    } 
   

    /*****************************************************
    * 如下认为合法可以没有“mailto:”头;
    * [[email protected]]pazee[/email]
    * [[email protected]][/email]
    * [email][email protected][/email]
    *****************************************************/
    function email($start, $para, $end, $value){ 
        $sA= $value;
        $sURL= substr(trim($para), 1);
        if (strlen($sURL) > 0)
        {
          if (strlen($value) == 0)
            $sA= $sURL;
        }
        else
        {
          $sURL= trim($value);
        }
        if (strtolower(substr($sURL, 0, 7)) != "mailto:") 
          $sURL= "mailto:". $sURL; 
        if($this->emailcheck(substr($sURL, 7)))
          return "<a href=\"$sURL\">$sA</a>"; 
        else
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
    } 
   

    /*****************************************************
    * 显示图片;如下用法认为合法
    * [img=www.21cn.com/title.jpg][/img]
    * [img]www.21cn.com/title.jpg[/img]
    *****************************************************/
    function img($start, $para, $end, $value){ 
        $sURL= substr(trim($para), 1);
        if (strlen($sURL) <= 0)
          $sURL= trim($value);
        $sURL= $this->formatURL($sURL);
        if ($this->checkImgURL($sURL)) 
          return sprintf("<img src=\"%s\"></img>", $sURL); 
        else
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
    } 

    /*****************************************************
    * 字符串从右向左循环移动
    * 无参数
    * 等效与html的<marquee>
    *****************************************************/
    function fly($start, $para, $end, $value){ 
      if (strlen($para)>0) // 有参数
        return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
      else
        return '<marquee behavior=alternate scrolldelay=100>'.$value.'</marquee>'; 
    } 
   
    /*****************************************************
    * 字符串来回移动
    * 无参数
    * 等效与html的<marquee>
    *****************************************************/
    function move($start, $para, $end, $value) {
      if (strlen($para)>0) // 有参数
        return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
      else
        return '<marquee  scrolldelay=100>'.$value.'</marquee>'; 
    } 
   

    /*****************************************************
    * 字符晕光效果包括 glow、shadow和blur
    * 字符晕光效果[glow=a,b,c]或者[shadow=a,b,c]
    * 3个参数允许缺省
    * 实现文字阴影特效,
    * glow, shadow,blur 属性依次为颜色、宽度和边界大小
    * wave 属性依次为变形频率、宽度和边界大小
    *****************************************************/
    function CSSStyle(&$start, &$para, &$end, &$value){
        $rets= sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
        if (strlen($para)==0)
        {
          $para="=,,";
        }
        if (eregi("^=([#]?[[:xdigit:]]{6}|[a-z0-9]*),([0-9]*),([0-9]*)", $para, $er_arr))
        {
          $color=  ($er_arr[1] != "") ? $er_arr[1] : red;   // Default Color
          $width=  ($er_arr[2] != "") ? $er_arr[2] : 400;   // Default Width
          $border= ($er_arr[3] != "") ? $er_arr[3] : 5;     // Default Border
          switch ($start)
          {
            case "glow":
            case "shadow":
              $rets= sprintf("<font style=\"FILTER: %s(Color =%s,Strength=%s); width:%s\">%s</font>", $start, $color, $border, $width, $value);
              break;
            case "blur";
              $rets= sprintf("<font style=\"FILTER: %s(Strength=%s);color:%s; width:%s\">%s</font>", $start, $border, $color, $width, $value);
              break;
            case "wave":
              $color=  ($er_arr[1] != "") ? $er_arr[1] : 4;   // Default Color
              $border= ($er_arr[3] != "") ? $er_arr[3] : 2;     // Default Border
              $rets= sprintf("<font style=\"FILTER: %s(Freq=%s, Strength=%s); width:%s\">%s</font>", $start, $color, $border, $width, $value);
              break;
          }
        }
        return  $rets;
    } 


 

    /*****************************************************
    * 字体颜色 [color=n]xxx[/color]
    * n 可以是 #xxxxxx 或者 xxxxxx (6位16进制数)
    * red,greed,blue,black等颜色保留字也有效
    * 等效与html的<font color=n>xxx</font>
    * [color]xxxx[/color]等效于 [color=red]
    *****************************************************/
    function color($start, $para, $end, $value){
        $cl= strtolower(substr($para, 1));
        if ($cl == "")
          $cl= "red";
        if (eregi("(^[#]?[[:xdigit:]]{6})|red|green|blue|yellow|blue|white|gray|brown" ,$cl))
          return sprintf("<font color=%s>%s</font>",$cl, $value);
        else
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
    } 


    /*****************************************************
    * 字体大小 [size=n]xxx[/size] 1<= n <= 7;
    * 等效与html的<font size=n>xxx</font>
    *****************************************************/
    function size($start, $para, $end, $value){
        $size= substr($para, 1);
        if ($size >=1 && $size <=7 && (strlen($para) > 1))
          return sprintf("<font size=%s>%s</font>",$size, $value);
        else
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
    } 


    /*****************************************************
    * 字体名字 [face=n] n字体名称,不需要引号
    * 等效与html的<font face=n>xxx</font>
    *****************************************************/
    function face($start, $para, $end, $value){
        $fn= substr($para, 1);
        if (!eregi("[[:punct:]]", $fn) && strlen($para) > 1) {
          switch (strtoupper($fn))
          {
            case "ST":
              $fn= "宋体";
              break;
            case "HT":
              $fn= "黑体";
              break;
            case "KT":
              $fn= "楷体_GB2312";
              break;
            case "FT":
              $fn= "仿宋_GB2312";
              break;
            case "YY":
              $fn= "幼圆";
              break;
            case "LS":
              $fn= "隶书";
              break;
          }
          return sprintf("<font face=\"%s\">%s</font>",$fn, $value);
        }
        else
          return sprintf("[%s%s]%s[%s]", $start, $para, $value, $end);
    } 
   
    /*****************************************************
    * 返回UBB解释器的版本和最后修改日期
    *****************************************************/
    function  GetUBBVer(&$sVer, &$sLastMod)
    {
      $sVer= sVersion;
      $sLastMod= $this->$sLastModified;
      return $sVer;
  }


/**************************** UPDATE LOG *********************************
2001.12.31 实现基本完整的UBB标签支持功能
           增加对若干标签的支持,比如face, size, color等
2001.01.04 增加了对图片URL的扩展名称检查,支持gif,bmp,pcx,tiff,png,jpg,jpeg,tga,lwf文件
           增加了自动补全URL协议部分的函数,支持http,fpt,gopher,finger,bbs,telnet等等
           允许\\和//的等效,
2002.01.07 修改了[face=]的显示错误,增加中文字体缩写
2002.01.08 完善了[glow]标签函数,增加了默认值,允许函数有缺省
           增加了[shadow]标签,使用方法和[glow]类似,并允许叠加效果
2002.01.09 增加了[wave][blur]标签函数,
           使用方法和[glow]类似,并允许叠加效果
2002.01.15 修改了正则表达式的匹配字符串,因为[URL=xxxx] 可能出现=_"'等这些字符,
           但是使用[url]xxxxx[/url]就不会有问题,原来没考虑到;
           FormatURL增加了对mms协议的支持,现在media player的格式很多;
           增加版本函数,可以返回UBB解释器的版本和最后修改日期
**************************************************************************/
?>

 
<?php 
    //测试 
    include ("./ubbcode.php");
    printf("<html>\n"); 
    echo "<head><title>UBB代码测试</title></head>\n"; 
    echo "<body style =\"FONT-SIZE: 9pt; FONT-FAMILY: 宋体\">\n"; 
    echo "<marquee scrolldelay=20>UBB表达式测试页</marquee>\n";
    $ubbcode = new ubbcode(); 
    $ubbcode->GetUBBVer($sVer, $sLastMod);
    printf("<br>\n    版本:%s<br>\n最后修订日期:%s<br>", $sVer, $sLastMod);
    echo "<form action=".($PATH_INFO)." method=post>\n"; 
    echo "<textarea  name=ubb style=\"width:95%; height:140px\">".stripslashes($ubb)."</textarea><br>\n"; 
    echo "<input type=submit value=转换>\n"; 
    echo "</form>\n";
 
    if(isset($ubb)){ 
       echo "<hr>\n".$ubbcode->parse(stripslashes(nl2br($ubb))); 
    } 
 
    echo "</body>\n"; 
    echo "</html>\n"; 
?>

大家可在这里测试效果
http://our93611.51.net/ubb/ubb.php

这里时说明
http://our93611.51.net/ubb/ubbintro.htm

按照写个规则,大家很容易写出来支持flash,mid,wma等等的新的ubb函数。
 
 
 

本文地址:http://com.8s8s.com/it/it27027.htm