array('open' => $start_open, 'close' => $start_close),
'end' => array('open' => $end_open, 'close' => $end_open + strlen('[/' . $name . ']')) );
if ($start_equal !== false) {
$res['start']['equal'] = $start_equal + 1;
}
return $res;
}
function bb_tag_preg_replace($pattern, $replace, $name, $s)
{
$string = $s;
$occurance = 1;
$pos = get_bb_tag_pos($string, $name, $occurance);
while ($pos !== false && $occurance < 1000) {
$start = substr($string, 0, $pos['start']['open']);
$subject = substr($string, $pos['start']['open'], $pos['end']['close'] - $pos['start']['open']);
$end = substr($string, $pos['end']['close']);
if ($end === false) {
$end = '';
}
$subject = preg_replace($pattern, $replace, $subject);
$string = $start . $subject . $end;
$occurance++;
$pos = get_bb_tag_pos($string, $name, $occurance);
}
return $string;
}
function tryoembed($match)
{
$url = ((count($match) == 2) ? $match[1] : $match[2]);
$o = oembed_fetch_url($url);
if ($o['type'] == 'error') {
return $match[0];
}
$html = oembed_format_object($o);
return $html;
}
function nakedoembed($match)
{
$url = ((count($match) == 2) ? $match[1] : $match[2]);
$strip_url = strip_escaped_zids($url);
// this function no longer performs oembed on naked links
// because they author may have created naked links intentionally.
// Now it just strips zids on naked links.
return str_replace($url, $strip_url, $match[0]);
}
function tryzrlaudio($match)
{
$link = $match[1];
$zrl = is_matrix_url($link);
if ($zrl) {
$link = zid($link);
}
return '';
}
function tryzrlvideo($match)
{
$link = $match[1];
$zrl = is_matrix_url($link);
if ($zrl) {
$link = zid($link);
}
$static_link = get_config('system', 'video_default_poster', 'images/video_poster.jpg');
if ($static_link) {
$poster = 'poster="' . escape_tags($static_link) . '" ' ;
}
return '';
}
function videowithopts($match)
{
$link = $match[2];
$zrl = is_matrix_url($link);
if ($zrl) {
$link = zid($link);
}
$attributes = $match[1];
$poster = "";
preg_match("/poster='(.*?)'/ism", $attributes, $matches);
if (isset($matches[1]) && $matches[1] != "") {
$poster = 'poster="' . (($zrl) ? zid($matches[1]) : $matches[1]) . '"';
}
preg_match("/poster=\"\;(.*?)\"\;/ism", $attributes, $matches);
if (isset($matches[1]) && $matches[1] != "") {
$poster = 'poster="' . (($zrl) ? zid($matches[1]) : $matches[1]) . '"';
}
preg_match("/poster=\\\"(.*?)\\\"/ism", $attributes, $matches);
if (isset($matches[1]) && $matches[1] != "") {
$poster = 'poster="' . (($zrl) ? zid($matches[1]) : $matches[1]) . '"';
}
return '';
}
// [noparse][i]italic[/i][/noparse] turns into
// [noparse][ i ]italic[ /i ][/noparse],
// to hide them from parser.
function bb_spacefy($st)
{
$whole_match = $st[0];
$captured = $st[1];
$spacefied = preg_replace("/\[(.*?)\]/", "[ $1 ]", $captured);
$new_str = str_replace($captured, $spacefied, $whole_match);
return $new_str;
}
// The previously spacefied [noparse][ i ]italic[ /i ][/noparse],
// now turns back and the [noparse] tags are trimmed
// returning [i]italic[/i]
function bb_unspacefy_and_trim($st)
{
//$whole_match = $st[0];
$captured = $st[1];
$unspacefied = preg_replace("/\[ (.*?)\ ]/", "[$1]", $captured);
return $unspacefied;
}
function bb_extract_images($body)
{
$saved_image = [];
$orig_body = $body;
$new_body = '';
$cnt = 0;
$img_start = strpos($orig_body, '[img');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
$img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
while (($img_st_close !== false) && ($img_end !== false)) {
$img_st_close++; // make it point to AFTER the closing bracket
$img_end += $img_start;
if (! strcmp(substr($orig_body, $img_start + $img_st_close, 5), 'data:')) {
// This is an embedded image
$saved_image[$cnt] = substr($orig_body, $img_start + $img_st_close, $img_end - ($img_start + $img_st_close));
$new_body = $new_body . substr($orig_body, 0, $img_start) . '[$#saved_image' . $cnt . '#$]';
$cnt++;
} else {
$new_body = $new_body . substr($orig_body, 0, $img_end + strlen('[/img]'));
}
$orig_body = substr($orig_body, $img_end + strlen('[/img]'));
if ($orig_body === false) { // in case the body ends on a closing image tag
$orig_body = '';
}
$img_start = strpos($orig_body, '[img');
$img_st_close = ($img_start !== false ? strpos(substr($orig_body, $img_start), ']') : false);
$img_end = ($img_start !== false ? strpos(substr($orig_body, $img_start), '[/img]') : false);
}
$new_body = $new_body . $orig_body;
return array('body' => $new_body, 'images' => $saved_image);
}
function bb_replace_images($body, $images)
{
$newbody = $body;
$cnt = 0;
if (! $images) {
return $newbody;
}
foreach ($images as $image) {
// We're depending on the property of 'foreach' (specified on the PHP website) that
// it loops over the array starting from the first element and going sequentially
// to the last element
$newbody = str_replace('[$#saved_image' . $cnt . '#$]', '', $newbody);
$cnt++;
}
// logger('replace_images: ' . $newbody);
return $newbody;
}
/**
* @brief Parses crypt BBCode.
*
* @param array $match
* @return string HTML code
*/
function bb_parse_crypt($match)
{
$matches = [];
$attributes = $match[1];
$algorithm = "";
preg_match("/alg='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$algorithm = $matches[1];
}
preg_match("/alg=\"\;(.*?)\"\;/ism", $attributes, $matches);
if ($matches[1] != "") {
$algorithm = $matches[1];
}
preg_match("/alg=\\\"(.*?)\\\"/ism", $attributes, $matches);
if ($matches[1] != "") {
$algorithm = $matches[1];
}
$hint = "";
$matches = [];
preg_match("/hint='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "") {
$hint = $matches[1];
}
preg_match("/hint=\"\;(.*?)\"\;/ism", $attributes, $matches);
if ($matches[1] != "") {
$hint = $matches[1];
}
preg_match("/hint=\\\"(.*?)\\\"/ism", $attributes, $matches);
if ($matches[1] != "") {
$hint = $matches[1];
}
$x = random_string();
$f = 'hz_decrypt';
$onclick = 'onclick="' . $f . '(\'' . $algorithm . '\',\'' . $hint . '\',\'' . $match[2] . '\',\'#' . $x . '\');"';
$label = t('Encrypted content');
$Text = '
' . str_replace("\n", '
', wordwrap($r, 75, "\n", true)) . '
';
return $r;
}
function bb_parse_app($match)
{
$app = Apps::app_decode($match[1]);
if ($app) {
return Apps::app_render($app);
}
}
function bb_parse_app_ap($match)
{
$app = Apps::app_decode($match[1]);
if ($app) {
return sprintf(t('(Embedded app \'%s\' could not be displayed).'), $app['name']);
}
}
function bb_svg($match)
{
$params = str_replace(['' . bb_code_protect(trim($match[1])) . '
';
} else {
return '' . bb_code_protect(trim($match[1])) . '
';
}
}
function bb_code_options($match)
{
if (strpos($match[0], "' . bb_code_protect(trim($match[2])) . '
';
} else {
return '' . bb_code_protect(trim($match[2])) . '
';
}
}
function md_protect($match)
{
return bb_code_protect($match[1]);
}
function html_protect($match)
{
return str_replace(['<','>'], ['<','>'], $match[1]);
}
function md_header($content)
{
$headingLevel = strlen($content[1]);
$header = trim($content[2]);
// Build anchor without space, numbers.
$anchor = preg_replace('#[^a-z?!]#', '', strtolower($header));
return sprintf('%s
', $class, bb_code_protect($content));
}
function md_italic($content)
{
return '' . $content[1] . $content[3] . '';
}
function md_bold($content)
{
return '' . $content[1] . $content[3] . '';
}
function md_bolditalic($content)
{
return '' . $content[1] . $content[3] . '';
}
function md_image($content)
{
$url = filter_var($content[1], FILTER_SANITIZE_URL);
$alt = '';
if (isset($content[2])) {
$content[2] = str_replace('"', '', $content[2]);
$alt = ' alt="' . filter_var($content[2], FILTER_SANITIZE_STRING) . '"';
}
return sprintf('', $url, $alt);
}
function md_topheader($matches)
{
// Terrible hack to check we haven't found an empty list item.
if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) {
return $matches[0];
}
$level = $matches[2][0] == '=' ? 1 : 2;
return "$1'; // Check for [quote] text // handle nested quotes $endlessloop = 0; while ((strpos($Text, "[/quote]") !== false) && (strpos($Text, "[quote]") !== false) && (++$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) && (strpos($Text, "[quote=") !== false) && (++$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_callback("/\[crypt (.*?)\](.*?)\[\/crypt\]/ism", 'bb_parse_b64_crypt', $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 (.*?)\](.*?)\[\/video\]/ism", 'videowithopts', $Text); $Text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", 'tryzrlvideo', $Text); } if (strpos($Text, '[/audio]') !== false) { $Text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", 'tryzrlaudio', $Text); } if (strpos($Text, '[/zvideo]') !== false) { $Text = preg_replace_callback("/\[zvideo (.*?)\](.*?)\[\/zvideo\]/ism", 'videowithopts', $Text); $Text = preg_replace_callback("/\[zvideo\](.*?)\[\/zvideo\]/ism", 'tryzrlvideo', $Text); } if (strpos($Text, '[/zaudio]') !== false) { $Text = preg_replace_callback("/\[zaudio\](.*?)\[\/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("