Campustream 1.0
A social network MQP for WPI
application/lib/bbparser.php
Go to the documentation of this file.
00001 <?
00002 
00008 class bbparser{
00009         private $isOsimo;
00010         private $simple_bbcodes;
00011         private $fancy_bbcodes;
00012         private $allowedCSS;
00013         
00014         public static function bb2html($bb) {
00015                 $parser = new bbparser();
00016                 return $parser->parse($bb);
00017         }
00018         
00019         public function bbparser(){
00020                 $this->isOsimo = false;
00021                 
00022                 $this->loadDefaults();
00023         }
00024         
00025         private function loadDefaults(){
00026                 $simple_defaults = array(
00027                         "b"=>array(
00028                                 "search"=>"/\[b\](.+?)\[\/b\]/is",
00029                                 "replace"=>'<strong>$1</strong>'
00030                         ),
00031                         "i"=>array(
00032                                 "search"=>"/\[i\](.+?)\[\/i\]/is",
00033                                 "replace"=>'<i>$1</i>'
00034                         ),
00035                         "u"=>array(
00036                                 "search"=>"/\[u\](.+?)\[\/u\]/is",
00037                                 "replace"=>'<u>$1</u>'
00038                         ),
00039                         "s"=>array(
00040                                 'search'=>"/\[s\](.+?)\[\/s\]/is",
00041                                 'replace'=>'<span style="text-decoration:line-through">$1</span>'
00042                         ),
00043                         "url"=>array(
00044                                 "search"=>"/\[url\](.+?)\[\/url\]/is",
00045                                 "replace"=>'<a target="_blank" href="$1">$1</a>'
00046                         ),
00047                         "img"=>array(
00048                                 "search"=>"/\[img\](.+?)\[\/img\]/is",
00049                                 "replace"=>'<img src="$1" />'
00050                         ),
00051                         "quote"=>array(
00052                                 "search"=>"/\[quote\](.+?)\[\/quote\]/is",
00053                                 "replace"=>'<blockquote><span class="blockquote-title">Quote:</span><br/>$1</blockquote>'
00054                         ),
00055                         'code'=>array(
00056                                 'search'=>"/\[code\](.+?)\[\/code\]/is",
00057                                 'replace'=>'<pre class="code"><code class="plain">$1</code></pre>'
00058                         ),
00059                         'right'=>array(
00060                                 'search'=>"/\[right\](.+?)\[\/right\]/is",
00061                                 'replace'=>'<div style="text-align:right">$1</div>'
00062                         ),
00063                         'center'=>array(
00064                                 'search'=>"/\[center\](.+?)\[\/center\]/is",
00065                                 'replace'=>'<div style="text-align:center">$1</div>'
00066                         ),
00067                         'left'=>array(
00068                                 'search'=>"/\[left\](.+?)\[\/left\]/is",
00069                                 'replace'=>'<div style="text-align:left">$1</div>'
00070                         ),
00071                         'list'=>array(
00072                                 'search'=>"/\[list\](.+?)\[\/list\]/is",
00073                                 'replace'=>'<ul>$1</ul>'
00074                         ),
00075                         '[*]'=>array(
00076                                 'search'=>"/\[\*\]([^\n|\r]+)/is",
00077                                 'replace'=>'<li>$1</li>'
00078                         ),
00079                         'table'=>array(
00080                                 'search'=>"/\[table\](.+?)\[\/table\]/is",
00081                                 'replace'=>'<table>$1</table>'
00082                         ),
00083                         'row'=>array(
00084                                 'search'=>"/\[row\](.+?)\[\/row\]/is",
00085                                 'replace'=>'<tr>$1</tr>'
00086                         ),
00087                         'cell'=>array(
00088                                 'search'=>"/\[cell\](.+?)\[\/cell\]/is",
00089                                 'replace'=>'<td>$1</td>'
00090                         ),
00091                         'spoiler'=>array(
00092                                 'search'=>"/\[spoiler\](.+?)\[\/spoiler\]/is",
00093                                 'replace'=>'<div class="spoiler"><div class="spoiler_header" onclick="$(this).next().slideToggle(\'slow\')">Click to show/hide spoiler.</div><div class="spoiler_content" style="display:none">$1</div></div>'
00094                         ),
00095                         'hide'=>array(
00096                                 'search'=>"/\[hide\](.+?)\[\/hide\]/is",
00097                                 'replace'=>'<span class="inline_spoiler_notify" onclick="if($(this).next().is(\':visible\')){ $(this).next().fadeOut(\'fast\'); } else { $(this).next().fadeIn(\'fast\'); }">Spoiler!</span><span class="inline_spoiler">$1</span>'
00098                         )
00099                 );
00100                 
00101                 $fancy_defaults = array(
00102                         'email'=>array(
00103                                 'search'=>"/\[email=([^\]]+)\](.+?)\[\/email\]/is",
00104                                 'replace'=>'<a href="$1">$2</a>'
00105                         ),
00106                         "url"=>array(
00107                                 "search"=>"/\[url=([^\]]+)\](.+?)\[\/url\]/is",
00108                                 "replace"=>'<a target="_blank" href="$1">$2</a>'
00109                         ),
00110                         'size'=>array(
00111                                 'search'=>"/\[size=\s?([0-9]+)(?:px)?\](.+?)\[\/size\]/is",
00112                                 'replace'=>'<span style="font-size:$1px">$2</span>'
00113                         ),
00114                         'font'=>array(
00115                                 'search'=>"/\[font=([^\]]+)\](.+?)\[\/font\]/is",
00116                                 'replace'=>'<span style="font-family:$1">$2</span>'
00117                         ),
00118                         'color'=>array(
00119                                 'search'=>"/\[color=([^\]]+)\](.+?)\[\/color\]/is",
00120                                 'replace'=>'<span style="color:$1">$2</span>'
00121                         ),
00122                         'quote'=>array(
00123                                 'search'=>"/\[quote=([^\]]+)\](.+?)\[\/quote\]/is",
00124                                 'replace'=>'<blockquote><span class="blockquote-title">Quote by $1:</span><br/>$2</blockquote>'
00125                         ),
00126                         'align'=>array(
00127                                 'search'=>"/\[align=(left|right|center)\](.+?)\[\/align\]/is",
00128                                 'replace'=>'<div style="text-align: $1">$2</div>'
00129                         ),
00130                         'spoiler'=>array(
00131                                 'search'=>"/\[spoiler=([^\]]+)\](.+?)\[\/spoiler\]/is",
00132                                 'replace'=>'<div class="spoiler"><div class="spoiler_header" onclick="$(this).next().slideToggle(\'slow\')">$1</div><div class="spoiler_content" style="display:none">$2</div></div>'
00133                         ),
00134                         'hide'=>array(
00135                                 'search'=>"/\[hide=([^\]]+)\](.+?)\[\/hide\]/is",
00136                                 'replace'=>'<span class="inline_spoiler_notify" onclick="if($(this).next().is(\':visible\')){ $(this).next().fadeOut(\'fast\'); } else { $(this).next().fadeIn(\'fast\'); }">$1</span><span class="inline_spoiler">$2</span>'
00137                         )
00138                 );
00139                 
00140                 $this->addSimple($simple_defaults);
00141                 $this->addFancy($fancy_defaults);
00142                 
00143                 /* Allowed CSS attributes for tables - prevents things like
00144                  * using position: absolute to cover the page contents. */
00145                 $this->allowedCSS = array(
00146                         'width',
00147                         'height',
00148                         'background-color',
00149                         'color',
00150                         'border',
00151                         'border-color',
00152                         'border-style',
00153                         'border-width',
00154                         'border-collapse',
00155                         'padding',
00156                         'vertical-align',
00157                         /* these next 2 aren't CSS but are useful for tables */
00158                         'cellpadding',
00159                         'cellspacing',
00160                         'align' // not a real CSS property - will allow for easy alignment
00161                 );
00162         }
00163         
00164         public function addSimple($tag){
00165                 if(is_array($tag)){
00166                         foreach($tag as $name=>$code){
00167                                 $this->simple_bbcodes[$name] = $code;
00168                         }
00169                 }
00170                 else{ //make an assumption...
00171                         $this->simple_bbcodes[$tag] = array(
00172                                 "tag"=>$tag,
00173                                 "search"=>"/\[$tag\](.+)\[\/$tag\]/i",
00174                                 "replace"=>'<'.$tag.'>$1</'.$tag.'>'
00175                         );
00176                 }
00177         }
00178         
00179         public function addFancy($tag){
00180                 if(is_array($tag)){
00181                         foreach($tag as $name=>$code){
00182                                 $this->fancy_bbcodes[$name] = $code;
00183                         }
00184                 }
00185                 else{
00186                         return false;
00187                 }
00188         }
00189         
00190         public function parse($content,&$count=false){
00191                 $search = array();
00192                 $replace = array();
00193                 
00194                 foreach($this->simple_bbcodes as $code){
00195                         $search[] = $code['search'];
00196                         $replace[] = $code['replace'];
00197                 }
00198                 
00199                 foreach($this->fancy_bbcodes as $code){
00200                         $search[] = $code['search'];
00201                         $replace[] = $code['replace'];
00202                 }
00203                 
00204                 if(get_magic_quotes_gpc()){
00205                         $content = stripslashes($content);
00206                 }
00207                 
00208                 $content = str_replace(array('<','>'),array('&lt;','&gt;'),$content);
00209                 
00210                 /* nocode tag check - must do this first! */
00211                 $content =  preg_replace_callback(
00212                         '/\[nocode\](.+?)\[\/nocode\]/is',
00213                         create_function(
00214                                 '$matches',
00215                                 'return str_replace(array("[","]"),array("&#91;","&#93;"),$matches[1]);'
00216                         ),
00217                         $content
00218                 );
00219                 
00220                 /* unfortunately we have to do fancy tables separately */
00221                 $content = preg_replace_callback(
00222                         "/\[(table)=([^\]]+)\](.+?)\[\/table\]/is",
00223                         array($this,'parseTable'),
00224                         $content
00225                 );
00226                 $content = preg_replace_callback(
00227                         "/\[(row)=([^\]]+)\](.+?)\[\/row\]/is",
00228                         array($this,'parseTable'),
00229                         $content
00230                 );
00231                 $content = preg_replace_callback(
00232                         "/\[(cell)=([^\]]+)\](.+?)\[\/cell\]/is",
00233                         array($this,'parseTable'),
00234                         $content
00235                 );
00236                 
00237                 foreach($search as $pattern){
00238                         while(preg_match($pattern,$content)){
00239                                 $content = preg_replace($search,$replace,$content,-1,$count);
00240                         }
00241                 }
00242                 
00243                 /* Handle smilies, will probably change later */
00244                 if($this->isOsimo){
00245                         $content = $this->processSmilies($content);
00246                 }
00247                 
00248                 return nl2br($content);
00249         }
00250         
00251         private function parseTable($matches){
00252                 $return_css = '';
00253                 $return_attr = '';
00254                 $css = explode(';',$matches[2]);
00255                 if(count($css)>0){
00256                         foreach($css as $prop){
00257                                 $data = explode(':',$prop);
00258                                 $css_name = strtolower($data[0]);
00259                                 if(in_array($css_name,$this->allowedCSS)){
00260                                         if($matches[1]=='table'){
00261                                                 if($css_name == 'cellpadding'||$css_name == 'cellspacing'){
00262                                                         $return_attr .= $css_name.'="'.$data[1].'" ';
00263                                                         continue;
00264                                                 }
00265                                                 
00266                                                 if($css_name == 'align'){
00267                                                         if($data[1] == 'left'){
00268                                                                 $return_css .= 'margin-right: auto;';
00269                                                         }
00270                                                         elseif($data[1] == 'center'){
00271                                                                 $return_css .= 'margin-right: auto;margin-left: auto;';
00272                                                         }
00273                                                         elseif($data[1] == 'right'){
00274                                                                 $return_css  .= 'margin-left: auto;';
00275                                                         }
00276                                                         continue;
00277                                                 }
00278                                         }
00279                                         
00280                                         $return_css .= $prop;
00281                                         if(substr($prop,strlen($prop)-1) != ';'){
00282                                                 $return_css .= ';';
00283                                         }
00284                                 }
00285                         }
00286                 }
00287                 if($matches[1]=='row'){ $ele_name = 'tr'; }
00288                 elseif($matches[1]=='cell'){ $ele_name = 'td'; }
00289                 else{ $ele_name = 'table'; }
00290                 return "<$ele_name $return_attr style=\"$return_css\">{$matches[3]}</$ele_name>";
00291         }
00292         
00293         /*
00294          * This was copied directly from the old BBCode parser...
00295          * this will probably be completely changed in the future
00296          */
00297         private function processSmilies($post)
00298         {
00299                 if(!isset($_SESSION['osimo']['options']['smileySet']))
00300                 {
00301                         $query = "SELECT value FROM config WHERE name='current-smilies' LIMIT 1";
00302                         $result = mysql_query($query);
00303                         if($result)
00304                         {
00305                                 $_SESSION['osimo']['options']['smileySet'] = reset(mysql_fetch_row($result));
00306                         }
00307                 }
00308                 
00309                 /* If smiley BBCode isn't cached, then do so */
00310                 if(!is_array($_SESSION['osimo']['smilies']))
00311                 {
00312                         $query = "SELECT code,image FROM smilies WHERE smileySet='".$_SESSION['osimo']['options']['smileySet']."'";
00313                         $result = mysql_query($query);
00314                         
00315                         if($result)
00316                         {
00317                                 $i=0;
00318                                 while(list($code,$image)=mysql_fetch_row($result))
00319                                 {
00320                                         $_SESSION['osimo']['smilies']['name'][$i] = $image;
00321                                         $_SESSION['osimo']['smilies']['code'][$i] = $code;
00322                                         $i++;
00323                                 }
00324                         }
00325                 }
00326                 
00327                 if(is_array($_SESSION['osimo']['smilies']))
00328                 {
00329                         $j=0;
00330                         foreach($_SESSION['osimo']['smilies']['name'] as $smiley)
00331                         {
00332                                 $replace[$j] = "<img src=\"".OSIMOPATH."os-content/smilies/".$_SESSION['osimo']['options']['smileySet']."/$smiley\" />";
00333                                 $j++;
00334                         }
00335                         
00336                         $post = str_replace($_SESSION['osimo']['smilies']['code'],$replace,$post);
00337                 }
00338                 
00339                 return $post;
00340         }
00341 }
00342 ?>