. * */ namespace Friendica\Content\Text; use Friendica\Core\System; use Friendica\DI; use Friendica\Model\Contact; /** * Friendica-specific usage of Markdown */ class Markdown { /** * Converts a Markdown string into HTML. The hardwrap parameter maximizes * compatibility with Diaspora in spite of the Markdown standard. * * @param string $text * @param bool $hardwrap * @return string * @throws \Exception */ public static function convert($text, $hardwrap = true) { $stamp1 = microtime(true); $MarkdownParser = new MarkdownParser(); $MarkdownParser->code_class_prefix = 'language-'; $MarkdownParser->hard_wrap = $hardwrap; $MarkdownParser->hashtag_protection = true; $MarkdownParser->url_filter_func = function ($url) { if (strpos($url, '#') === 0) { $url = ltrim($_SERVER['REQUEST_URI'], '/') . $url; } return $url; }; $text = self::convertDiasporaMentionsToHtml($text); $html = $MarkdownParser->transform($text); DI::profiler()->saveTimestamp($stamp1, "parser", System::callstack()); return $html; } /** * Replace Diaspora-style mentions in a text since they trip the Markdown parser autolinker. * * @param string $text * @return string */ private static function convertDiasporaMentionsToHtml(string $text) { return preg_replace_callback( '/([@!]){(?:([^}]+?); ?)?([^} ]+)}/', /* * Matching values for the callback * [1] = mention type (@ or !) * [2] = name (optional) * [3] = profile URL */ function ($matches) { if ($matches[3] == '') { return ''; } $data = Contact::getDetailsByAddr($matches[3]); if (empty($data)) { return ''; } $name = $matches[2]; if ($name == '') { $name = $data['name']; } return $matches[1] . '' . $name . ''; }, $text ); } /* * we don't want to support a bbcode specific markdown interpreter * and the markdown library we have is pretty good, but provides HTML output. * So we'll use that to convert to HTML, then convert the HTML back to bbcode, * and then clean up a few Diaspora specific constructs. */ public static function toBBCode($s) { $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8'); // The parser cannot handle paragraphs correctly $s = str_replace(['
', '', '
'], ['
', '
', '
'], $s);
// Escaping hashtags that could be titles
$s = preg_replace('/^\#([^\s\#])/im', '\#$1', $s);
$s = self::convert($s);
$s = HTML::toBBCode($s);
// protect the recycle symbol from turning into a tag, but without unescaping angles and naked ampersands
$s = str_replace('♲', html_entity_decode('♲', ENT_QUOTES, 'UTF-8'), $s);
// Convert everything that looks like a link to a link
$s = preg_replace('/([^\]=]|^)(https?\:\/\/)([a-zA-Z0-9:\/\-?&;.=_~#%$!+,@]+(?