2011-03-28 14:21:28 +00:00
< ?
2013-12-12 08:01:01 +00:00
class Text {
/**
* Array of valid tags ; tag => max number of attributes
* @ var array $ValidTags
*/
2014-04-15 08:00:45 +00:00
private static $ValidTags = array ( 'b' => 0 , 'u' => 0 , 'i' => 0 , 's' => 0 , '*' => 0 , '#' => 0 , 'artist' => 0 , 'user' => 0 , 'n' => 0 , 'inlineurl' => 0 , 'inlinesize' => 1 , 'headline' => 1 , 'align' => 1 , 'color' => 1 , 'colour' => 1 , 'size' => 1 , 'url' => 1 , 'img' => 1 , 'quote' => 1 , 'pre' => 1 , 'code' => 1 , 'tex' => 0 , 'hide' => 1 , 'spoiler' => 1 , 'plain' => 0 , 'important' => 0 , 'torrent' => 0 , 'rule' => 0 , 'mature' => 1 ,
2012-08-28 08:00:14 +00:00
);
2012-08-25 08:00:15 +00:00
2013-12-12 08:01:01 +00:00
/**
* Array of smilies ; code => image file in STATIC_SERVER / common / smileys
* @ var array $Smileys
*/
private static $Smileys = array (
2011-03-28 14:21:28 +00:00
':angry:' => 'angry.gif' ,
':-D' => 'biggrin.gif' ,
':D' => 'biggrin.gif' ,
':|' => 'blank.gif' ,
':-|' => 'blank.gif' ,
':blush:' => 'blush.gif' ,
':cool:' => 'cool.gif' ,
2012-10-27 08:00:09 +00:00
':'(' => 'crying.gif' ,
':crying:' => 'crying.gif' ,
2011-03-28 14:21:28 +00:00
'>.>' => 'eyesright.gif' ,
':frown:' => 'frown.gif' ,
'<3' => 'heart.gif' ,
':unsure:' => 'hmm.gif' ,
2013-01-15 08:00:37 +00:00
//':\\' => 'hmm.gif',
2011-03-28 14:21:28 +00:00
':whatlove:' => 'ilu.gif' ,
':lol:' => 'laughing.gif' ,
2013-01-15 08:00:37 +00:00
':loveflac:' => 'loveflac.gif' ,
2012-06-25 08:00:10 +00:00
':flaclove:' => 'loveflac.gif' ,
2011-03-28 14:21:28 +00:00
':ninja:' => 'ninja.gif' ,
':no:' => 'no.gif' ,
':nod:' => 'nod.gif' ,
':ohno:' => 'ohnoes.gif' ,
':ohnoes:' => 'ohnoes.gif' ,
':omg:' => 'omg.gif' ,
':o' => 'ohshit.gif' ,
':O' => 'ohshit.gif' ,
':paddle:' => 'paddle.gif' ,
':(' => 'sad.gif' ,
':-(' => 'sad.gif' ,
':shifty:' => 'shifty.gif' ,
':sick:' => 'sick.gif' ,
':)' => 'smile.gif' ,
':-)' => 'smile.gif' ,
':sorry:' => 'sorry.gif' ,
':thanks:' => 'thanks.gif' ,
':P' => 'tongue.gif' ,
2012-08-25 08:00:15 +00:00
':p' => 'tongue.gif' ,
2011-03-28 14:21:28 +00:00
':-P' => 'tongue.gif' ,
':-p' => 'tongue.gif' ,
':wave:' => 'wave.gif' ,
2011-07-10 08:00:06 +00:00
';-)' => 'wink.gif' ,
2011-03-28 14:21:28 +00:00
':wink:' => 'wink.gif' ,
':creepy:' => 'creepy.gif' ,
':worried:' => 'worried.gif' ,
':wtf:' => 'wtf.gif' ,
2011-07-06 08:00:07 +00:00
':wub:' => 'wub.gif' ,
2011-03-28 14:21:28 +00:00
);
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
/**
* Processed version of the $Smileys array , see { @ link smileys }
* @ var array $ProcessedSmileys
*/
private static $ProcessedSmileys = array ();
/**
* Whether or not to turn images into URLs ( used inside [ quote ] tags ) .
* This is an integer reflecting the number of levels we ' re doing that
* transition , i . e . images will only be displayed as images if $NoImg <= 0.
* By setting this variable to a negative number you can delay the
* transition to a deeper level of quotes .
* @ var int $NoImg
*/
private static $NoImg = 0 ;
2013-02-10 08:00:29 +00:00
2013-12-12 08:01:01 +00:00
/**
* Internal counter for the level of recursion in to_html
* @ var int $Levels
*/
private static $Levels = 0 ;
2013-04-23 08:01:29 +00:00
2013-04-22 08:00:58 +00:00
/**
* The maximum amount of nesting allowed ( exclusive )
* In reality n - 1 nests are shown .
* @ var int $MaximumNests
*/
2013-12-12 08:01:01 +00:00
private static $MaximumNests = 10 ;
2012-10-27 08:00:09 +00:00
/**
2013-01-15 08:00:37 +00:00
* Used to detect and disable parsing ( e . g . TOC ) within quotes
2012-10-27 08:00:09 +00:00
* @ var int $InQuotes
*/
2013-12-12 08:01:01 +00:00
private static $InQuotes = 0 ;
2013-04-23 08:01:29 +00:00
2013-04-22 08:00:58 +00:00
/**
* Used to [ hide ] quote trains starting with the specified depth ( inclusive )
* @ var int $NestsBeforeHide
*
2013-04-23 08:01:29 +00:00
* This defaulted to 5 but was raised to 10 to effectively " disable " it until
2013-04-22 08:00:58 +00:00
* an optimal number of nested [ quote ] tags is chosen . The variable $MaximumNests
* effectively overrides this variable , if $MaximumNests is less than the value
* of $NestsBeforeHide .
*/
2013-12-12 08:01:01 +00:00
private static $NestsBeforeHide = 10 ;
2012-10-27 08:00:09 +00:00
/**
* Array of headlines for Table Of Contents ( TOC )
* @ var array $HeadLines
*/
2013-12-12 08:01:01 +00:00
private static $Headlines ;
2012-10-27 08:00:09 +00:00
/**
* Counter for making headline URLs unique
* @ var int $HeadLines
*/
2013-12-12 08:01:01 +00:00
private static $HeadlineID = 0 ;
2012-10-27 08:00:09 +00:00
/**
* Depth
* @ var array $HeadlineLevels
*/
2013-12-12 08:01:01 +00:00
private static $HeadlineLevels = array ( '1' , '2' , '3' , '4' );
2012-10-27 08:00:09 +00:00
/**
* TOC enabler
* @ var bool $TOC
*/
2013-12-12 08:01:01 +00:00
public static $TOC = false ;
2012-10-27 08:00:09 +00:00
2013-02-10 08:00:29 +00:00
/**
2013-01-15 08:00:37 +00:00
* Output BBCode as XHTML
2012-10-27 08:00:09 +00:00
* @ param string $Str BBCode text
* @ param bool $OutputTOC Ouput TOC near ( above ) text
* @ param int $Min See { @ link parse_toc }
* @ return string
*/
2013-12-12 08:01:01 +00:00
public static function full_format ( $Str , $OutputTOC = true , $Min = 3 ) {
2011-03-28 14:21:28 +00:00
$Str = display_str ( $Str );
2013-12-12 08:01:01 +00:00
self :: $Headlines = array ();
2011-03-28 14:21:28 +00:00
//Inline links
2011-07-10 08:00:06 +00:00
$URLPrefix = '(\[url\]|\[url\=|\[img\=|\[img\])' ;
$Str = preg_replace ( '/' . $URLPrefix . '\s+/i' , '$1' , $Str );
$Str = preg_replace ( '/(?<!' . $URLPrefix . ')http(s)?:\/\//i' , '$1[inlineurl]http$2://' , $Str );
// For anonym.to and archive.org links, remove any [inlineurl] in the middle of the link
2013-06-18 08:00:48 +00:00
$callback = create_function ( '$matches' , 'return str_replace("[inlineurl]", "", $matches[0]);' );
2011-07-10 08:00:06 +00:00
$Str = preg_replace_callback ( '/(?<=\[inlineurl\]|' . $URLPrefix . ')(\S*\[inlineurl\]\S*)/m' , $callback , $Str );
2013-12-12 08:01:01 +00:00
if ( self :: $TOC ) {
2012-10-27 08:00:09 +00:00
$Str = preg_replace ( '/(\={5})([^=].*)\1/i' , '[headline=4]$2[/headline]' , $Str );
$Str = preg_replace ( '/(\={4})([^=].*)\1/i' , '[headline=3]$2[/headline]' , $Str );
$Str = preg_replace ( '/(\={3})([^=].*)\1/i' , '[headline=2]$2[/headline]' , $Str );
$Str = preg_replace ( '/(\={2})([^=].*)\1/i' , '[headline=1]$2[/headline]' , $Str );
} else {
$Str = preg_replace ( '/(\={4})([^=].*)\1/i' , '[inlinesize=3]$2[/inlinesize]' , $Str );
$Str = preg_replace ( '/(\={3})([^=].*)\1/i' , '[inlinesize=5]$2[/inlinesize]' , $Str );
$Str = preg_replace ( '/(\={2})([^=].*)\1/i' , '[inlinesize=7]$2[/inlinesize]' , $Str );
}
2013-12-12 08:01:01 +00:00
$HTML = nl2br ( self :: to_html ( self :: parse ( $Str )));
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
if ( self :: $TOC && $OutputTOC ) {
$HTML = self :: parse_toc ( $Min ) . $HTML ;
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
return $HTML ;
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
public static function strip_bbcode ( $Str ) {
2011-03-28 14:21:28 +00:00
$Str = display_str ( $Str );
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
//Inline links
$Str = preg_replace ( '/(?<!(\[url\]|\[url\=|\[img\=|\[img\]))http(s)?:\/\//i' , '$1[inlineurl]http$2://' , $Str );
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
return nl2br ( self :: raw_text ( self :: parse ( $Str )));
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
private static function valid_url ( $Str , $Extension = '' , $Inline = false ) {
2011-03-28 14:21:28 +00:00
$Regex = '/^' ;
$Regex .= '(https?|ftps?|irc):\/\/' ; // protocol
$Regex .= '(\w+(:\w+)?@)?' ; // user:pass@
$Regex .= '(' ;
$Regex .= '(([0-9]{1,3}\.){3}[0-9]{1,3})|' ; // IP or...
$Regex .= '(([a-z0-9\-\_]+\.)+\w{2,6})' ; // sub.sub.sub.host.com
$Regex .= ')' ;
$Regex .= '(:[0-9]{1,5})?' ; // port
$Regex .= '\/?' ; // slash?
2011-07-10 08:00:06 +00:00
$Regex .= '(\/?[0-9a-z\-_.,&=@~%\/:;()+|!#]+)*' ; // /file
2013-04-05 08:00:43 +00:00
if ( ! empty ( $Extension )) {
2011-03-28 14:21:28 +00:00
$Regex .= $Extension ;
}
// query string
if ( $Inline ) {
2012-03-20 08:00:21 +00:00
$Regex .= '(\?([0-9a-z\-_.,%\/\@~&=:;()+*\^$!#|?]|\[\d*\])*)?' ;
2011-03-28 14:21:28 +00:00
} else {
2012-03-20 08:00:21 +00:00
$Regex .= '(\?[0-9a-z\-_.,%\/\@[\]~&=:;()+*\^$!#|?]*)?' ;
2011-03-28 14:21:28 +00:00
}
$Regex .= '(#[a-z0-9\-_.,%\/\@[\]~&=:;()+*\^$!]*)?' ; // #anchor
$Regex .= '$/i' ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
return preg_match ( $Regex , $Str , $Matches );
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
public static function local_url ( $Str ) {
2011-03-28 14:21:28 +00:00
$URLInfo = parse_url ( $Str );
2013-04-20 08:01:01 +00:00
if ( ! $URLInfo ) {
return false ;
}
2011-03-28 14:21:28 +00:00
$Host = $URLInfo [ 'host' ];
2011-04-13 15:36:33 +00:00
// If for some reason your site does not require subdomains or contains a directory in the SITE_URL, revert to the line below.
2013-04-05 08:00:43 +00:00
//if ($Host == NONSSL_SITE_URL || $Host == SSL_SITE_URL || $Host == 'www.'.NONSSL_SITE_URL) {
if ( empty ( $URLInfo [ 'port' ]) && preg_match ( '/(\S+\.)*' . NONSSL_SITE_URL . '/' , $Host )) {
2013-11-06 08:00:50 +00:00
$URL = '' ;
if ( ! empty ( $URLInfo [ 'path' ])) {
$URL .= ltrim ( $URLInfo [ 'path' ], '/' ); // Things break if the path starts with '//'
}
2013-04-05 08:00:43 +00:00
if ( ! empty ( $URLInfo [ 'query' ])) {
2013-11-06 08:00:50 +00:00
$URL .= " ? $URLInfo[query] " ;
2011-03-28 14:21:28 +00:00
}
2013-04-05 08:00:43 +00:00
if ( ! empty ( $URLInfo [ 'fragment' ])) {
2013-11-06 08:00:50 +00:00
$URL .= " # $URLInfo[fragment] " ;
2011-03-28 14:21:28 +00:00
}
2013-11-06 08:00:50 +00:00
return $URL ? " / $URL " : false ;
2011-03-28 14:21:28 +00:00
} else {
return false ;
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
/*
How parsing works
Parsing takes $Str , breaks it into blocks , and builds it into $Array .
Blocks start at the beginning of $Str , when the parser encounters a [, and after a tag has been closed .
This is all done in a loop .
EXPLANATION OF PARSER LOGIC
1 ) Find the next tag ( regex )
1 a ) If there aren ' t any tags left , write everything remaining to a block and return ( done parsing )
1 b ) If the next tag isn ' t where the pointer is , write everything up to there to a text block .
2 ) See if it ' s a [[ wiki - link ]] or an ordinary tag , and get the tag name
3 ) If it ' s not a wiki link :
2013-12-12 08:01:01 +00:00
3 a ) check it against the self :: $ValidTags array to see if it ' s actually a tag and not [ bullshit ]
2012-10-27 08:00:09 +00:00
If it ' s [ not a tag ], just leave it as plaintext and move on
3 b ) Get the attribute , if it exists [ name = attribute ]
4 ) Move the pointer past the end of the tag
5 ) Find out where the tag closes ( beginning of [ / tag ])
5 a ) Different for different types of tag . Some tags don ' t close , others are weird like [ * ]
2013-01-15 08:00:37 +00:00
5 b ) If it ' s a normal tag , it may have versions of itself nested inside - e . g .:
2012-10-27 08:00:09 +00:00
[ quote = bob ] *
[ quote = joe ] I am a redneck !** [ / quote ]
Me too !
*** [ / quote ]
If we ' re at the position * , the first [ / quote ] tag is denoted by **.
However , our quote tag doesn ' t actually close there . We must perform
a loop which checks the number of opening [ quote ] tags , and make sure
they are all closed before we find our final [ / quote ] tag ( *** ) .
5 c ) Get the contents between [ open ] and [ / close ] and call it the block .
In many cases , this will be parsed itself later on , in a new parse () call .
5 d ) Move the pointer past the end of the [ / close ] tag .
6 ) Depending on what type of tag we ' re dealing with , create an array with the attribute and block .
In many cases , the block may be parsed here itself . Stick them in the $Array .
7 ) Increment array pointer , start again ( past the end of the [ / close ] tag )
*/
2013-12-12 08:01:01 +00:00
private static function parse ( $Str ) {
2011-03-28 14:21:28 +00:00
$i = 0 ; // Pointer to keep track of where we are in $Str
$Len = strlen ( $Str );
$Array = array ();
$ArrayPos = 0 ;
2011-07-11 12:01:08 +00:00
2013-04-05 08:00:43 +00:00
while ( $i < $Len ) {
2011-03-28 14:21:28 +00:00
$Block = '' ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 1) Find the next tag (regex)
// [name(=attribute)?]|[[wiki-link]]
2011-08-09 21:03:28 +00:00
$IsTag = preg_match ( " /(( \ [[a-zA-Z*#]+)(=(?:[^ \n ' \" \ [ \ ]]| \ [ \ d* \ ])+)? \ ])|( \ [ \ [[^ \n \" ' \ [ \ ]]+ \ ] \ ])/ " , $Str , $Tag , PREG_OFFSET_CAPTURE , $i );
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 1a) If there aren't any tags left, write everything remaining to a block
2013-04-05 08:00:43 +00:00
if ( ! $IsTag ) {
2011-03-28 14:21:28 +00:00
// No more tags
$Array [ $ArrayPos ] = substr ( $Str , $i );
break ;
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 1b) If the next tag isn't where the pointer is, write everything up to there to a text block.
$TagPos = $Tag [ 0 ][ 1 ];
2013-04-05 08:00:43 +00:00
if ( $TagPos > $i ) {
$Array [ $ArrayPos ] = substr ( $Str , $i , $TagPos - $i );
2011-03-28 14:21:28 +00:00
++ $ArrayPos ;
2013-04-05 08:00:43 +00:00
$i = $TagPos ;
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 2) See if it's a [[wiki-link]] or an ordinary tag, and get the tag name
2013-04-05 08:00:43 +00:00
if ( ! empty ( $Tag [ 4 ][ 0 ])) { // Wiki-link
2011-03-28 14:21:28 +00:00
$WikiLink = true ;
$TagName = substr ( $Tag [ 4 ][ 0 ], 2 , - 2 );
$Attrib = '' ;
} else { // 3) If it's not a wiki link:
$WikiLink = false ;
$TagName = strtolower ( substr ( $Tag [ 2 ][ 0 ], 1 ));
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
//3a) check it against the self::$ValidTags array to see if it's actually a tag and not [bullshit]
if ( ! isset ( self :: $ValidTags [ $TagName ])) {
2013-04-20 08:01:01 +00:00
$Array [ $ArrayPos ] = substr ( $Str , $i , ( $TagPos - $i ) + strlen ( $Tag [ 0 ][ 0 ]));
2013-04-05 08:00:43 +00:00
$i = $TagPos + strlen ( $Tag [ 0 ][ 0 ]);
2011-03-28 14:21:28 +00:00
++ $ArrayPos ;
continue ;
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
$MaxAttribs = self :: $ValidTags [ $TagName ];
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 3b) Get the attribute, if it exists [name=attribute]
2013-04-05 08:00:43 +00:00
if ( ! empty ( $Tag [ 3 ][ 0 ])) {
2011-03-28 14:21:28 +00:00
$Attrib = substr ( $Tag [ 3 ][ 0 ], 1 );
} else {
2013-05-16 08:00:10 +00:00
$Attrib = '' ;
2011-03-28 14:21:28 +00:00
}
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 4) Move the pointer past the end of the tag
2013-04-20 08:01:01 +00:00
$i = $TagPos + strlen ( $Tag [ 0 ][ 0 ]);
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 5) Find out where the tag closes (beginning of [/tag])
2012-10-27 08:00:09 +00:00
2013-01-15 08:00:37 +00:00
// Unfortunately, BBCode doesn't have nice standards like XHTML
2011-03-28 14:21:28 +00:00
// [*], [img=...], and http:// follow different formats
// Thus, we have to handle these before we handle the majority of tags
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
//5a) Different for different types of tag. Some tags don't close, others are weird like [*]
2013-04-05 08:00:43 +00:00
if ( $TagName == 'img' && ! empty ( $Tag [ 3 ][ 0 ])) { //[img=...]
2011-03-28 14:21:28 +00:00
$Block = '' ; // Nothing inside this tag
// Don't need to touch $i
2013-04-05 08:00:43 +00:00
} elseif ( $TagName == 'inlineurl' ) { // We did a big replace early on to turn http:// into [inlineurl]http://
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// Let's say the block can stop at a newline or a space
$CloseTag = strcspn ( $Str , " \n \r " , $i );
2013-04-05 08:00:43 +00:00
if ( $CloseTag === false ) { // block finishes with URL
2011-03-28 14:21:28 +00:00
$CloseTag = $Len ;
}
2013-04-05 08:00:43 +00:00
if ( preg_match ( '/[!,.?:]+$/' , substr ( $Str , $i , $CloseTag ), $Match )) {
2011-03-28 14:21:28 +00:00
$CloseTag -= strlen ( $Match [ 0 ]);
}
$URL = substr ( $Str , $i , $CloseTag );
2013-04-05 08:00:43 +00:00
if ( substr ( $URL , - 1 ) == ')' && substr_count ( $URL , '(' ) < substr_count ( $URL , ')' )) {
2011-03-28 14:21:28 +00:00
$CloseTag -- ;
$URL = substr ( $URL , 0 , - 1 );
}
$Block = $URL ; // Get the URL
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// strcspn returns the number of characters after the offset $i, not after the beginning of the string
// Therefore, we use += instead of the = everywhere else
2012-10-27 08:00:09 +00:00
$i += $CloseTag ; // 5d) Move the pointer past the end of the [/close] tag.
2013-04-05 08:00:43 +00:00
} elseif ( $WikiLink == true || $TagName == 'n' ) {
2011-03-28 14:21:28 +00:00
// Don't need to do anything - empty tag with no closing
2013-04-05 08:00:43 +00:00
} elseif ( $TagName === '*' || $TagName === '#' ) {
2011-03-28 14:21:28 +00:00
// We're in a list. Find where it ends
$NewLine = $i ;
do { // Look for \n[*]
2013-04-20 08:01:01 +00:00
$NewLine = strpos ( $Str , " \n " , $NewLine + 1 );
2013-05-16 08:00:10 +00:00
} while ( $NewLine !== false && substr ( $Str , $NewLine + 1 , 3 ) == " [ $TagName ] " );
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
$CloseTag = $NewLine ;
2013-04-05 08:00:43 +00:00
if ( $CloseTag === false ) { // block finishes with list
2011-03-28 14:21:28 +00:00
$CloseTag = $Len ;
}
2013-04-20 08:01:01 +00:00
$Block = substr ( $Str , $i , $CloseTag - $i ); // Get the list
2012-10-27 08:00:09 +00:00
$i = $CloseTag ; // 5d) Move the pointer past the end of the [/close] tag.
2011-03-28 14:21:28 +00:00
} else {
//5b) If it's a normal tag, it may have versions of itself nested inside
2013-04-20 08:01:01 +00:00
$CloseTag = $i - 1 ;
$InTagPos = $i - 1 ;
2011-03-28 14:21:28 +00:00
$NumInOpens = 0 ;
$NumInCloses = - 1 ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
$InOpenRegex = '/\[(' . $TagName . ')' ;
2013-04-05 08:00:43 +00:00
if ( $MaxAttribs > 0 ) {
2013-06-24 08:00:28 +00:00
$InOpenRegex .= " (=[^ \n ' \" \ [ \ ]]+)? " ;
2011-03-28 14:21:28 +00:00
}
2013-06-24 08:00:28 +00:00
$InOpenRegex .= '\]/i' ;
2012-10-27 08:00:09 +00:00
// Every time we find an internal open tag of the same type, search for the next close tag
2011-03-28 14:21:28 +00:00
// (as the first close tag won't do - it's been opened again)
do {
2013-05-16 08:00:10 +00:00
$CloseTag = stripos ( $Str , " [/ $TagName ] " , $CloseTag + 1 );
2013-04-05 08:00:43 +00:00
if ( $CloseTag === false ) {
2011-03-28 14:21:28 +00:00
$CloseTag = $Len ;
break ;
} else {
$NumInCloses ++ ; // Majority of cases
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// Is there another open tag inside this one?
2013-04-20 08:01:01 +00:00
$OpenTag = preg_match ( $InOpenRegex , $Str , $InTag , PREG_OFFSET_CAPTURE , $InTagPos + 1 );
2013-04-05 08:00:43 +00:00
if ( ! $OpenTag || $InTag [ 0 ][ 1 ] > $CloseTag ) {
2011-03-28 14:21:28 +00:00
break ;
} else {
$InTagPos = $InTag [ 0 ][ 1 ];
$NumInOpens ++ ;
}
2012-10-27 08:00:09 +00:00
2013-04-05 08:00:43 +00:00
} while ( $NumInOpens > $NumInCloses );
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// Find the internal block inside the tag
2013-04-20 08:01:01 +00:00
$Block = substr ( $Str , $i , $CloseTag - $i ); // 5c) Get the contents between [open] and [/close] and call it the block.
2012-10-27 08:00:09 +00:00
2013-04-20 08:01:01 +00:00
$i = $CloseTag + strlen ( $TagName ) + 3 ; // 5d) Move the pointer past the end of the [/close] tag.
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
// 6) Depending on what type of tag we're dealing with, create an array with the attribute and block.
2013-05-01 08:00:16 +00:00
switch ( $TagName ) {
2011-03-28 14:21:28 +00:00
case 'inlineurl' :
$Array [ $ArrayPos ] = array ( 'Type' => 'inlineurl' , 'Attr' => $Block , 'Val' => '' );
break ;
case 'url' :
$Array [ $ArrayPos ] = array ( 'Type' => 'img' , 'Attr' => $Attrib , 'Val' => $Block );
2013-04-05 08:00:43 +00:00
if ( empty ( $Attrib )) { // [url]http://...[/url] - always set URL to attribute
2011-03-28 14:21:28 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => 'url' , 'Attr' => $Block , 'Val' => '' );
} else {
2013-12-12 08:01:01 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => 'url' , 'Attr' => $Attrib , 'Val' => self :: parse ( $Block ));
2011-03-28 14:21:28 +00:00
}
break ;
case 'quote' :
2013-12-12 08:01:01 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => 'quote' , 'Attr' => self :: parse ( $Attrib ), 'Val' => self :: parse ( $Block ));
2011-03-28 14:21:28 +00:00
break ;
case 'img' :
case 'image' :
2013-04-05 08:00:43 +00:00
if ( empty ( $Block )) {
2011-03-28 14:21:28 +00:00
$Block = $Attrib ;
}
$Array [ $ArrayPos ] = array ( 'Type' => 'img' , 'Val' => $Block );
break ;
case 'aud' :
case 'mp3' :
case 'audio' :
2013-04-05 08:00:43 +00:00
if ( empty ( $Block )) {
2011-03-28 14:21:28 +00:00
$Block = $Attrib ;
}
$Array [ $ArrayPos ] = array ( 'Type' => 'aud' , 'Val' => $Block );
break ;
case 'user' :
$Array [ $ArrayPos ] = array ( 'Type' => 'user' , 'Val' => $Block );
break ;
case 'artist' :
$Array [ $ArrayPos ] = array ( 'Type' => 'artist' , 'Val' => $Block );
break ;
2012-02-02 08:00:26 +00:00
case 'torrent' :
$Array [ $ArrayPos ] = array ( 'Type' => 'torrent' , 'Val' => $Block );
break ;
2011-03-28 14:21:28 +00:00
case 'tex' :
$Array [ $ArrayPos ] = array ( 'Type' => 'tex' , 'Val' => $Block );
break ;
2013-02-10 08:00:29 +00:00
case 'rule' :
$Array [ $ArrayPos ] = array ( 'Type' => 'rule' , 'Val' => $Block );
break ;
2011-03-28 14:21:28 +00:00
case 'pre' :
2011-07-10 08:00:06 +00:00
case 'code' :
2011-03-28 14:21:28 +00:00
case 'plain' :
2013-06-24 08:00:28 +00:00
$Block = strtr ( $Block , array ( '[inlineurl]' => '' ));
2012-10-27 08:00:09 +00:00
$Callback = function ( $matches ) {
$n = $matches [ 2 ];
$text = '' ;
if ( $n < 5 && $n > 0 ) {
2013-04-20 08:01:01 +00:00
$e = str_repeat ( '=' , $matches [ 2 ] + 1 );
2012-10-27 08:00:09 +00:00
$text = $e . $matches [ 3 ] . $e ;
}
return $text ;
};
$Block = preg_replace_callback ( '/\[(headline)\=(\d)\](.*?)\[\/\1\]/i' , $Callback , $Block );
2011-03-28 14:21:28 +00:00
$Block = preg_replace ( '/\[inlinesize\=3\](.*?)\[\/inlinesize\]/i' , '====$1====' , $Block );
$Block = preg_replace ( '/\[inlinesize\=5\](.*?)\[\/inlinesize\]/i' , '===$1===' , $Block );
$Block = preg_replace ( '/\[inlinesize\=7\](.*?)\[\/inlinesize\]/i' , '==$1==' , $Block );
2012-10-27 08:00:09 +00:00
2011-07-10 08:00:06 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => $TagName , 'Val' => $Block );
2011-03-28 14:21:28 +00:00
break ;
2014-04-15 08:00:45 +00:00
case 'spoiler' :
2011-03-28 14:21:28 +00:00
case 'hide' :
2013-12-12 08:01:01 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => 'hide' , 'Attr' => $Attrib , 'Val' => self :: parse ( $Block ));
2011-03-28 14:21:28 +00:00
break ;
2012-12-03 08:00:16 +00:00
case 'mature' :
2013-12-12 08:01:01 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => 'mature' , 'Attr' => $Attrib , 'Val' => self :: parse ( $Block ));
2012-12-03 08:00:16 +00:00
break ;
2011-08-09 21:03:28 +00:00
case '#' :
2011-03-28 14:21:28 +00:00
case '*' :
$Array [ $ArrayPos ] = array ( 'Type' => 'list' );
2013-11-02 08:01:09 +00:00
$Array [ $ArrayPos ][ 'Val' ] = explode ( " [ $TagName ] " , $Block );
$Array [ $ArrayPos ][ 'ListType' ] = $TagName === '*' ? 'ul' : 'ol' ;
2011-08-09 21:03:28 +00:00
$Array [ $ArrayPos ][ 'Tag' ] = $TagName ;
2013-04-05 08:00:43 +00:00
foreach ( $Array [ $ArrayPos ][ 'Val' ] as $Key => $Val ) {
2013-12-12 08:01:01 +00:00
$Array [ $ArrayPos ][ 'Val' ][ $Key ] = self :: parse ( trim ( $Val ));
2011-03-28 14:21:28 +00:00
}
break ;
case 'n' :
$ArrayPos -- ;
break ; // n serves only to disrupt bbcode (backwards compatibility - use [pre])
default :
2013-04-05 08:00:43 +00:00
if ( $WikiLink == true ) {
2011-03-28 14:21:28 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => 'wiki' , 'Val' => $TagName );
2012-10-27 08:00:09 +00:00
} else {
2011-03-28 14:21:28 +00:00
// Basic tags, like [b] or [size=5]
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
$Array [ $ArrayPos ] = array ( 'Type' => $TagName , 'Val' => self :: parse ( $Block ));
2013-05-16 08:00:10 +00:00
if ( ! empty ( $Attrib ) && $MaxAttribs > 0 ) {
2011-03-28 14:21:28 +00:00
$Array [ $ArrayPos ][ 'Attr' ] = strtolower ( $Attrib );
}
}
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
$ArrayPos ++ ; // 7) Increment array pointer, start again (past the end of the [/close] tag)
}
return $Array ;
}
2012-10-27 08:00:09 +00:00
/**
* Generates a navigation list for TOC
* @ param int $Min Minimum number of headlines required for a TOC list
*/
2013-12-12 08:01:01 +00:00
public static function parse_toc ( $Min = 3 ) {
if ( count ( self :: $Headlines ) > $Min ) {
2012-10-27 08:00:09 +00:00
$list = '<ol class="navigation_list">' ;
$i = 0 ;
$level = 0 ;
$off = 0 ;
2013-12-12 08:01:01 +00:00
foreach ( self :: $Headlines as $t ) {
2013-10-30 08:01:19 +00:00
$n = ( int ) $t [ 0 ];
2013-04-20 08:01:01 +00:00
if ( $i === 0 && $n > 1 ) {
$off = $n - $level ;
}
2013-12-12 08:01:01 +00:00
self :: headline_level ( $n , $level , $list , $i , $off );
2012-10-27 08:00:09 +00:00
$list .= sprintf ( '<li><a href="#%2$s">%1$s</a>' , $t [ 1 ], $t [ 2 ]);
$level = $t [ 0 ];
$off = 0 ;
$i ++ ;
}
$list .= str_repeat ( '</li></ol>' , $level );
$list .= " \n \n " ;
return $list ;
}
}
/**
* Generates the list items and proper depth
*
2013-02-10 08:00:29 +00:00
* First check if the item should be higher than the current level
2012-10-27 08:00:09 +00:00
* - Close the list and previous lists
*
2013-02-10 08:00:29 +00:00
* Then check if the item should go lower than the current level
2012-10-27 08:00:09 +00:00
* - If the list doesn ' t open on level one , use the Offset
* - Open appropriate sub lists
*
* Otherwise the item is on the same as level as the previous item
*
* @ param int $ItemLevel Current item level
* @ param int $Level Current list level
2013-03-09 08:00:18 +00:00
* @ param str $List reference to an XHTML string
2012-10-27 08:00:09 +00:00
* @ param int $i Iterator digit
* @ param int $Offset If the list doesn ' t start at level 1
*/
2013-12-12 08:01:01 +00:00
private static function headline_level ( & $ItemLevel , & $Level , & $List , $i , & $Offset ) {
2012-10-27 08:00:09 +00:00
if ( $ItemLevel < $Level ) {
$diff = $Level - $ItemLevel ;
$List .= '</li>' . str_repeat ( '</ol></li>' , $diff );
} elseif ( $ItemLevel > $Level ) {
$diff = $ItemLevel - $Level ;
2013-04-20 08:01:01 +00:00
if ( $Offset > 0 ) $List .= str_repeat ( '<li><ol>' , $Offset - 2 );
2012-10-27 08:00:09 +00:00
if ( $ItemLevel > 1 ) {
2013-11-02 08:01:09 +00:00
$List .= $i === 0 ? '<li>' : '' ;
$List .= " \n <ol> \n " ;
2012-10-27 08:00:09 +00:00
}
} else {
2013-11-02 08:01:09 +00:00
$List .= $i > 0 ? '</li>' : '<li>' ;
2012-10-27 08:00:09 +00:00
}
}
2013-12-12 08:01:01 +00:00
private static function to_html ( $Array ) {
2012-08-23 08:00:17 +00:00
global $SSL ;
2013-12-12 08:01:01 +00:00
self :: $Levels ++ ;
2013-04-22 08:00:58 +00:00
/*
* Hax prevention
* That ' s the original comment on this .
* Most likely this was implemented to avoid anyone nesting enough
* elements to reach PHP ' s memory limit as nested elements are
* solved recursively .
* Original value of 10 , it is now replaced in favor of
* $MaximumNests .
* If this line is ever executed then something is , infact
* being haxed as the if before the block type switch for different
* tags should always be limiting ahead of this line .
* ( Larger than vs . smaller than . )
*/
2013-12-12 08:01:01 +00:00
if ( self :: $Levels > self :: $MaximumNests ) {
2013-04-22 08:00:58 +00:00
return $Block [ 'Val' ]; // Hax prevention, breaks upon exceeding nests.
}
2011-03-28 14:21:28 +00:00
$Str = '' ;
2013-04-05 08:00:43 +00:00
foreach ( $Array as $Block ) {
if ( is_string ( $Block )) {
2013-12-12 08:01:01 +00:00
$Str .= self :: smileys ( $Block );
2011-03-28 14:21:28 +00:00
continue ;
}
2013-12-12 08:01:01 +00:00
if ( self :: $Levels < self :: $MaximumNests ) {
2013-04-22 08:00:58 +00:00
switch ( $Block [ 'Type' ]) {
2011-03-28 14:21:28 +00:00
case 'b' :
2013-12-12 08:01:01 +00:00
$Str .= '<strong>' . self :: to_html ( $Block [ 'Val' ]) . '</strong>' ;
2011-03-28 14:21:28 +00:00
break ;
case 'u' :
2013-12-12 08:01:01 +00:00
$Str .= '<span style="text-decoration: underline;">' . self :: to_html ( $Block [ 'Val' ]) . '</span>' ;
2011-03-28 14:21:28 +00:00
break ;
case 'i' :
2013-12-12 08:01:01 +00:00
$Str .= '<span style="font-style: italic;">' . self :: to_html ( $Block [ 'Val' ]) . " </span> " ;
2011-03-28 14:21:28 +00:00
break ;
case 's' :
2013-12-12 08:01:01 +00:00
$Str .= '<span style="text-decoration: line-through;">' . self :: to_html ( $Block [ 'Val' ]) . '</span>' ;
2011-03-28 14:21:28 +00:00
break ;
2011-08-09 21:03:28 +00:00
case 'important' :
2013-12-12 08:01:01 +00:00
$Str .= '<strong class="important_text">' . self :: to_html ( $Block [ 'Val' ]) . '</strong>' ;
2011-08-09 21:03:28 +00:00
break ;
2011-03-28 14:21:28 +00:00
case 'user' :
2013-06-21 08:00:44 +00:00
$Str .= '<a href="user.php?action=search&search=' . urlencode ( $Block [ 'Val' ]) . '">' . $Block [ 'Val' ] . '</a>' ;
2011-03-28 14:21:28 +00:00
break ;
case 'artist' :
2013-06-21 08:00:44 +00:00
$Str .= '<a href="artist.php?artistname=' . urlencode ( Format :: undisplay_str ( $Block [ 'Val' ])) . '">' . $Block [ 'Val' ] . '</a>' ;
2011-03-28 14:21:28 +00:00
break ;
2013-02-10 08:00:29 +00:00
case 'rule' :
$Rule = trim ( strtolower ( $Block [ 'Val' ]));
2013-04-05 08:00:43 +00:00
if ( $Rule [ 0 ] != 'r' && $Rule [ 0 ] != 'h' ) {
2013-02-10 08:00:29 +00:00
$Rule = 'r' . $Rule ;
}
2013-06-21 08:00:44 +00:00
$Str .= '<a href="rules.php?p=upload#' . urlencode ( Format :: undisplay_str ( $Rule )) . '">' . preg_replace ( '/[aA-zZ]/' , '' , $Block [ 'Val' ]) . '</a>' ;
2013-02-10 08:00:29 +00:00
break ;
2012-02-02 08:00:26 +00:00
case 'torrent' :
2012-02-04 08:00:25 +00:00
$Pattern = '/(' . NONSSL_SITE_URL . '\/torrents\.php.*[\?&]id=)?(\d+)($|&|\#).*/i' ;
2012-02-02 08:00:26 +00:00
$Matches = array ();
if ( preg_match ( $Pattern , $Block [ 'Val' ], $Matches )) {
if ( isset ( $Matches [ 2 ])) {
2013-09-13 08:00:53 +00:00
$GroupID = $Matches [ 2 ];
$Groups = Torrents :: get_groups ( array ( $GroupID ), true , true , false );
if ( $Groups [ $GroupID ]) {
$Group = $Groups [ $GroupID ];
$Str .= Artists :: display_artists ( $Group [ 'ExtendedArtists' ]) . '<a href="torrents.php?id=' . $GroupID . '">' . $Group [ 'Name' ] . '</a>' ;
2012-02-02 08:00:26 +00:00
} else {
2013-06-18 08:00:48 +00:00
$Str .= '[torrent]' . str_replace ( '[inlineurl]' , '' , $Block [ 'Val' ]) . '[/torrent]' ;
2012-02-02 08:00:26 +00:00
}
}
} else {
2013-06-18 08:00:48 +00:00
$Str .= '[torrent]' . str_replace ( '[inlineurl]' , '' , $Block [ 'Val' ]) . '[/torrent]' ;
2012-02-02 08:00:26 +00:00
}
break ;
2011-03-28 14:21:28 +00:00
case 'wiki' :
2013-06-21 08:00:44 +00:00
$Str .= '<a href="wiki.php?action=article&name=' . urlencode ( $Block [ 'Val' ]) . '">' . $Block [ 'Val' ] . '</a>' ;
2011-03-28 14:21:28 +00:00
break ;
case 'tex' :
2013-07-02 08:01:37 +00:00
$Str .= '<img style="vertical-align: middle;" src="' . STATIC_SERVER . 'blank.gif" onload="if (this.src.substr(this.src.length - 9, this.src.length) == \'blank.gif\') { this.src = \'https://chart.googleapis.com/chart?cht=tx&chf=bg,s,FFFFFF00&chl=' . urlencode ( mb_convert_encoding ( $Block [ 'Val' ], 'UTF-8' , 'HTML-ENTITIES' )) . '&chco=\' + hexify(getComputedStyle(this.parentNode, null).color); }" alt="' . $Block [ 'Val' ] . '" />' ;
2011-03-28 14:21:28 +00:00
break ;
case 'plain' :
2013-06-21 08:00:44 +00:00
$Str .= $Block [ 'Val' ];
2011-03-28 14:21:28 +00:00
break ;
case 'pre' :
2013-06-21 08:00:44 +00:00
$Str .= '<pre>' . $Block [ 'Val' ] . '</pre>' ;
2011-03-28 14:21:28 +00:00
break ;
2011-07-10 08:00:06 +00:00
case 'code' :
2013-06-21 08:00:44 +00:00
$Str .= '<code>' . $Block [ 'Val' ] . '</code>' ;
2011-07-10 08:00:06 +00:00
break ;
2011-03-28 14:21:28 +00:00
case 'list' :
2013-11-02 08:01:09 +00:00
$Str .= " < $Block[ListType] class= \" postlist \" > " ;
2013-04-05 08:00:43 +00:00
foreach ( $Block [ 'Val' ] as $Line ) {
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
$Str .= '<li>' . self :: to_html ( $Line ) . '</li>' ;
2011-03-28 14:21:28 +00:00
}
2013-06-21 08:00:44 +00:00
$Str .= '</' . $Block [ 'ListType' ] . '>' ;
2011-03-28 14:21:28 +00:00
break ;
case 'align' :
$ValidAttribs = array ( 'left' , 'center' , 'right' );
2013-04-05 08:00:43 +00:00
if ( ! in_array ( $Block [ 'Attr' ], $ValidAttribs )) {
2013-12-12 08:01:01 +00:00
$Str .= '[align=' . $Block [ 'Attr' ] . ']' . self :: to_html ( $Block [ 'Val' ]) . '[/align]' ;
2011-03-28 14:21:28 +00:00
} else {
2013-12-12 08:01:01 +00:00
$Str .= '<div style="text-align: ' . $Block [ 'Attr' ] . ';">' . self :: to_html ( $Block [ 'Val' ]) . '</div>' ;
2011-03-28 14:21:28 +00:00
}
break ;
case 'color' :
case 'colour' :
$ValidAttribs = array ( 'aqua' , 'black' , 'blue' , 'fuchsia' , 'green' , 'grey' , 'lime' , 'maroon' , 'navy' , 'olive' , 'purple' , 'red' , 'silver' , 'teal' , 'white' , 'yellow' );
2013-04-05 08:00:43 +00:00
if ( ! in_array ( $Block [ 'Attr' ], $ValidAttribs ) && ! preg_match ( '/^#[0-9a-f]{6}$/' , $Block [ 'Attr' ])) {
2013-12-12 08:01:01 +00:00
$Str .= '[color=' . $Block [ 'Attr' ] . ']' . self :: to_html ( $Block [ 'Val' ]) . '[/color]' ;
2011-03-28 14:21:28 +00:00
} else {
2013-12-12 08:01:01 +00:00
$Str .= '<span style="color: ' . $Block [ 'Attr' ] . ';">' . self :: to_html ( $Block [ 'Val' ]) . '</span>' ;
2011-03-28 14:21:28 +00:00
}
break ;
2012-10-27 08:00:09 +00:00
case 'headline' :
2013-12-12 08:01:01 +00:00
$text = self :: to_html ( $Block [ 'Val' ]);
$raw = self :: raw_text ( $Block [ 'Val' ]);
if ( ! in_array ( $Block [ 'Attr' ], self :: $HeadlineLevels )) {
2012-10-27 08:00:09 +00:00
$Str .= sprintf ( '%1$s%2$s%1$s' , str_repeat ( '=' , $Block [ 'Attr' ] + 1 ), $text );
} else {
2013-12-12 08:01:01 +00:00
$id = '_' . crc32 ( $raw . self :: $HeadlineID );
if ( self :: $InQuotes === 0 ) {
self :: $Headlines [] = array ( $Block [ 'Attr' ], $raw , $id );
2013-04-20 08:01:01 +00:00
}
2012-10-27 08:00:09 +00:00
2013-04-20 08:01:01 +00:00
$Str .= sprintf ( '<h%1$d id="%3$s">%2$s</h%1$d>' , ( $Block [ 'Attr' ] + 2 ), $text , $id );
2013-12-12 08:01:01 +00:00
self :: $HeadlineID ++ ;
2012-10-27 08:00:09 +00:00
}
break ;
2011-03-28 14:21:28 +00:00
case 'inlinesize' :
case 'size' :
2013-11-02 08:01:09 +00:00
$ValidAttribs = array ( '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , '10' );
2013-04-05 08:00:43 +00:00
if ( ! in_array ( $Block [ 'Attr' ], $ValidAttribs )) {
2013-12-12 08:01:01 +00:00
$Str .= '[size=' . $Block [ 'Attr' ] . ']' . self :: to_html ( $Block [ 'Val' ]) . '[/size]' ;
2011-03-28 14:21:28 +00:00
} else {
2013-12-12 08:01:01 +00:00
$Str .= '<span class="size' . $Block [ 'Attr' ] . '">' . self :: to_html ( $Block [ 'Val' ]) . '</span>' ;
2011-03-28 14:21:28 +00:00
}
break ;
case 'quote' :
2013-12-12 08:01:01 +00:00
self :: $NoImg ++ ; // No images inside quote tags
self :: $InQuotes ++ ;
if ( self :: $InQuotes == self :: $NestsBeforeHide ) { //Put quotes that are nested beyond the specified limit in [hide] tags.
2013-06-21 08:00:44 +00:00
$Str .= '<strong>Older quotes</strong>: <a href="javascript:void(0);" onclick="BBCode.spoiler(this);">Show</a>' ;
$Str .= '<blockquote class="hidden spoiler">' ;
2013-04-22 08:00:58 +00:00
}
2013-04-05 08:00:43 +00:00
if ( ! empty ( $Block [ 'Attr' ])) {
2013-12-12 08:01:01 +00:00
$Exploded = explode ( '|' , self :: to_html ( $Block [ 'Attr' ]));
2013-08-28 23:08:41 +00:00
if ( isset ( $Exploded [ 1 ]) && ( is_numeric ( $Exploded [ 1 ]) || ( in_array ( $Exploded [ 1 ][ 0 ], array ( 'a' , 't' , 'c' , 'r' )) && is_numeric ( substr ( $Exploded [ 1 ], 1 ))))) {
// the part after | is either a number or starts with a, t, c or r, followed by a number (forum post, artist comment, torrent comment, collage comment or request comment, respectively)
2012-08-15 08:00:15 +00:00
$PostID = trim ( $Exploded [ 1 ]);
2013-08-28 23:08:41 +00:00
$Str .= '<a href="#" onclick="QuoteJump(event, \'' . $PostID . '\'); return false;"><strong class="quoteheader">' . $Exploded [ 0 ] . '</strong> wrote: </a>' ;
2012-08-12 08:00:16 +00:00
}
else {
2013-06-21 08:00:44 +00:00
$Str .= '<strong class="quoteheader">' . $Exploded [ 0 ] . '</strong> wrote: ' ;
2013-02-10 08:00:29 +00:00
}
2011-03-28 14:21:28 +00:00
}
2013-12-12 08:01:01 +00:00
$Str .= '<blockquote>' . self :: to_html ( $Block [ 'Val' ]) . '</blockquote>' ;
if ( self :: $InQuotes == self :: $NestsBeforeHide ) { //Close quote the deeply nested quote [hide].
2013-06-21 08:00:44 +00:00
$Str .= '</blockquote><br />' ; // Ensure new line after quote train hiding
2013-04-22 08:00:58 +00:00
}
2013-12-12 08:01:01 +00:00
self :: $NoImg -- ;
self :: $InQuotes -- ;
2011-03-28 14:21:28 +00:00
break ;
case 'hide' :
2013-06-21 08:00:44 +00:00
$Str .= '<strong>' . (( $Block [ 'Attr' ]) ? $Block [ 'Attr' ] : 'Hidden text' ) . '</strong>: <a href="javascript:void(0);" onclick="BBCode.spoiler(this);">Show</a>' ;
2013-12-12 08:01:01 +00:00
$Str .= '<blockquote class="hidden spoiler">' . self :: to_html ( $Block [ 'Val' ]) . '</blockquote>' ;
2011-03-28 14:21:28 +00:00
break ;
2012-12-03 08:00:16 +00:00
case 'mature' :
2013-08-28 23:08:41 +00:00
if ( G :: $LoggedUser [ 'EnableMatureContent' ]) {
2013-04-05 08:00:43 +00:00
if ( ! empty ( $Block [ 'Attr' ])) {
2013-06-21 08:00:44 +00:00
$Str .= '<strong class="mature" style="font-size: 1.2em;">Mature content:</strong><strong> ' . $Block [ 'Attr' ] . '</strong><br /> <a href="javascript:void(0);" onclick="BBCode.spoiler(this);">Show</a>' ;
2013-12-12 08:01:01 +00:00
$Str .= '<blockquote class="hidden spoiler">' . self :: to_html ( $Block [ 'Val' ]) . '</blockquote>' ;
2012-12-03 08:00:16 +00:00
}
else {
2013-06-21 08:00:44 +00:00
$Str .= '<strong>Use of the [mature] tag requires a description.</strong> The correct format is as follows: <strong>[mature=description] ...content... [/mature]</strong>, where "description" is a mandatory description of the post. Misleading descriptions will be penalized. For further information on our mature content policies, please refer to this <a href="wiki.php?action=article&id=1063">wiki</a>.' ;
2012-12-03 08:00:16 +00:00
}
}
else {
2013-08-28 23:08:41 +00:00
$Str .= '<span class="mature_blocked" style="font-style: italic;"><a href="wiki.php?action=article&id=1063">Mature content</a> has been blocked. You can choose to view mature content by editing your <a href="user.php?action=edit&userid=' . G :: $LoggedUser [ 'ID' ] . '">settings</a>.</span>' ;
2012-12-03 08:00:16 +00:00
}
break ;
2011-03-28 14:21:28 +00:00
case 'img' :
2013-12-12 08:01:01 +00:00
if ( self :: $NoImg > 0 && self :: valid_url ( $Block [ 'Val' ])) {
2013-06-21 08:00:44 +00:00
$Str .= '<a rel="noreferrer" target="_blank" href="' . $Block [ 'Val' ] . '">' . $Block [ 'Val' ] . '</a> (image)' ;
2011-03-28 14:21:28 +00:00
break ;
}
2013-12-12 08:01:01 +00:00
if ( ! self :: valid_url ( $Block [ 'Val' ], '\.(jpe?g|gif|png|bmp|tiff)' )) {
2013-06-21 08:00:44 +00:00
$Str .= '[img]' . $Block [ 'Val' ] . '[/img]' ;
2011-03-28 14:21:28 +00:00
} else {
2013-12-12 08:01:01 +00:00
$LocalURL = self :: local_url ( $Block [ 'Val' ]);
2013-04-05 08:00:43 +00:00
if ( $LocalURL ) {
2013-11-10 08:00:49 +00:00
$Str .= '<img class="scale_image" onclick="lightbox.init(this, $(this).width());" alt="' . $Block [ 'Val' ] . '" src="' . $LocalURL . '" />' ;
2011-03-28 14:21:28 +00:00
} else {
2013-11-10 08:00:49 +00:00
$Str .= '<img class="scale_image" onclick="lightbox.init(this, $(this).width());" alt="' . $Block [ 'Val' ] . '" src="' . ImageTools :: process ( $Block [ 'Val' ]) . '" />' ;
2011-03-28 14:21:28 +00:00
}
}
break ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
case 'aud' :
2013-12-12 08:01:01 +00:00
if ( self :: $NoImg > 0 && self :: valid_url ( $Block [ 'Val' ])) {
2013-06-21 08:00:44 +00:00
$Str .= '<a rel="noreferrer" target="_blank" href="' . $Block [ 'Val' ] . '">' . $Block [ 'Val' ] . '</a> (audio)' ;
2011-03-28 14:21:28 +00:00
break ;
}
2013-12-12 08:01:01 +00:00
if ( ! self :: valid_url ( $Block [ 'Val' ], '\.(mp3|ogg|wav)' )) {
2013-06-21 08:00:44 +00:00
$Str .= '[aud]' . $Block [ 'Val' ] . '[/aud]' ;
2011-03-28 14:21:28 +00:00
} else {
//TODO: Proxy this for staff?
2013-06-21 08:00:44 +00:00
$Str .= '<audio controls="controls" src="' . $Block [ 'Val' ] . '"><a rel="noreferrer" target="_blank" href="' . $Block [ 'Val' ] . '">' . $Block [ 'Val' ] . '</a></audio>' ;
2011-03-28 14:21:28 +00:00
}
break ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
case 'url' :
// Make sure the URL has a label
2013-04-05 08:00:43 +00:00
if ( empty ( $Block [ 'Val' ])) {
2011-03-28 14:21:28 +00:00
$Block [ 'Val' ] = $Block [ 'Attr' ];
$NoName = true ; // If there isn't a Val for this
} else {
2013-12-12 08:01:01 +00:00
$Block [ 'Val' ] = self :: to_html ( $Block [ 'Val' ]);
2011-03-28 14:21:28 +00:00
$NoName = false ;
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
if ( ! self :: valid_url ( $Block [ 'Attr' ])) {
2013-06-21 08:00:44 +00:00
$Str .= '[url=' . $Block [ 'Attr' ] . ']' . $Block [ 'Val' ] . '[/url]' ;
2011-03-28 14:21:28 +00:00
} else {
2013-12-12 08:01:01 +00:00
$LocalURL = self :: local_url ( $Block [ 'Attr' ]);
2013-04-05 08:00:43 +00:00
if ( $LocalURL ) {
if ( $NoName ) { $Block [ 'Val' ] = substr ( $LocalURL , 1 ); }
2013-06-21 08:00:44 +00:00
$Str .= '<a href="' . $LocalURL . '">' . $Block [ 'Val' ] . '</a>' ;
2011-03-28 14:21:28 +00:00
} else {
2013-06-21 08:00:44 +00:00
$Str .= '<a rel="noreferrer" target="_blank" href="' . $Block [ 'Attr' ] . '">' . $Block [ 'Val' ] . '</a>' ;
2011-03-28 14:21:28 +00:00
}
}
break ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
case 'inlineurl' :
2013-12-12 08:01:01 +00:00
if ( ! self :: valid_url ( $Block [ 'Attr' ], '' , true )) {
$Array = self :: parse ( $Block [ 'Attr' ]);
2011-03-28 14:21:28 +00:00
$Block [ 'Attr' ] = $Array ;
2013-12-12 08:01:01 +00:00
$Str .= self :: to_html ( $Block [ 'Attr' ]);
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
else {
2013-12-12 08:01:01 +00:00
$LocalURL = self :: local_url ( $Block [ 'Attr' ]);
2013-04-05 08:00:43 +00:00
if ( $LocalURL ) {
2013-06-21 08:00:44 +00:00
$Str .= '<a href="' . $LocalURL . '">' . substr ( $LocalURL , 1 ) . '</a>' ;
2011-03-28 14:21:28 +00:00
} else {
2013-06-21 08:00:44 +00:00
$Str .= '<a rel="noreferrer" target="_blank" href="' . $Block [ 'Attr' ] . '">' . $Block [ 'Attr' ] . '</a>' ;
2012-10-27 08:00:09 +00:00
}
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
break ;
2013-05-16 16:15:57 +00:00
2011-03-28 14:21:28 +00:00
}
}
2013-04-22 08:00:58 +00:00
}
2013-12-12 08:01:01 +00:00
self :: $Levels -- ;
2011-03-28 14:21:28 +00:00
return $Str ;
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
private static function raw_text ( $Array ) {
2011-03-28 14:21:28 +00:00
$Str = '' ;
2013-04-05 08:00:43 +00:00
foreach ( $Array as $Block ) {
if ( is_string ( $Block )) {
2013-06-21 08:00:44 +00:00
$Str .= $Block ;
2011-03-28 14:21:28 +00:00
continue ;
}
2013-04-22 08:00:58 +00:00
switch ( $Block [ 'Type' ]) {
2012-10-27 08:00:09 +00:00
case 'headline' :
break ;
2011-03-28 14:21:28 +00:00
case 'b' :
case 'u' :
case 'i' :
case 's' :
case 'color' :
case 'size' :
case 'quote' :
case 'align' :
2013-05-16 16:15:57 +00:00
2013-12-12 08:01:01 +00:00
$Str .= self :: raw_text ( $Block [ 'Val' ]);
2011-03-28 14:21:28 +00:00
break ;
case 'tex' : //since this will never strip cleanly, just remove it
break ;
case 'artist' :
case 'user' :
case 'wiki' :
case 'pre' :
2011-07-10 08:00:06 +00:00
case 'code' :
2011-03-28 14:21:28 +00:00
case 'aud' :
case 'img' :
2013-06-21 08:00:44 +00:00
$Str .= $Block [ 'Val' ];
2011-03-28 14:21:28 +00:00
break ;
case 'list' :
2013-04-05 08:00:43 +00:00
foreach ( $Block [ 'Val' ] as $Line ) {
2013-12-12 08:01:01 +00:00
$Str .= $Block [ 'Tag' ] . self :: raw_text ( $Line );
2011-03-28 14:21:28 +00:00
}
break ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
case 'url' :
// Make sure the URL has a label
2013-04-05 08:00:43 +00:00
if ( empty ( $Block [ 'Val' ])) {
2011-03-28 14:21:28 +00:00
$Block [ 'Val' ] = $Block [ 'Attr' ];
} else {
2013-12-12 08:01:01 +00:00
$Block [ 'Val' ] = self :: raw_text ( $Block [ 'Val' ]);
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2013-06-21 08:00:44 +00:00
$Str .= $Block [ 'Val' ];
2011-03-28 14:21:28 +00:00
break ;
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
case 'inlineurl' :
2013-12-12 08:01:01 +00:00
if ( ! self :: valid_url ( $Block [ 'Attr' ], '' , true )) {
$Array = self :: parse ( $Block [ 'Attr' ]);
2011-03-28 14:21:28 +00:00
$Block [ 'Attr' ] = $Array ;
2013-12-12 08:01:01 +00:00
$Str .= self :: raw_text ( $Block [ 'Attr' ]);
2011-03-28 14:21:28 +00:00
}
else {
2013-06-21 08:00:44 +00:00
$Str .= $Block [ 'Attr' ];
2011-03-28 14:21:28 +00:00
}
2012-10-27 08:00:09 +00:00
2011-03-28 14:21:28 +00:00
break ;
}
}
return $Str ;
}
2012-10-27 08:00:09 +00:00
2013-12-12 08:01:01 +00:00
private static function smileys ( $Str ) {
2013-08-28 23:08:41 +00:00
if ( ! empty ( G :: $LoggedUser [ 'DisableSmileys' ])) {
2011-03-28 14:21:28 +00:00
return $Str ;
}
2013-12-12 08:01:01 +00:00
if ( count ( self :: $ProcessedSmileys ) == 0 && count ( self :: $Smileys ) > 0 ) {
foreach ( self :: $Smileys as $Key => $Val ) {
self :: $ProcessedSmileys [ $Key ] = '<img border="0" src="' . STATIC_SERVER . 'common/smileys/' . $Val . '" alt="" />' ;
}
reset ( self :: $ProcessedSmileys );
}
$Str = strtr ( $Str , self :: $ProcessedSmileys );
2011-03-28 14:21:28 +00:00
return $Str ;
}
}
/*
2013-06-26 08:01:00 +00:00
// Uncomment this part to test the class via command line:
function display_str ( $Str ) {
return $Str ;
}
function check_perms ( $Perm ) {
return true ;
}
2012-10-27 08:00:09 +00:00
$Str = " hello
2011-03-28 14:21:28 +00:00
[ pre ] http :// anonym . to / ? http :// whatshirts . portmerch . com /
==== hi ====
=== hi ===
== hi == [ / pre ]
==== hi ====
hi " ;
2013-12-12 08:01:01 +00:00
echo Text :: full_format ( $Str );
2011-03-28 14:21:28 +00:00
echo " \n "
*/