(.*?)\<\;br\>\;(.*?)\<\/code\>/ism','$1
$2
',$Text);
} while ($replaced != $Text);
// bbcode code blocks are wrapped in . Do the same for markdown code blocks so that the styling is consistent
$Text = str_replace([ '', '
' ], [ '', '
' ] , $Text);
$Text = str_replace('&_lt;br&_gt;','<br>', $Text);
// END markdown quirks
$Text = str_replace(array("\t", " "), array(" ", " "), $Text);
// Check for [code] text
if (strpos($Text,'[code]') !== false) {
$Text = preg_replace_callback("/\[code\](.*?)\[\/code\]/ism", 'bb_code', $Text);
}
// Check for [code options] text
if (strpos($Text,'[code ') !== false) {
$Text = preg_replace_callback("/\[code(.*?)\](.*?)\[\/code\]/ism", 'bb_code_options', $Text);
}
// Set up the parameters for a URL search string
$URLSearchString = "^\[\]";
// Set up the parameters for a MAIL search string
$MAILSearchString = $URLSearchString;
// replace [observer.baseurl]
if ($observer) {
$s1 = '';
$s2 = '';
$obsBaseURL = $observer['xchan_connurl'];
$obsBaseURL = preg_replace("/\/poco\/.*$/", '', $obsBaseURL);
$Text = str_replace('[observer.baseurl]', $obsBaseURL, $Text);
$Text = str_replace('[observer.url]',$observer['xchan_url'], $Text);
$Text = str_replace('[observer.name]',$s1 . $observer['xchan_name'] . $s2, $Text);
$Text = str_replace('[observer.address]',$s1 . $observer['xchan_addr'] . $s2, $Text);
$Text = str_replace('[observer.webname]', substr($observer['xchan_addr'],0,strpos($observer['xchan_addr'],'@')), $Text);
$Text = str_replace('[observer.photo]',$s1 . '[zmg]'.$observer['xchan_photo_l'].'[/zmg]' . $s2, $Text);
$Text = str_replace('[observer.baseurl/]', $obsBaseURL, $Text);
$Text = str_replace('[observer.url/]',$observer['xchan_url'], $Text);
$Text = str_replace('[observer.name/]',$s1 . $observer['xchan_name'] . $s2, $Text);
$Text = str_replace('[observer.address/]',$s1 . $observer['xchan_addr'] . $s2, $Text);
$Text = str_replace('[observer.webname/]', substr($observer['xchan_addr'],0,strpos($observer['xchan_addr'],'@')), $Text);
$Text = str_replace('[observer.photo/]',$s1 . '[zmg]'.$observer['xchan_photo_l'].'[/zmg]' . $s2, $Text);
} else {
$Text = str_replace('[observer.baseurl]', '', $Text);
$Text = str_replace('[observer.url]','', $Text);
$Text = str_replace('[observer.name]','', $Text);
$Text = str_replace('[observer.address]','', $Text);
$Text = str_replace('[observer.webname]','',$Text);
$Text = str_replace('[observer.photo]','', $Text);
$Text = str_replace('[observer.baseurl/]', '', $Text);
$Text = str_replace('[observer.url/]','', $Text);
$Text = str_replace('[observer.name/]','', $Text);
$Text = str_replace('[observer.address/]','', $Text);
$Text = str_replace('[observer.webname/]','',$Text);
$Text = str_replace('[observer.photo/]','', $Text);
}
// Perform URL Search
$urlchars = '[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]';
if (strpos($Text,'http') !== false) {
$Text = preg_replace("/([^\]\='".'"'."\;\/])(https?\:\/\/$urlchars+)/ismu", '$1$2', $Text);
}
if (strpos($Text,'[/share]') !== false) {
$Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", 'bb_ShareAttributes', $Text);
}
if (strpos($Text,'[/url]') !== false) {
// $Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '#^$1', $Text);
// $Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '#^$2', $Text);
$Text = preg_replace("/\[url\]([$URLSearchString]*)\[\/url\]/ism", '$1', $Text);
$Text = preg_replace("/\@(\!?)\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '@$1$3', $Text);
$Text = preg_replace("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$2', $Text);
}
if (strpos($Text,'[/zrl]') !== false) {
// render hubzilla bookmarks as normal links
$Text = preg_replace("/\#\^\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '$1', $Text);
$Text = preg_replace("/\#\^\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '$2', $Text);
$Text = preg_replace("/\[zrl\]([$URLSearchString]*)\[\/zrl\]/ism", '$1', $Text);
$Text = preg_replace("/\@(\!?)\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '@$1$3', $Text);
$Text = preg_replace("/\[zrl\=([$URLSearchString]*)\](.*?)\[\/zrl\]/ism", '$2', $Text);
}
// named anchors do not work well in conversational text, as it is often collapsed by a "showmore" script.
// Included here for completeness.
if (strpos($Text,'[/anchor]') !== false) {
$Text = preg_replace("/\[anchor\](.*?)\[\/anchor\]/ism", '', $Text);
}
if (strpos($Text,'[/goto]') !== false) {
$Text = preg_replace("/\[goto=(.*?)\](.*?)\[\/goto\]/ism", '$2', $Text);
}
// Perform MAIL Search
if (strpos($Text,'[/mail]') !== false) {
$Text = preg_replace("/\[mail\]([$MAILSearchString]*)\[\/mail\]/", '$1', $Text);
$Text = preg_replace("/\[mail\=([$MAILSearchString]*)\](.*?)\[\/mail\]/", '$2', $Text);
}
// leave open the posibility of [map=something]
// this is replaced in prepare_body() which has knowledge of the item location
if ($export) {
$Text = str_replace( [ '[map]','[/map]' ], [ '','' ] , $Text);
$Text = preg_replace("/\[map=(.*?)[, ](.*?)\]/ism", 'geo:$1,$2', $Text);
}
else {
if (strpos($Text,'[/map]') !== false) {
$Text = preg_replace_callback("/\[map\](.*?)\[\/map\]/ism", 'bb_map_location', $Text);
}
if (strpos($Text,'[map=') !== false) {
$Text = preg_replace_callback("/\[map=(.*?)\/\]/ism", 'bb_map_coords', $Text);
$Text = preg_replace_callback("/\[map=(.*?)\]/ism", 'bb_map_coords', $Text);
}
if (strpos($Text,'[map]') !== false) {
$Text = preg_replace("/\[map\/\]/", '', $Text);
$Text = preg_replace("/\[map\]/", '', $Text);
}
}
// Check for bold text
if (strpos($Text,'[b]') !== false) {
$Text = preg_replace("(\[b\](.*?)\[\/b\])ism", '$1', $Text);
}
// Check for Italics text
if (strpos($Text,'[i]') !== false) {
$Text = preg_replace("(\[i\](.*?)\[\/i\])ism", '$1', $Text);
}
// Check for Underline text
if (strpos($Text,'[u]') !== false) {
$Text = preg_replace("(\[u\](.*?)\[\/u\])ism", '$1', $Text);
}
// Check for strike-through text
if (strpos($Text,'[s]') !== false) {
$Text = preg_replace("(\[s\](.*?)\[\/s\])ism", '$1', $Text);
}
// Check for over-line text
if (strpos($Text,'[o]') !== false) {
$Text = preg_replace("(\[o\](.*?)\[\/o\])ism", '$1', $Text);
}
if (strpos($Text,'[sup]') !== false) {
$Text = preg_replace("(\[sup\](.*?)\[\/sup\])ism", '$1', $Text);
}
if (strpos($Text,'[sub]') !== false) {
$Text = preg_replace("(\[sub\](.*?)\[\/sub\])ism", '$1', $Text);
}
// Check for colored text
if (strpos($Text,'[/color]') !== false) {
$Text = preg_replace("(\[color=(.*?)\](.*?)\[\/color\])ism", "$2", $Text);
}
// Check for colored text
if (strpos($Text,'[/hl]') !== false) {
$Text = preg_replace("(\[hl\](.*?)\[\/hl\])ism", "$1", $Text);
$Text = preg_replace("(\[hl=(.*?)\](.*?)\[\/hl\])ism", "$2", $Text);
}
// Check for sized text
// [size=50] --> font-size: 50px (with the unit).
if (strpos($Text,'[/size]') !== false) {
$Text = preg_replace("(\[size=(\d*?)\](.*?)\[\/size\])ism", "$2", $Text);
$Text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $Text);
}
// Check for h1
if (strpos($Text,'[h1]') !== false) {
$Text = preg_replace("(\[h1\](.*?)\[\/h1\])ism",'$1
',$Text);
$Text = str_replace('
', '', $Text);
}
// Check for h2
if (strpos($Text,'[h2]') !== false) {
$Text = preg_replace("(\[h2\](.*?)\[\/h2\])ism",'$1
',$Text);
$Text = str_replace('
', '', $Text);
}
// Check for h3
if (strpos($Text,'[h3]') !== false) {
$Text = preg_replace("(\[h3\](.*?)\[\/h3\])ism",'$1
',$Text);
$Text = str_replace('
', '', $Text);
}
// Check for h4
if (strpos($Text,'[h4]') !== false) {
$Text = preg_replace("(\[h4\](.*?)\[\/h4\])ism",'$1
',$Text);
$Text = str_replace('
', '', $Text);
}
// Check for h5
if (strpos($Text,'[h5]') !== false) {
$Text = preg_replace("(\[h5\](.*?)\[\/h5\])ism",'$1
',$Text);
$Text = str_replace('
', '', $Text);
}
// Check for h6
if (strpos($Text,'[h6]') !== false) {
$Text = preg_replace("(\[h6\](.*?)\[\/h6\])ism",'$1
',$Text);
$Text = str_replace('
', '', $Text);
}
// Check for table of content without params
while(strpos($Text,'[toc]') !== false) {
$toc_id = 'toc-' . random_string(10);
$Text = preg_replace("/\[toc\]/ism", '
', $Text, 1);
$Text = preg_replace("/\[toc\/\]/ism", '', $Text, 1);
}
// Check for table of content with params
while(strpos($Text,'[toc') !== false) {
$toc_id = 'toc-' . random_string(10);
$Text = preg_replace("/\[toc([^\]]+?)\/\]/ism", '', $Text, 1);
$Text = preg_replace("/\[toc([^\]]+?)\]/ism", '', $Text, 1);
}
// Check for centered text
if (strpos($Text,'[/center]') !== false) {
$Text = preg_replace("(\[center\](.*?)\[\/center\])ism", "$1
", $Text);
}
// Check for footer
if (strpos($Text,'[/footer]') !== false) {
$Text = preg_replace("(\[footer\](.*?)\[\/footer\])ism", "", $Text);
}
// Check for bdi
if (strpos($Text,'[/bdi]') !== false) {
$Text = preg_replace("(\[bdi\](.*?)\[\/bdi\])ism", "$1", $Text);
}
// Check for list text
$Text = preg_replace("/
\[\*\/\]/ism",'[*/]',$Text);
$Text = preg_replace("/
\[\*\]/ism",'[*/]',$Text);
$Text = str_replace("[*/]", "", $Text);
$Text = str_replace("[*]", "", $Text);
// handle nested lists
$endlessloop = 0;
while ((((strpos($Text, "[/list]") !== false) && (strpos($Text, "[list") !== false)) ||
((strpos($Text, "[/ol]") !== false) && (strpos($Text, "[ol]") !== false)) ||
((strpos($Text, "[/ul]") !== false) && (strpos($Text, "[ul]") !== false)) ||
((strpos($Text, "[/dl]") !== false) && (strpos($Text, "[dl") !== false)) ||
((strpos($Text, "[/li]") !== false) && (strpos($Text, "[li]") !== false))) && (++$endlessloop < 20)) {
$Text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '', $Text);
$Text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '', $Text);
$Text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '', $Text);
$Text = preg_replace("/\[list=((?-i)i)\](.*?)\[\/list\]/ism",'', $Text);
$Text = preg_replace("/\[list=((?-i)I)\](.*?)\[\/list\]/ism", '', $Text);
$Text = preg_replace("/\[list=((?-i)a)\](.*?)\[\/list\]/ism", '', $Text);
$Text = preg_replace("/\[list=((?-i)A)\](.*?)\[\/list\]/ism", '', $Text);
$Text = preg_replace("/\[ul\](.*?)\[\/ul\]/ism", '', $Text);
$Text = preg_replace("/\[ol\](.*?)\[\/ol\]/ism", '', $Text);
$Text = preg_replace("/\[\/li\]
\[li\]/ism",'[/li][li]',$Text);
$Text = preg_replace("/\[li\](.*?)\[\/li\]/ism", '$1', $Text);
// [dl] tags have an optional [dl terms="bi"] form where bold/italic/underline/mono/large
// etc. style may be specified for the "terms" in the definition list. The quotation marks
// are also optional. The regex looks intimidating, but breaks down as:
// "[dl" "]" "[/dl]"
// where optional-termStyles are: "terms="
$Text = preg_replace_callback('/\[dl[[:space:]]*(?:terms=(?:"|")?([a-zA-Z]+)(?:"|")?)?\](.*?)\[\/dl\]/ism', 'bb_definitionList', $Text);
}
// Friendica generates this
if (strpos($Text,'[/abstract]') !== false) {
$Text = preg_replace("/\[abstract\](.*?)\[\/abstract\]/ism", '$1
', $Text);
}
if (strpos($Text,'[checklist]') !== false) {
$Text = preg_replace_callback("/\[checklist\](.*?)\[\/checklist\]/ism", 'bb_checklist', $Text);
}
if (strpos($Text,'[th]') !== false) {
$Text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '$1 | ', $Text);
}
if (strpos($Text,'[td]') !== false) {
$Text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '$1 | ', $Text);
}
if (strpos($Text,'[tr]') !== false) {
$Text = preg_replace("/\[tr\](.*?)\[\/tr\]/sm", '$1
', $Text);
}
if (strpos($Text,'[/table]') !== false) {
$Text = preg_replace("/\[table\](.*?)\[\/table\]/sm", '', $Text);
$Text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '', $Text);
$Text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '', $Text);
}
$Text = str_replace('
', "
\n", $Text);
$Text = str_replace('[hr]', '
', $Text);
$Text = str_replace('[hr/]', '
', $Text);
// This is actually executed in prepare_body()
$Text = str_replace('[nosmile]', '', $Text);
$Text = str_replace('[nosmile/]', '', $Text);
// Check for font change text
if (strpos($Text,'[/font]') !== false) {
$Text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "$2", $Text);
}
if(strpos($Text,'[/summary]') !== false) {
$Text = preg_replace_callback("/^(.*?)\[summary\](.*?)\[\/summary\](.*?)$/ism", 'bb_summary', $Text);
}
// Check for [spoiler] text
$endlessloop = 0;
while ((strpos($Text, "[/spoiler]")!== false) and (strpos($Text, "[spoiler]") !== false) and (++$endlessloop < 20)) {
$Text = preg_replace_callback("/\[spoiler\](.*?)\[\/spoiler\]/ism", 'bb_spoilertag', $Text);
}
// Check for [spoiler=Author] text
$endlessloop = 0;
while ((strpos($Text, "[/spoiler]")!== false) and (strpos($Text, "[spoiler=") !== false) and (++$endlessloop < 20)) {
$Text = preg_replace_callback("/\[spoiler=(.*?)\](.*?)\[\/spoiler\]/ism", 'bb_spoilertag', $Text);
}
// Check for [open] text
$endlessloop = 0;
while ((strpos($Text, "[/open]")!== false) and (strpos($Text, "[open]") !== false) and (++$endlessloop < 20)) {
$Text = preg_replace_callback("/\[open\](.*?)\[\/open\]/ism", 'bb_opentag', $Text);
}
// Check for [open=Title] text
$endlessloop = 0;
while ((strpos($Text, "[/open]")!== false) and (strpos($Text, "[open=") !== false) and (++$endlessloop < 20)) {
$Text = preg_replace_callback("/\[open=(.*?)\](.*?)\[\/open\]/ism", 'bb_opentag', $Text);
}
// Declare the format for [quote] layout
$QuoteLayout = '$1
';
// Check for [quote] text
// handle nested quotes
$endlessloop = 0;
while ((strpos($Text, "[/quote]") !== false) and (strpos($Text, "[quote]") !== false) and (++$endlessloop < 20))
$Text = preg_replace("/\[quote\](.*?)\[\/quote\]/ism", "$QuoteLayout", $Text);
// Check for [quote=Author] text
$t_wrote = t('$1 wrote:');
// handle nested quotes
$endlessloop = 0;
while ((strpos($Text, "[/quote]")!== false) and (strpos($Text, "[quote=") !== false) and (++$endlessloop < 20))
$Text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism",
"" . $t_wrote . "$2
",
$Text);
if ($plain) {
$Text = str_replace([ '','
' ], [ '“', '”' ], $Text);
}
// Images
// [img]pathtoimage[/img]
if (strpos($Text,'[/img]') !== false) {
$Text = preg_replace("/\[img\](.*?)\[\/img\]/ism", '', $Text);
// Friendica's modified bbcode img tags
$Text = preg_replace("/\[img=http(.*?)\](.*?)\[\/img\]/ism", '', $Text);
}
if (strpos($Text,'[/zmg]') !== false) {
$Text = preg_replace("/\[zmg\](.*?)\[\/zmg\]/ism", '', $Text);
}
$Text = preg_replace_callback("/\[([zi])mg([ \=])(.*?)\](.*?)\[\/[zi]mg\]/ism",'bb_imgoptions',$Text);
if($censored) {
$Text = separate_img_links($Text);
$Text = preg_replace_callback("/\/ism","bb_colorbox",$Text);
}
// style (sanitized)
if (strpos($Text,'[/style]') !== false) {
$Text = preg_replace_callback("(\[style=(.*?)\](.*?)\[\/style\])ism", "bb_sanitize_style", $Text);
}
// crypt
if (strpos($Text,'[/crypt]') !== false) {
if ($activitypub) {
$Text = preg_replace("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", '
', $Text);
}
else {
$Text = preg_replace_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_crypt', $Text);
}
}
if (strpos($Text,'[/app]') !== false) {
if ($activitypub) {
$Text = preg_replace_callback("/\[app\](.*?)\[\/app\]/ism",'bb_parse_app_ap', $Text);
}
else {
$Text = preg_replace_callback("/\[app\](.*?)\[\/app\]/ism",'bb_parse_app', $Text);
}
}
if(strpos($Text,'[/element]') !== false) {
$Text = preg_replace_callback("/\[element\](.*?)\[\/element\]/ism",'bb_parse_element', $Text);
}
// html5 video and audio
if (strpos($Text,'[/video]') !== false) {
$Text = preg_replace_callback("/\[video (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg|mov))\[\/video\]/ism", 'videowithopts', $Text);
$Text = preg_replace_callback("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg|mov))\[\/video\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
$Text = preg_replace_callback("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/audio\]/ism", 'tryzrlaudio', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
$Text = preg_replace_callback("/\[zvideo (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg|mov))\[\/zvideo\]/ism", 'videowithopts', $Text);
$Text = preg_replace_callback("/\[zvideo\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg|mov))\[\/zvideo\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
$Text = preg_replace_callback("/\[zaudio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/zaudio\]/ism", 'tryzrlaudio', $Text);
}
// if video couldn't be embedded, link to it instead.
if (strpos($Text,'[/video]') !== false) {
$Text = preg_replace("/\[video\](.*?)\[\/video\]/", '$1', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
$Text = preg_replace("/\[audio\](.*?)\[\/audio\]/", '$1', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
$Text = preg_replace("/\[zvideo\](.*?)\[\/zvideo\]/", '$1', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
$Text = preg_replace("/\[zaudio\](.*?)\[\/zaudio\]/", '$1', $Text);
}
// SVG stuff
if ($activitypub) {
$Text = preg_replace_callback("/\[svg(.*?)\](.*?)\[\/svg\]/ism", 'bb_svg_export', $Text);
}
else {
$Text = preg_replace_callback("/\[svg(.*?)\](.*?)\[\/svg\]/ism", 'bb_svg', $Text);
}
// oembed tag
if(! $export)
$Text = oembed_bbcode2html($Text);
// Avoid triple linefeeds through oembed
$Text = str_replace("
", "
", $Text);
// If we found an event earlier, strip out all the event code and replace with a reformatted version.
// Replace the event-start section with the entire formatted event. The other bbcode is stripped.
// Summary (e.g. title) is required, earlier revisions only required description (in addition to
// start which is always required). Allow desc with a missing summary for compatibility.
if ((x($ev,'desc') || x($ev,'summary')) && x($ev,'dtstart')) {
$sub = format_event_html($ev);
$sub = str_replace('$',"\0",$sub);
$Text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism",$sub,$Text);
$Text = preg_replace("/\[event\](.*?)\[\/event\]/ism",'',$Text);
$Text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism",'',$Text);
$Text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism",'',$Text);
$Text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism",'',$Text);
$Text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism",'',$Text);
$Text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism",'',$Text);
$Text = preg_replace("/\[event\-timezone\](.*?)\[\/event\-timezone\]/ism",'',$Text);
$Text = preg_replace("/\[event\-adjust\](.*?)\[\/event\-adjust\]/ism",'',$Text);
$Text = str_replace("\0",'$',$Text);
}
// Unhide all [noparse] contained bbtags unspacefying them
// and triming the [noparse] tag.
if (strpos($Text,'[noparse]') !== false) {
$Text = preg_replace_callback("/\[noparse\](.*?)\[\/noparse\]/ism", 'bb_unspacefy_and_trim', $Text);
}
if (strpos($Text,'[nobb]') !== false) {
$Text = preg_replace_callback("/\[nobb\](.*?)\[\/nobb\]/ism", 'bb_unspacefy_and_trim', $Text);
}
if (strpos($Text,'[pre]') !== false) {
$Text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", 'bb_unspacefy_and_trim', $Text);
}
// replace escaped links in code= blocks
$Text = str_replace('%eY9-!','http', $Text);
$Text = bb_code_unprotect($Text);
$Text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $Text);
// fix any escaped ampersands that may have been converted into links
if(strpos($Text,'&') !== false)
$Text = preg_replace("/\<(.*?)(src|href)=(.*?)\&\;(.*?)\>/ism", '<$1$2=$3&$4>', $Text);
// This is subtle - it's an XSS filter. It only accepts links with a protocol scheme and where
// the scheme begins with z (zhttp), h (http(s)), f (ftp(s)), m (mailto), t (tel) and named anchors.
// data: urls are allowed if exporting to activitypub which allows inline svg to federate, but not
// to be used for local display
if ($activitypub) {
$Text = preg_replace("/\<(.*?)(src|href)=\"[^dzhfmt#](.*?)\>/ism", '<$1$2="">', $Text);
}
else {
$Text = preg_replace("/\<(.*?)(src|href)=\"[^zhfmt#](.*?)\>/ism", '<$1$2="">', $Text);
}
$Text = bb_replace_images($Text, $saved_images);
$args = [ 'text' => $Text, 'options' => $options ];
call_hooks('bbcode', $args);
return $args['text'];
}