2021-12-14 18:32:47 +00:00
< ? php
declare ( strict_types = 1 );
2019-08-07 19:53:59 +00:00
2023-01-10 22:44:09 +00:00
namespace Shimmie2 ;
2007-07-08 18:56:29 +00:00
2019-05-28 16:59:38 +00:00
class BBCode extends FormatterExtension
{
public function format ( string $text ) : string
2024-01-01 16:05:48 +00:00
{
$text = $this -> _format ( $text );
return " <span class='bbcode'> $text </span> " ;
}
public function _format ( string $text ) : string
2019-05-28 16:59:38 +00:00
{
$text = $this -> extract_code ( $text );
foreach ([
" b " , " i " , " u " , " s " , " sup " , " sub " , " h1 " , " h2 " , " h3 " , " h4 " ,
] as $el ) {
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " ! \ [ $el\ ](.*?) \ [/ $el\ ]!s " , " < $el > $ 1</ $el > " , $text );
2019-05-28 16:59:38 +00:00
}
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( '!^>>([^\d].+)!' , '<blockquote><small>$1</small></blockquote>' , $text );
$text = preg_replace_ex ( '!>>(\d+)(#c?\d+)?!s' , '<a class="shm-clink" data-clink-sel="$2" href="' . make_link ( 'post/view/$1$2' ) . '">>>$1$2</a>' , $text );
$text = preg_replace_ex ( '!\[anchor=(.*?)\](.*?)\[/anchor\]!s' , '<span class="anchor">$2 <a class="alink" href="#bb-$1" name="bb-$1" title="link to this anchor"> ¶ </a></span>' , $text ); // add "bb-" to avoid clashing with eg #top
$text = preg_replace_ex ( '!\[url=site://(.*?)(#c\d+)?\](.*?)\[/url\]!s' , '<a class="shm-clink" data-clink-sel="$2" href="' . make_link ( '$1$2' ) . '">$3</a>' , $text );
$text = preg_replace_ex ( '!\[url\]site://(.*?)(#c\d+)?\[/url\]!s' , '<a class="shm-clink" data-clink-sel="$2" href="' . make_link ( '$1$2' ) . '">$1$2</a>' , $text );
$text = preg_replace_ex ( '!\[url=((?:https?|ftp|irc|mailto)://.*?)\](.*?)\[/url\]!s' , '<a href="$1">$2</a>' , $text );
$text = preg_replace_ex ( '!\[url\]((?:https?|ftp|irc|mailto)://.*?)\[/url\]!s' , '<a href="$1">$1</a>' , $text );
$text = preg_replace_ex ( '!\[email\](.*?)\[/email\]!s' , '<a href="mailto:$1">$1</a>' , $text );
$text = preg_replace_ex ( '!\[img\](https?:\/\/.*?)\[/img\]!s' , '<img alt="user image" src="$1">' , $text );
2024-08-31 20:28:59 +00:00
$text = preg_replace_ex ( '!\[img\]site://(.*?)(#c\d+)?\[/img\]!s' , '<img alt="user image" src="' . make_link ( '$1$2' ) . '">' , $text );
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( '!\[\[([^\|\]]+)\|([^\]]+)\]\]!s' , '<a href="' . make_link ( 'wiki/$1' ) . '">$2</a>' , $text );
$text = preg_replace_ex ( '!\[\[([^\]]+)\]\]!s' , '<a href="' . make_link ( 'wiki/$1' ) . '">$1</a>' , $text );
$text = preg_replace_ex ( " ! \n \ s* \n ! " , " \n \n " , $text );
2019-05-28 16:59:38 +00:00
$text = str_replace ( " \n " , " \n <br> " , $text );
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " / \ [quote \ ](.*?) \ [ \ /quote \ ]/s " , " <blockquote><small> \\ 1</small></blockquote> " , $text );
$text = preg_replace_ex ( " / \ [quote=(.*?) \ ](.*?) \ [ \ /quote \ ]/s " , " <blockquote><em> \\ 1 said:</em><br><small> \\ 2</small></blockquote> " , $text );
2019-05-28 16:59:38 +00:00
while ( preg_match ( " / \ [list \ ](.*?) \ [ \ /list \ ]/s " , $text )) {
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " / \ [list \ ](.*?) \ [ \ /list \ ]/s " , " <ul> \\ 1</ul> " , $text );
2019-05-28 16:59:38 +00:00
}
while ( preg_match ( " / \ [ul \ ](.*?) \ [ \ /ul \ ]/s " , $text )) {
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " / \ [ul \ ](.*?) \ [ \ /ul \ ]/s " , " <ul> \\ 1</ul> " , $text );
2019-05-28 16:59:38 +00:00
}
while ( preg_match ( " / \ [ol \ ](.*?) \ [ \ /ol \ ]/s " , $text )) {
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " / \ [ol \ ](.*?) \ [ \ /ol \ ]/s " , " <ol> \\ 1</ol> " , $text );
2019-05-28 16:59:38 +00:00
}
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " / \ [li \ ](.*?) \ [ \ /li \ ]/s " , " <li> \\ 1</li> " , $text );
$text = preg_replace_ex ( " # \ [ \ * \ ]#s " , " <li> " , $text );
$text = preg_replace_ex ( " #<br><(li|ul|ol|/ul|/ol)>#s " , " < \\ 1> " , $text );
$text = preg_replace_ex ( " # \ [align=(left|center|right) \ ](.*?) \ [ \ /align \ ]#s " , " <div style='text-align: \\ 1;'> \\ 2</div> " , $text );
2019-05-28 16:59:38 +00:00
$text = $this -> filter_spoiler ( $text );
$text = $this -> insert_code ( $text );
return $text ;
}
public function strip ( string $text ) : string
{
foreach ([
" b " , " i " , " u " , " s " , " sup " , " sub " , " h1 " , " h2 " , " h3 " , " h4 " ,
" code " , " url " , " email " , " li " ,
] as $el ) {
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " ! \ [ $el\ ](.*?) \ [/ $el\ ]!s " , '$1' , $text );
2019-05-28 16:59:38 +00:00
}
2024-08-31 18:53:07 +00:00
$text = preg_replace_ex ( " ! \ [anchor=(.*?) \ ](.*?) \ [/anchor \ ]!s " , '$2' , $text );
$text = preg_replace_ex ( " ! \ [url=(.*?) \ ](.*?) \ [/url \ ]!s " , '$2' , $text );
$text = preg_replace_ex ( " ! \ [img \ ](.*?) \ [/img \ ]!s " , " " , $text );
$text = preg_replace_ex ( " ! \ [ \ [([^ \ | \ ]]+) \ |([^ \ ]]+) \ ] \ ]!s " , '$2' , $text );
$text = preg_replace_ex ( " ! \ [ \ [([^ \ ]]+) \ ] \ ]!s " , '$1' , $text );
$text = preg_replace_ex ( " ! \ [quote \ ](.*?) \ [/quote \ ]!s " , " " , $text );
$text = preg_replace_ex ( " ! \ [quote=(.*?) \ ](.*?) \ [/quote \ ]!s " , " " , $text );
$text = preg_replace_ex ( " ! \ [/?(list|ul|ol) \ ]! " , " " , $text );
$text = preg_replace_ex ( " ! \ [ \ * \ ](.*?)!s " , '$1' , $text );
2019-05-28 16:59:38 +00:00
$text = $this -> strip_spoiler ( $text );
return $text ;
}
private function filter_spoiler ( string $text ) : string
{
return str_replace (
[ " [spoiler] " , " [/spoiler] " ],
[ " <span style= \" background-color:#000; color:#000; \" > " , " </span> " ],
$text
);
}
private function strip_spoiler ( string $text ) : string
{
$l1 = strlen ( " [spoiler] " );
$l2 = strlen ( " [/spoiler] " );
while ( true ) {
$start = strpos ( $text , " [spoiler] " );
if ( $start === false ) {
break ;
}
$end = strpos ( $text , " [/spoiler] " );
if ( $end === false ) {
break ;
}
if ( $end < $start ) {
break ;
}
$beginning = substr ( $text , 0 , $start );
2023-11-11 21:49:12 +00:00
$middle = str_rot13 ( substr ( $text , $start + $l1 , ( $end - $start - $l1 )));
$ending = substr ( $text , $end + $l2 , ( strlen ( $text ) - $end + $l2 ));
2019-05-28 16:59:38 +00:00
$text = $beginning . $middle . $ending ;
}
return $text ;
}
private function extract_code ( string $text ) : string
{
# at the end of this function, the only code! blocks should be
# the ones we've added -- others may contain malicious content,
# which would only appear after decoding
$text = str_replace ( " [code!] " , " [code] " , $text );
$text = str_replace ( " [/code!] " , " [/code] " , $text );
$l1 = strlen ( " [code] " );
$l2 = strlen ( " [/code] " );
while ( true ) {
$start = strpos ( $text , " [code] " );
if ( $start === false ) {
break ;
}
$end = strpos ( $text , " [/code] " , $start );
if ( $end === false ) {
break ;
}
if ( $end < $start ) {
break ;
}
$beginning = substr ( $text , 0 , $start );
2023-11-11 21:49:12 +00:00
$middle = base64_encode ( substr ( $text , $start + $l1 , ( $end - $start - $l1 )));
$ending = substr ( $text , $end + $l2 , ( strlen ( $text ) - $end + $l2 ));
2019-05-28 16:59:38 +00:00
$text = $beginning . " [code!] " . $middle . " [/code!] " . $ending ;
}
return $text ;
}
private function insert_code ( string $text ) : string
{
$l1 = strlen ( " [code!] " );
$l2 = strlen ( " [/code!] " );
while ( true ) {
$start = strpos ( $text , " [code!] " );
if ( $start === false ) {
break ;
}
$end = strpos ( $text , " [/code!] " );
if ( $end === false ) {
break ;
}
$beginning = substr ( $text , 0 , $start );
2023-11-11 21:49:12 +00:00
$middle = base64_decode ( substr ( $text , $start + $l1 , ( $end - $start - $l1 )));
$ending = substr ( $text , $end + $l2 , ( strlen ( $text ) - $end + $l2 ));
2019-05-28 16:59:38 +00:00
2024-06-11 15:02:52 +00:00
$text = $beginning . " <pre><code> " . $middle . " </code></pre> " . $ending ;
2019-05-28 16:59:38 +00:00
}
return $text ;
}
2007-07-08 18:56:29 +00:00
}