%s'); //// Functions for processing marked-up text (Stud.IP markup, HTML, JS). use Studip\Markup; function htmlReady($what, $trim=TRUE, $br=FALSE, $double_encode=true) { return Markup::htmlReady($what, $trim, $br, $double_encode); } /** * Prepare text for wysiwyg (if enabled), otherwise convert special * characters using htmlReady. * * @param string $text The text. * @param boolean $trim Trim text before applying markup rules, if TRUE. * @param boolean $br Replace newlines by
, if TRUE and wysiwyg editor disabled. * @param boolean $double_encode Encode existing HTML entities, if TRUE and wysiwyg editor disabled. * @return string The converted string. */ function wysiwygReady($what, $trim=TRUE, $br=FALSE, $double_encode=true) { return Markup::wysiwygReady($what, $trim, $br, $double_encode); } function jsReady ($what, $target = 'script-single') { switch ($target) { case "script-single" : return addcslashes($what, "\\'\n\r"); break; case "script-double" : return addcslashes($what, "\\\"\n\r"); break; case "inline-single" : return htmlReady(addcslashes($what, "\\'\n\r"), false, false, true); break; case "inline-double" : return htmlReady(addcslashes($what, "\\\"\n\r"), false, false, true); break; } return addslashes($what); } /** * Quote a piece of text, optionally include the author's name. * * @param string $text Text that is to be quoted. * @param string $author Name of the text's author (optional). * * @return string The quoted text. */ function quotes_encode($text, $author = '') { // If quoting is changed update these functions: // - StudipFormat::markupQuote // lib/classes/StudipFormat.php // - quotes_encode lib/visual.inc.php // - STUDIP.Forum.citeEntry > quote // public/plugins_packages/core/Forum/javascript/forum.js // - studipQuotePlugin > insertStudipQuote // public/assets/javascripts/ckeditor/plugins/studip-quote/plugin.js $text = Markup::markupToHtml($text); if ($author) { $title = sprintf(_('%s hat geschrieben:'), htmlReady($author)); $text = '
' . $title . '
' . $text; } $text = sprintf('
%s

 

', $text); return Markup::markAsHtml($text); } /** * Common function to get all special Stud.IP formattings. * * @access public * @param string $text Marked-up text. * @param boolean $trim Trim leading and trailing whitespace, if TRUE. * @return string HTML code computed by applying markup-rules. */ function formatReady($text, $trim = true) { $formatted = Markup::apply(new StudipFormat(), $text, $trim); return $formatted !== '' ? sprintf(FORMATTED_CONTENT_WRAPPER, $formatted) : ''; } /** * Simplified version of formatReady that handles link formatting only. * * @param string $text Marked-up text. * @param bool $nl2br Convert newlines to
. * @return string Marked-up text with markup-links converted to * HTML-links. */ function formatLinks($text, $nl2br = true) { $link_markup_rule = StudipCoreFormat::getStudipMarkup('links'); $email_markup_rule = StudipCoreFormat::getStudipMarkup('emails'); $markup = new TextFormat(); $markup->addMarkup( 'links', $link_markup_rule['start'], $link_markup_rule['end'] ?? '', $link_markup_rule['callback'] ); $markup->addMarkup( 'emails', $email_markup_rule['start'], $email_markup_rule['end'] ?? '', $email_markup_rule['callback'] ); return $markup->format(htmlReady($text, true, $nl2br)); } /** * Special version of formatReady for wiki-webs. * * @access public * @param string $what Marked-up text. * @param string $trim Trim leading and trailing whitespace, if TRUE. * @param string $range_id the id of the course or institute * @param string $page_id the id of the page * @return string HTML code computed by applying markup-rules. */ function wikiReady($text, $trim=TRUE, $range_id = null, $page_id = null) { $formatted = Markup::apply(new WikiFormat($range_id, $page_id), $text, $trim); return $formatted !== '' ? sprintf(FORMATTED_CONTENT_WRAPPER, $formatted) : ''; } /** * Special version of formatReady for blubber, which includes hashtags * * @access public * @param string $what Marked-up text. * @param string $trim Trim leading and trailing whitespace, if TRUE. * @return string HTML code computed by applying markup-rules. */ function blubberReady($text, $trim=TRUE) { $formatted = Markup::apply(new BlubberFormat(), $text, $trim); return $formatted !== '' ? sprintf(FORMATTED_CONTENT_WRAPPER, $formatted) : ''; } //////////////////////////////////////////////////////////////////////////////// /** * decodes html entities to normal characters * * @access public * @param string * @return string */ function decodeHTML ($string) { return html_entity_decode($string, ENT_QUOTES); } /** * formats a ~~~~ wiki signature with username and timestamp * @param string * @param unix timestamp */ function preg_call_format_signature($username, $timestamp) { $fullname = get_fullname_from_uname($username); $date = strftime('%x, %X', $timestamp); return '-- '.htmlReady($fullname).' '.htmlReady($date).''; } /** * removes all characters used by quick-format-syntax * * @access public * @param string * @return string */ function kill_format ($text) { if (Markup::isHtml($text)) { $is_fallback = Markup::isHtmlFallback($text); $text = Markup::removeHtml($text); if (!$is_fallback) { // pure HTML - no Stud.IP markup to remove return $text; } } // remove Stud.IP markup $text = preg_replace("'\n?\r\n?'", "\n", $text); // wir wandeln [code] einfach in [pre][nop] um und sind ein Problem los ... :-) $text = preg_replace_callback("|(\[/?code\])|isU", function ($a) { return $a[0] === '[code]' ? '[pre][nop]' : '[/nop][/pre]'; }, $text); $pattern = [ "'(^|\n)\!{1,4}(.+)$'m", // Ueberschriften "'(\n|\A)(-|=)+ (.+)$'m", // Aufzaehlungslisten "'%%(\S|\S.*?\S)%%'s", // ML-kursiv "'\*\*(\S|\S.*?\S)\*\*'s", // ML-fett "'__(\S|\S.*?\S)__'s", // ML-unterstrichen "'##(\S|\S.*?\S)##'s", // ML-diktengleich "'\+\+(((\+\+)*)(\S|\S.*?\S)?\\2)\+\+'s", // ML-groesser "'--(((--)*)(\S|\S.*?\S)?\\2)--'s", // ML-kleiner "'>>(\S|\S.*?\S)>>'is", // ML-hochgestellt "'<<(\S|\S.*?\S)<<'is", // ML-tiefgestellt "'{-(.+?)-}'is" , // durchgestrichen "'\n\n (((\n\n) )*(.+?))(\Z|\n\n(?! ))'s", // Absatz eingerueckt "'(?<=\n|^)--+(\d?)(\n|$|(?=<))'m", // Trennlinie "'\[pre\](.+?)\[/pre\]'is" , // praeformatierter Text "'\[nop\].+\[/nop\]'isU", //"'\[.+?\](((http\://|https\://|ftp\://)?([^/\s]+)(.[^/\s]+){2,})|([-a-z0-9_]+(\.[_a-z0-9-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)+)))'i", "'\[(.+?)\](((http\://|https\://|ftp\://)?([^/\s]+)(\.[^/\s]+){2,}(/[^\s]*)?)|([-a-z0-9_]+(\.[_a-z0-9-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)+)))'i", // "'\[quote=.+?quote\]'is", // quoting ]; $replace = [ "\\1\\2", "\\1\\3", "\\1", "\\1", "\\1", "\\1", "\\1", "\\1", "\\1", "\\1", "\\1", "\n\\1\n", "", "\\1",'[nop] [/nop]', //"\\2", '$1 ($2)', //"", '$1$2']; $callback = function ($c) { return function ($m) use ($c) { return $m[1] . mb_substr(str_replace($c, ' ', $m[2]), 0, -1); }; }; $pattern_callback = [ "'(^|\s)%(?!%)(\S+%)+'" => $callback('%'), // SL-kursiv "'(^|\s)\*(?!\*)(\S+\*)+'" => $callback('*') , // SL-fett "'(^|\s)_(?!_)(\S+_)+'" => $callback('_'), // SL-unterstrichen "'(^|\s)#(?!#)(\S+#)+'" => $callback('#'), // SL-diktengleich "'(^|\s)\+(?!\+)(\S+\+)+'" => $callback('+'), // SL-groesser "'(^|\s)-(?!-)(\S+-)+'" => $callback('-'), // SL-kleiner "'(^|\s)>(?!>)(\S+>)+'" => $callback('>'), // SL-hochgestellt "'(^|\s)<(?!<)(\S+<)+'" => $callback('<'), // SL-tiefgestellt); ]; if (preg_match_all("'\[nop\](.+)\[/nop\]'isU", $text, $matches)) { $text = preg_replace($pattern, $replace, $text); $text = preg_replace_callback_array($pattern_callback, $text); $text = explode("[nop] [/nop]", $text); $i = 0; $all = ''; foreach ($text as $w) { $all .= $w . ($matches[1][$i++] ?? ''); } return $all; } $text = preg_replace($pattern, $replace, $text); $text = preg_replace_callback_array($pattern_callback, $text); return $text; } function isURL($url) { return filter_var($url, FILTER_VALIDATE_URL) !== false; } function isLinkIntern($url) { $pum = @parse_url(TransformInternalLinks($url)); if (!$pum) { return false; } // If given $url is pointing to an anchor, it should be internal if (count($pum) === 1 && isset($pum['fragment'])) { return true; } return in_array($pum['scheme'] ?? null, ['https', 'http', null], true) && in_array($pum['host'] ?? null, [$_SERVER['SERVER_NAME'] ?? null, null], true) && in_array($pum['port'] ?? null, [$_SERVER['SERVER_PORT'] ?? null, null], true) && mb_strpos($pum['path'] ?? '', $GLOBALS['CANONICAL_RELATIVE_PATH_STUDIP']) === 0; } /** * convert links with 'umlauten' to punycode * * @param string $link link to convert * @return string link in punycode * * @throws \Algo26\IdnaConvert\Exception\AlreadyPunycodeException * @throws \Algo26\IdnaConvert\Exception\InvalidCharacterException */ function idna_link(string $link) { if (!Config::get()->CONVERT_IDNA_URL) { return $link; } $pu = parse_url($link); if ( isset($pu['host']) && preg_match('/&\w+;/i', $pu['host']) //umlaute? (html-coded) && preg_match('#^([^/]*)//([^/?]*)([/?].*)?$#i',$link, $matches) ) { $IDN = new Algo26\IdnaConvert\ToIdn(); $out = $IDN->convert(decodeHTML($matches[2])); // false by error if ($out) { return $matches[1] . '//' . htmlReady($out) . ($matches[3] ?? ''); } } return $link; } /** * create symbols from the shorts * * This functions converts the short, locatet in the config.inc * into the assigned pictures. A tooltip which shows the symbol * code is given, too. * * @access public * * @param string the text to convert * * @return string convertet text */ function symbol ($text = '') { if (!$text) { return $text; } $patterns = []; $replaces = []; //symbols in short notation foreach ($GLOBALS['SYMBOL_SHORT'] as $key => $value) { $patterns[] = "'" . preg_quote($key) . "'m"; $replaces[] = $value; } return preg_replace($patterns, $replaces, $text); } //Beschneidungsfunktion fuer alle printhead Ausgaben function mila ($titel, $size = 60) { global $auth; if (!empty($auth->auth['jscript']) && $size == 60) { //hier wird die maximale Laenge berechnet, nach der Abgeschnitten wird (JS dynamisch) if (mb_strlen($titel) > $auth->auth['xres'] / 13) { $titel = mb_substr($titel, 0, $auth->auth['xres'] / 13) . '... '; } } elseif (mb_strlen ($titel) >$size) { $titel = mb_substr($titel, 0, $size) . '... '; } return $titel; } /** * Returns a given text as html tooltip * * title and alt attribute is default, with_popup means a JS alert box * activated on click * * @param string $text * @param boolean $with_alt return text with alt attribute * @param boolean $with_popup return text with JS alert box on click * @return string */ function tooltip ($text, $with_alt = TRUE, $with_popup = FALSE) { return arrayToHtmlAttributes(tooltip2($text, $with_alt, $with_popup)); } /** * Returns a given text as an array of html attributes used as tooltip * * title and alt attribute is default, with_popup means a JS alert box * activated on click * * @param string $text * @param boolean $with_alt return text with alt attribute * @param boolean $with_popup return text with JS alert box on click * @return string */ function tooltip2($text, $with_alt = TRUE, $with_popup = FALSE) { $ret = []; if ($with_popup) { $ret['onClick'] = "alert('".JSReady($text, "alert")."');"; } $text = preg_replace("/(\n\r|\r\n|\n|\r)/", " ", $text); $text = htmlReady($text); if ($with_alt) { $ret['alt'] = $text; } $ret['title'] = $text; $ret['tabindex'] = '0'; return $ret; } /** * returns a html-snippet with an icon and a tooltip on it * * @param string|null $text tooltip text, html gets encoded * @param bool $important render icon in "important" style * @param bool $html tooltip text is HTML content * @param bool $alt_info * @return string */ function tooltipIcon(?string $text, bool $important = false, bool $html = false, bool $alt_info= false): string { if (!trim($text)) { return ''; } // render tooltip $template = $GLOBALS['template_factory']->open('shared/tooltip'); return $template->render(compact('text', 'important', 'html', 'alt_info')); } /** * returns a html-snippet with an icon and a tooltip on it * * @param string|null $text tooltip text, html is rendered as is * @param bool $important render icon in "important" style * @return string */ function tooltipHtmlIcon(?string $text, bool $important = false) { return tooltipIcon($text, $important, true); } /** * detects internal links in a given string and convert used domain to the domain * actually used (only necessary if more than one domain exists), relative URLs are * converted to absolute URLs * * @param string $str URL/Link to convert * @return string converted URL/Link */ function TransformInternalLinks($str){ $str = trim($str); if (!$str) { return ''; } if (mb_strpos($str, 'http') !== 0) { if ($str[0] === '#' || preg_match('/^[a-z][a-z0-9+.-]*:/i', $str)) { return $str; } if ($str[0] === '/') { $str = mb_substr($str, mb_strlen($GLOBALS['CANONICAL_RELATIVE_PATH_STUDIP'])); } $str = $GLOBALS['ABSOLUTE_URI_STUDIP'] . $str; } if (!empty($GLOBALS['STUDIP_DOMAINS']) && count($GLOBALS['STUDIP_DOMAINS']) > 1) { if (!isset($GLOBALS['TransformInternalLinks_domainData'])){ $domain_data['domains'] = ''; foreach ($GLOBALS['STUDIP_DOMAINS'] as $studip_domain) $domain_data['domains'] .= '|' . preg_quote($studip_domain); $domain_data['domains'] = preg_replace("'\|[^/|]*'", '$0[^/]*?', $domain_data['domains']); $domain_data['domains'] = mb_substr($domain_data['domains'], 1); $domain_data['user_domain'] = preg_replace("'^({$domain_data['domains']})(.*)$'i", "\\1", $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); $domain_data['user_domain_scheme'] = 'http' . ((!empty($_SERVER['HTTPS']) || $_SERVER['SERVER_PORT'] == 443) ? 's' : '') . '://'; $GLOBALS['TransformInternalLinks_domainData'] = $domain_data; } $domain_data = $GLOBALS['TransformInternalLinks_domainData']; return preg_replace("'https?\://({$domain_data['domains']})((/[^<\s]*[^\.\s<])*)'i", "{$domain_data['user_domain_scheme']}{$domain_data['user_domain']}\\2", $str); } else { return $str; } } /** * Displays the provided exception in a more readable fashion. * * @param Throwable $exception The exception to be displayed * @param bool $as_html Indicates whether the exception shall be displayed as * plain text or html (optional, defaults to plain text) * @param bool $deep Indicates whether any previous exception should be * included in the output (optional, defaults to false) * @return String The exception display either as plain text or html */ function display_exception(Throwable $exception, bool $as_html = false, bool $deep = false): string { return ExceptionDisplay::from($exception)->display($as_html, $deep); } /** * Converts an array of attributes to an html attribute string. * * @param array $attributes Associative array of attributes * @return string * @since Stud.IP 4.1 * @todo Nested attribute definitions? */ function arrayToHtmlAttributes(array $attributes) { return (string) HTMLAttributes::from($attributes); }