diff --git a/doc/Addons.md b/doc/Addons.md index dadf76abd7..de0d9e4963 100644 --- a/doc/Addons.md +++ b/doc/Addons.md @@ -372,7 +372,7 @@ include/cronhooks.php: Addon::callHooks('cron', $d); include/security.php: Addon::callHooks('logged_in', $a->user); -include/html2bbcode.php: Addon::callHooks('html2bbcode', $text); +src/Content/Text/HTML.php: Addon::callHooks('html2bbcode', $text); include/Contact.php: Addon::callHooks('remove_user',$r[0]); diff --git a/doc/de/Addons.md b/doc/de/Addons.md index f4c14bc613..5bbfde2794 100644 --- a/doc/de/Addons.md +++ b/doc/de/Addons.md @@ -265,7 +265,7 @@ include/cronhooks.php: Addon::callHooks('cron', $d); include/security.php: Addon::callHooks('logged_in', $a->user); -include/html2bbcode.php: Addon::callHooks('html2bbcode', $text); +src/Content/Text/HTML.php: Addon::callHooks('html2bbcode', $text); include/Contact.php: Addon::callHooks('remove_user',$r[0]); diff --git a/include/api.php b/include/api.php index 60a9acce0d..eec713c537 100644 --- a/include/api.php +++ b/include/api.php @@ -10,6 +10,7 @@ use Friendica\App; use Friendica\Content\ContactSelector; use Friendica\Content\Feature; use Friendica\Content\Text\BBCode; +use Friendica\Content\Text\HTML; use Friendica\Core\Addon; use Friendica\Core\Config; use Friendica\Core\L10n; @@ -41,11 +42,9 @@ use Friendica\Util\Network; use Friendica\Util\XML; require_once 'include/conversation.php'; -require_once 'include/html2plain.php'; require_once 'mod/share.php'; require_once 'mod/item.php'; require_once 'include/security.php'; -require_once 'include/html2bbcode.php'; require_once 'mod/wall_upload.php'; require_once 'mod/proxy.php'; @@ -1096,7 +1095,7 @@ function api_statuses_mediap($type) $purifier = new HTMLPurifier($config); $txt = $purifier->purify($txt); } - $txt = html2bbcode($txt); + $txt = HTML::toBBCode($txt); $a->argv[1]=$user_info['screen_name']; //should be set to username? @@ -1147,7 +1146,7 @@ function api_statuses_update($type) $purifier = new HTMLPurifier($config); $txt = $purifier->purify($txt); - $_REQUEST['body'] = html2bbcode($txt); + $_REQUEST['body'] = HTML::toBBCode($txt); } } else { $_REQUEST['body'] = requestdata('status'); @@ -2624,10 +2623,10 @@ function api_format_messages($item, $recipient, $sender) if ($_GET['getText'] == 'html') { $ret['text'] = BBCode::convert($item['body'], false); } elseif ($_GET['getText'] == 'plain') { - $ret['text'] = trim(html2plain(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0)); + $ret['text'] = trim(HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0)); } } else { - $ret['text'] = $item['title'] . "\n" . html2plain(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0); + $ret['text'] = $item['title'] . "\n" . HTML::toPlaintext(BBCode::convert(api_clean_plain_items($item['body']), false, 2, true), 0); } if (x($_GET, 'getUserObjects') && $_GET['getUserObjects'] == 'false') { unset($ret['sender']); @@ -2650,7 +2649,7 @@ function api_convert_item($item) // Workaround for ostatus messages where the title is identically to the body $html = BBCode::convert(api_clean_plain_items($body), false, 2, true); - $statusbody = trim(html2plain($html, 0)); + $statusbody = trim(HTML::toPlaintext($html, 0)); // handle data: images $statusbody = api_format_items_embeded_images($item, $statusbody); diff --git a/include/enotify.php b/include/enotify.php index c877540aba..1e2008392d 100644 --- a/include/enotify.php +++ b/include/enotify.php @@ -12,8 +12,6 @@ use Friendica\Database\DBM; use Friendica\Util\DateTimeFormat; use Friendica\Util\Emailer; -require_once 'include/html2bbcode.php'; - /** * @brief Creates a notification entry and possibly sends a mail * diff --git a/include/html2bbcode.php b/include/html2bbcode.php deleted file mode 100644 index a5967d2cb3..0000000000 --- a/include/html2bbcode.php +++ /dev/null @@ -1,403 +0,0 @@ -query("//".$oldnode); - foreach ($list as $oldNode) { - $attr = []; - if ($oldNode->attributes->length) { - foreach ($oldNode->attributes as $attribute) { - $attr[$attribute->name] = $attribute->value; - } - } - - $replace = true; - - $startbb = $savestart; - - $i = 0; - - foreach ($attributes as $attribute => $value) { - $startbb = str_replace('\x01'.++$i, '$1', $startbb); - if (strpos('*'.$startbb, '$1') > 0) { - if ($replace && (@$attr[$attribute] != '')) { - $startbb = preg_replace($value, $startbb, $attr[$attribute], -1, $count); - - // If nothing could be changed - if ($count == 0) { - $replace = false; - } - } else { - $replace = false; - } - } else { - if (@$attr[$attribute] != $value) { - $replace = false; - } - } - } - - if ($replace) { - $StartCode = $oldNode->ownerDocument->createTextNode($startbb); - $EndCode = $oldNode->ownerDocument->createTextNode($endbb); - - $oldNode->parentNode->insertBefore($StartCode, $oldNode); - - if ($oldNode->hasChildNodes()) { - foreach ($oldNode->childNodes as $child) { - $newNode = $child->cloneNode(true); - $oldNode->parentNode->insertBefore($newNode, $oldNode); - } - } - - $oldNode->parentNode->insertBefore($EndCode, $oldNode); - $oldNode->parentNode->removeChild($oldNode); - } - } - return($replace); -} - -function html2bbcode($message, $basepath = '') -{ - - $message = str_replace("\r", "", $message); - - // Removing code blocks before the whitespace removal processing below - $codeblocks = []; - $message = preg_replace_callback( - '#
(.*)
#iUs', - function ($matches) use (&$codeblocks) { - $return = '[codeblock-' . count($codeblocks) . ']'; - - $prefix = '[code]'; - if ($matches[1] != '') { - $prefix = '[code=' . $matches[1] . ']'; - } - $codeblocks[] = $prefix . trim($matches[2]) . '[/code]'; - return $return; - }, - $message - ); - - $message = str_replace( - [ - "
  • ", - "

  • ", - ], - [ - "
  • ", - "
  • ", - ], - $message - ); - - // remove namespaces - $message = preg_replace('=<(\w+):(.+?)>=', '', $message); - $message = preg_replace('==', '', $message); - - $doc = new DOMDocument(); - $doc->preserveWhiteSpace = false; - - $message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8"); - - @$doc->loadHTML($message); - - XML::deleteNode($doc, 'style'); - XML::deleteNode($doc, 'head'); - XML::deleteNode($doc, 'title'); - XML::deleteNode($doc, 'meta'); - XML::deleteNode($doc, 'xml'); - XML::deleteNode($doc, 'removeme'); - - $xpath = new DomXPath($doc); - $list = $xpath->query("//pre"); - foreach ($list as $node) { - $node->nodeValue = str_replace("\n", "\r", $node->nodeValue); - } - - $message = $doc->saveHTML(); - $message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "
    ", " ", ""], $message); - $message = preg_replace('= [\s]*=i', " ", $message); - @$doc->loadHTML($message); - - node2bbcode($doc, 'html', [], "", ""); - node2bbcode($doc, 'body', [], "", ""); - - // Outlook-Quote - Variant 1 - node2bbcode($doc, 'p', ['class'=>'MsoNormal', 'style'=>'margin-left:35.4pt'], '[quote]', '[/quote]'); - - // Outlook-Quote - Variant 2 - node2bbcode($doc, 'div', ['style'=>'border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt'], '[quote]', '[/quote]'); - - // MyBB-Stuff - node2bbcode($doc, 'span', ['style'=>'text-decoration: underline;'], '[u]', '[/u]'); - node2bbcode($doc, 'span', ['style'=>'font-style: italic;'], '[i]', '[/i]'); - node2bbcode($doc, 'span', ['style'=>'font-weight: bold;'], '[b]', '[/b]'); - - /*node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[font=$1][size=$2][color=$3]', '[/color][/size][/font]'); - node2bbcode($doc, 'font', array('size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[size=$1][color=$2]', '[/color][/size]'); - node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(.+)/'), '[font=$1][size=$2]', '[/size][/font]'); - node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/', 'color'=>'/(.+)/'), '[font=$1][color=$3]', '[/color][/font]'); - node2bbcode($doc, 'font', array('face'=>'/([\w ]+)/'), '[font=$1]', '[/font]'); - node2bbcode($doc, 'font', array('size'=>'/(\d+)/'), '[size=$1]', '[/size]'); - node2bbcode($doc, 'font', array('color'=>'/(.+)/'), '[color=$1]', '[/color]'); - */ - // Untested - //node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*font-family:\s*(.+?)[,;].*color:\s*(.+?)[,;].*/'), '[size=$1][font=$2][color=$3]', '[/color][/font][/size]'); - //node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(\d+)[,;].*/'), '[size=$1]', '[/size]'); - //node2bbcode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*/'), '[size=$1]', '[/size]'); - - node2bbcode($doc, 'span', ['style'=>'/.*color:\s*(.+?)[,;].*/'], '[color="$1"]', '[/color]'); - - //node2bbcode($doc, 'span', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]'); - - //node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)pt.*/'), '[font=$1][size=$2]', '[/size][/font]'); - //node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)px.*/'), '[font=$1][size=$2]', '[/size][/font]'); - //node2bbcode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]'); - - // Importing the classes - interesting for importing of posts from third party networks that were exported from friendica - // Test - //node2bbcode($doc, 'span', array('class'=>'/([\w ]+)/'), '[class=$1]', '[/class]'); - node2bbcode($doc, 'span', ['class'=>'type-link'], '[class=type-link]', '[/class]'); - node2bbcode($doc, 'span', ['class'=>'type-video'], '[class=type-video]', '[/class]'); - - node2bbcode($doc, 'strong', [], '[b]', '[/b]'); - node2bbcode($doc, 'em', [], '[i]', '[/i]'); - node2bbcode($doc, 'b', [], '[b]', '[/b]'); - node2bbcode($doc, 'i', [], '[i]', '[/i]'); - node2bbcode($doc, 'u', [], '[u]', '[/u]'); - - node2bbcode($doc, 'big', [], "[size=large]", "[/size]"); - node2bbcode($doc, 'small', [], "[size=small]", "[/size]"); - - node2bbcode($doc, 'blockquote', [], '[quote]', '[/quote]'); - - node2bbcode($doc, 'br', [], "\n", ''); - - node2bbcode($doc, 'p', ['class'=>'MsoNormal'], "\n", ""); - node2bbcode($doc, 'div', ['class'=>'MsoNormal'], "\r", ""); - - node2bbcode($doc, 'span', [], "", ""); - - node2bbcode($doc, 'span', [], "", ""); - node2bbcode($doc, 'pre', [], "", ""); - - node2bbcode($doc, 'div', [], "\r", "\r"); - node2bbcode($doc, 'p', [], "\n", "\n"); - - node2bbcode($doc, 'ul', [], "[list]", "[/list]"); - node2bbcode($doc, 'ol', [], "[list=1]", "[/list]"); - node2bbcode($doc, 'li', [], "[*]", ""); - - node2bbcode($doc, 'hr', [], "[hr]", ""); - - node2bbcode($doc, 'table', [], "", ""); - node2bbcode($doc, 'tr', [], "\n", ""); - node2bbcode($doc, 'td', [], "\t", ""); - //node2bbcode($doc, 'table', array(), "[table]", "[/table]"); - //node2bbcode($doc, 'th', array(), "[th]", "[/th]"); - //node2bbcode($doc, 'tr', array(), "[tr]", "[/tr]"); - //node2bbcode($doc, 'td', array(), "[td]", "[/td]"); - - //node2bbcode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n"); - //node2bbcode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n"); - //node2bbcode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n"); - //node2bbcode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n"); - //node2bbcode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n"); - //node2bbcode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n"); - - node2bbcode($doc, 'h1', [], "\n\n[h1]", "[/h1]\n"); - node2bbcode($doc, 'h2', [], "\n\n[h2]", "[/h2]\n"); - node2bbcode($doc, 'h3', [], "\n\n[h3]", "[/h3]\n"); - node2bbcode($doc, 'h4', [], "\n\n[h4]", "[/h4]\n"); - node2bbcode($doc, 'h5', [], "\n\n[h5]", "[/h5]\n"); - node2bbcode($doc, 'h6', [], "\n\n[h6]", "[/h6]\n"); - - node2bbcode($doc, 'a', ['href'=>'/mailto:(.+)/'], '[mail=$1]', '[/mail]'); - node2bbcode($doc, 'a', ['href'=>'/(.+)/'], '[url=$1]', '[/url]'); - - node2bbcode($doc, 'img', ['src'=>'/(.+)/', 'width'=>'/(\d+)/', 'height'=>'/(\d+)/'], '[img=$2x$3]$1', '[/img]'); - node2bbcode($doc, 'img', ['src'=>'/(.+)/'], '[img]$1', '[/img]'); - - - node2bbcode($doc, 'video', ['src'=>'/(.+)/'], '[video]$1', '[/video]'); - node2bbcode($doc, 'audio', ['src'=>'/(.+)/'], '[audio]$1', '[/audio]'); - node2bbcode($doc, 'iframe', ['src'=>'/(.+)/'], '[iframe]$1', '[/iframe]'); - - node2bbcode($doc, 'key', [], '[code]', '[/code]'); - node2bbcode($doc, 'code', [], '[code]', '[/code]'); - - $message = $doc->saveHTML(); - - // I'm removing something really disturbing - // Don't know exactly what it is - $message = str_replace(chr(194).chr(160), ' ', $message); - - $message = str_replace(" ", " ", $message); - - // removing multiple DIVs - $message = preg_replace('=\r *\r=i', "\n", $message); - $message = str_replace("\r", "\n", $message); - - Addon::callHooks('html2bbcode', $message); - - $message = strip_tags($message); - - $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8'); - - $message = str_replace(["<"], ["<"], $message); - - // remove quotes if they don't make sense - $message = preg_replace('=\[/quote\][\s]*\[quote\]=i', "\n", $message); - - $message = preg_replace('=\[quote\]\s*=i', "[quote]", $message); - $message = preg_replace('=\s*\[/quote\]=i', "[/quote]", $message); - - do { - $oldmessage = $message; - $message = str_replace("\n \n", "\n\n", $message); - } while ($oldmessage != $message); - - do { - $oldmessage = $message; - $message = str_replace("\n\n\n", "\n\n", $message); - } while ($oldmessage != $message); - - do { - $oldmessage = $message; - $message = str_replace( - [ - "[/size]\n\n", - "\n[hr]", - "[hr]\n", - "\n[list", - "[/list]\n", - "\n[/", - "[list]\n", - "[list=1]\n", - "\n[*]"], - [ - "[/size]\n", - "[hr]", - "[hr]", - "[list", - "[/list]", - "[/", - "[list]", - "[list=1]", - "[*]"], - $message - ); - } while ($message != $oldmessage); - - $message = str_replace( - ['[b][b]', '[/b][/b]', '[i][i]', '[/i][/i]'], - ['[b]', '[/b]', '[i]', '[/i]'], - $message - ); - - // Handling Yahoo style of mails - $message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message); - - // Restore code blocks - $message = preg_replace_callback( - '#\[codeblock-([0-9]+)\]#iU', - function ($matches) use ($codeblocks) { - $return = ''; - if (isset($codeblocks[intval($matches[1])])) { - $return = $codeblocks[$matches[1]]; - } - return $return; - }, - $message - ); - - $message = trim($message); - - if ($basepath != '') { - $message = addHostname($message, $basepath); - } - - return $message; -} - -/** - * @brief Sub function to complete incomplete URL - * - * @param array $matches Result of preg_replace_callback - * @param string $basepath Basepath that is used to complete the URL - * - * @return string The expanded URL - */ -function addHostnameSub($matches, $basepath) -{ - $base = parse_url($basepath); - unset($base['query']); - unset($base['fragment']); - - $link = $matches[0]; - $url = $matches[1]; - - $parts = array_merge($base, parse_url($url)); - $url2 = Network::unparseURL($parts); - - return str_replace($url, $url2, $link); -} - -/** - * @brief Complete incomplete URLs in BBCode - * - * @param string $body Body with URLs - * @param string $basepath Basepath that is used to complete the URL - * - * @return string Body with expanded URLs - */ -function addHostname($body, $basepath) -{ - $URLSearchString = "^\[\]"; - - $matches = ["/\[url\=([$URLSearchString]*)\].*?\[\/url\]/ism", - "/\[url\]([$URLSearchString]*)\[\/url\]/ism", - "/\[img\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism", - "/\[img\](.*?)\[\/img\]/ism", - "/\[zmg\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism", - "/\[zmg\](.*?)\[\/zmg\]/ism", - "/\[video\](.*?)\[\/video\]/ism", - "/\[audio\](.*?)\[\/audio\]/ism", - ]; - - foreach ($matches as $match) { - $body = preg_replace_callback( - $match, - function ($match) use ($basepath) { - return addHostnameSub($match, $basepath); - }, - $body - ); - } - return $body; -} diff --git a/include/html2plain.php b/include/html2plain.php deleted file mode 100644 index 626f5e45ed..0000000000 --- a/include/html2plain.php +++ /dev/null @@ -1,246 +0,0 @@ - 0) && strlen($line) > $wraplen) { - $newline = trim(substr($line, 0, $pos)); - if ($level > 0) { - $newline = str_repeat(">", $level) . ' ' . $newline; - } - - $newlines[] = $newline . " "; - $line = substr($line, $pos + 1); - } - } while ((strlen($line) > $wraplen) && !($oldline == $line)); - - if ($level > 0) { - $line = str_repeat(">", $level) . ' ' . $line; - } - - $newlines[] = $line; - - return implode($newlines, "\n"); -} - -function quotelevel($message, $wraplength = 75) -{ - $lines = explode("\n", $message); - - $newlines = []; - $level = 0; - foreach ($lines as $line) { - $line = trim($line); - $startquote = false; - while (strpos("*" . $line, '[quote]') > 0) { - $level++; - $pos = strpos($line, '[quote]'); - $line = substr($line, 0, $pos) . substr($line, $pos + 7); - $startquote = true; - } - - $currlevel = $level; - - while (strpos("*" . $line, '[/quote]') > 0) { - $level--; - if ($level < 0) { - $level = 0; - } - - $pos = strpos($line, '[/quote]'); - $line = substr($line, 0, $pos) . substr($line, $pos + 8); - } - - if (!$startquote || ($line != '')) { - $newlines[] = breaklines($line, $currlevel, $wraplength); - } - } - - return implode($newlines, "\n"); -} - -function collecturls($message) -{ - $pattern = '/(.*?)<\/a>/is'; - preg_match_all($pattern, $message, $result, PREG_SET_ORDER); - - $urls = []; - foreach ($result as $treffer) { - $ignore = false; - - // A list of some links that should be ignored - $list = ["/user/", "/tag/", "/group/", "/profile/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/", - "//facebook.com/profile.php?id=", "//plus.google.com/", "//twitter.com/"]; - foreach ($list as $listitem) { - if (strpos($treffer[1], $listitem) !== false) { - $ignore = true; - } - } - - if ((strpos($treffer[1], "//twitter.com/") !== false) && (strpos($treffer[1], "/status/") !== false)) { - $ignore = false; - } - - if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/posts") !== false)) { - $ignore = false; - } - - if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/photos") !== false)) { - $ignore = false; - } - - if (!$ignore) { - $urls[$treffer[1]] = $treffer[1]; - } - } - - return $urls; -} - -function html2plain($html, $wraplength = 75, $compact = false) -{ - global $lang; - - $message = str_replace("\r", "", $html); - - $doc = new DOMDocument(); - $doc->preserveWhiteSpace = false; - - $message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8"); - - @$doc->loadHTML($message); - - $xpath = new DomXPath($doc); - $list = $xpath->query("//pre"); - foreach ($list as $node) { - $node->nodeValue = str_replace("\n", "\r", $node->nodeValue); - } - - $message = $doc->saveHTML(); - $message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "
    ", " ", ""], $message); - $message = preg_replace('= [\s]*=i', " ", $message); - - // Collecting all links - $urls = collecturls($message); - - @$doc->loadHTML($message); - - node2bbcode($doc, 'html', [], '', ''); - node2bbcode($doc, 'body', [], '', ''); - - // MyBB-Auszeichnungen - /* - node2bbcode($doc, 'span', array('style'=>'text-decoration: underline;'), '_', '_'); - node2bbcode($doc, 'span', array('style'=>'font-style: italic;'), '/', '/'); - node2bbcode($doc, 'span', array('style'=>'font-weight: bold;'), '*', '*'); - - node2bbcode($doc, 'strong', array(), '*', '*'); - node2bbcode($doc, 'b', array(), '*', '*'); - node2bbcode($doc, 'i', array(), '/', '/'); - node2bbcode($doc, 'u', array(), '_', '_'); - */ - - if ($compact) { - node2bbcode($doc, 'blockquote', [], "»", "«"); - } else { - node2bbcode($doc, 'blockquote', [], '[quote]', "[/quote]\n"); - } - - node2bbcode($doc, 'br', [], "\n", ''); - - node2bbcode($doc, 'span', [], "", ""); - node2bbcode($doc, 'pre', [], "", ""); - node2bbcode($doc, 'div', [], "\r", "\r"); - node2bbcode($doc, 'p', [], "\n", "\n"); - - //node2bbcode($doc, 'ul', array(), "\n[list]", "[/list]\n"); - //node2bbcode($doc, 'ol', array(), "\n[list=1]", "[/list]\n"); - node2bbcode($doc, 'li', [], "\n* ", "\n"); - - node2bbcode($doc, 'hr', [], "\n" . str_repeat("-", 70) . "\n", ""); - - node2bbcode($doc, 'tr', [], "\n", ""); - node2bbcode($doc, 'td', [], "\t", ""); - - node2bbcode($doc, 'h1', [], "\n\n*", "*\n"); - node2bbcode($doc, 'h2', [], "\n\n*", "*\n"); - node2bbcode($doc, 'h3', [], "\n\n*", "*\n"); - node2bbcode($doc, 'h4', [], "\n\n*", "*\n"); - node2bbcode($doc, 'h5', [], "\n\n*", "*\n"); - node2bbcode($doc, 'h6', [], "\n\n*", "*\n"); - - // Problem: there is no reliable way to detect if it is a link to a tag or profile - //node2bbcode($doc, 'a', array('href'=>'/(.+)/'), ' $1 ', ' ', true); - //node2bbcode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '', true); - //node2bbcode($doc, 'img', array('alt'=>'/(.+)/'), '$1', ''); - //node2bbcode($doc, 'img', array('title'=>'/(.+)/'), '$1', ''); - //node2bbcode($doc, 'img', array(), '', ''); - if (!$compact) { - node2bbcode($doc, 'img', ['src' => '/(.+)/'], ' [img]$1', '[/img] '); - } else { - node2bbcode($doc, 'img', ['src' => '/(.+)/'], ' ', ' '); - } - - node2bbcode($doc, 'iframe', ['src' => '/(.+)/'], ' $1 ', ''); - - $message = $doc->saveHTML(); - - if (!$compact) { - $message = str_replace("[img]", "", $message); - $message = str_replace("[/img]", "", $message); - } - - // was ersetze ich da? - // Irgendein stoerrisches UTF-Zeug - $message = str_replace(chr(194) . chr(160), ' ', $message); - - $message = str_replace(" ", " ", $message); - - // Aufeinanderfolgende DIVs - $message = preg_replace('=\r *\r=i', "\n", $message); - $message = str_replace("\r", "\n", $message); - - $message = strip_tags($message); - - $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8'); - - if (!$compact && ($message != '')) { - foreach ($urls as $id => $url) { - if ($url != '' && strpos($message, $url) === false) { - $message .= "\n" . $url . ' '; - } - } - } - - $message = str_replace("\n«", "«\n", $message); - $message = str_replace("»\n", "\n»", $message); - - do { - $oldmessage = $message; - $message = str_replace("\n\n\n", "\n\n", $message); - } while ($oldmessage != $message); - - $message = quotelevel(trim($message), $wraplength); - - return trim($message); -} diff --git a/mod/babel.php b/mod/babel.php index 99e6f4078d..a2d197599c 100644 --- a/mod/babel.php +++ b/mod/babel.php @@ -3,12 +3,9 @@ * @file mod/babel.php */ -use Friendica\Content\Text\BBCode; -use Friendica\Content\Text\Markdown; +use Friendica\Content\Text; use Friendica\Core\L10n; -require_once 'include/html2bbcode.php'; - function visible_lf($s) { return str_replace("\n", '
    ', $s); @@ -37,31 +34,31 @@ function babel_content() $o .= '

    ' . L10n::t('Source input: ') . '

    ' . EOL . EOL; $o .= visible_lf($text) . EOL . EOL; - $html = BBCode::convert($text); - $o .= '

    ' . L10n::t("bbcode \x28raw HTML\x28: ") . '

    ' . EOL . EOL; + $html = Text\BBCode::convert($text); + $o .= '

    ' . L10n::t("BBCode::convert \x28raw HTML\x28: ") . '

    ' . EOL . EOL; $o .= htmlspecialchars($html) . EOL . EOL; - $o .= '

    ' . L10n::t('bbcode: ') . '

    ' . EOL . EOL; + $o .= '

    ' . L10n::t('BBCode::convert: ') . '

    ' . EOL . EOL; $o .= $html . EOL . EOL; - $bbcode = html2bbcode($html); - $o .= '

    ' . L10n::t('bbcode => html2bbcode: ') . '

    ' . EOL . EOL; + $bbcode = Text\HTML::toBBCode($html); + $o .= '

    ' . L10n::t('BBCode::convert => HTML::toBBCode: ') . '

    ' . EOL . EOL; $o .= visible_lf($bbcode) . EOL . EOL; - $diaspora = BBCode::toMarkdown($text); + $diaspora = Text\BBCode::toMarkdown($text); $o .= '

    ' . L10n::t('BBCode::toMarkdown: ') . '

    ' . EOL . EOL; $o .= visible_lf($diaspora) . EOL . EOL; - $html = Markdown::convert($diaspora); + $html = Text\Markdown::convert($diaspora); $o .= '

    ' . L10n::t('BBCode::toMarkdown => Markdown::convert: ') . '

    ' . EOL . EOL; $o .= $html . EOL . EOL; - $bbcode = Markdown::toBBCode($diaspora); + $bbcode = Text\Markdown::toBBCode($diaspora); $o .= '

    ' . L10n::t('BBCode::toMarkdown => Markdown::toBBCode: ') . '

    ' . EOL . EOL; $o .= visible_lf($bbcode) . EOL . EOL; - $bbcode = html2bbcode($html); - $o .= '

    ' . L10n::t('bbcode => html2bbcode: ') . '

    ' . EOL . EOL; + $bbcode = Text\HTML::toBBCode($html); + $o .= '

    ' . L10n::t('BBCode::toMarkdown => Markdown::convert => HTML::toBBCode: ') . '

    ' . EOL . EOL; $o .= visible_lf($bbcode) . EOL . EOL; } @@ -70,8 +67,8 @@ function babel_content() $o .= '

    ' . L10n::t("Source input \x28Diaspora format\x29: ") . '

    ' . EOL . EOL; $o .= '
    ' . $d2bbtext . '
    ' . EOL . EOL; - $bb = Markdown::toBBCode($d2bbtext); - $o .= '

    ' . L10n::t('diaspora2bb: ') . '

    ' . EOL . EOL; + $bb = Text\Markdown::toBBCode($d2bbtext); + $o .= '

    ' . L10n::t('Markdown::toBBCode: ') . '

    ' . EOL . EOL; $o .= '
    ' . $bb . '
    ' . EOL . EOL; } diff --git a/mod/display.php b/mod/display.php index ab27b283b7..dfa8640309 100644 --- a/mod/display.php +++ b/mod/display.php @@ -5,6 +5,7 @@ use Friendica\App; use Friendica\Content\Text\BBCode; +use Friendica\Content\Text\HTML; use Friendica\Core\ACL; use Friendica\Core\Config; use Friendica\Core\L10n; @@ -367,10 +368,8 @@ function display_content(App $a, $update = false, $update_uid = 0) { $o .= conversation($a, $items, 'display', $update_uid); // Preparing the meta header - require_once 'include/html2plain.php'; - - $description = trim(html2plain(BBCode::convert($s[0]["body"], false), 0, true)); - $title = trim(html2plain(BBCode::convert($s[0]["title"], false), 0, true)); + $description = trim(HTML::toPlaintext(BBCode::convert($s[0]["body"], false), 0, true)); + $title = trim(HTML::toPlaintext(BBCode::convert($s[0]["title"], false), 0, true)); $author_name = $s[0]["author-name"]; $image = $a->remove_baseurl($s[0]["author-thumb"]); diff --git a/mod/item.php b/mod/item.php index 8aa7c665af..1bbc085279 100644 --- a/mod/item.php +++ b/mod/item.php @@ -808,7 +808,6 @@ function item_post(App $a) { $link = '' . $a->user['username'] . '

    '; $html = prepare_body($datarray); $message = '' . $link . $html . $disclaimer . ''; - include_once 'include/html2plain.php'; $params = [ 'fromName' => $a->user['username'], 'fromEmail' => $a->user['email'], @@ -816,7 +815,7 @@ function item_post(App $a) { 'replyTo' => $a->user['email'], 'messageSubject' => $subject, 'htmlVersion' => $message, - 'textVersion' => html2plain($html.$disclaimer) + 'textVersion' => Friendica\Content\Text\HTML::toPlaintext($html.$disclaimer) ]; Emailer::send($params); } diff --git a/mod/oexchange.php b/mod/oexchange.php index feca39d353..9f844e1db3 100644 --- a/mod/oexchange.php +++ b/mod/oexchange.php @@ -46,13 +46,11 @@ function oexchange_content(App $a) { return; } - require_once('include/html2bbcode.php'); - $post = []; $post['profile_uid'] = local_user(); $post['return'] = '/oexchange/done' ; - $post['body'] = html2bbcode($s); + $post['body'] = Friendica\Content\Text\HTML::toBBCode($s); $post['type'] = 'wall'; $_REQUEST = $post; diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 9c7dac2605..1148103054 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -28,7 +28,6 @@ use Friendica\Util\ParseUrl; use League\HTMLToMarkdown\HtmlConverter; require_once "include/event.php"; -require_once "include/html2plain.php"; require_once "mod/proxy.php"; class BBCode extends BaseObject @@ -413,7 +412,7 @@ class BBCode extends BaseObject } $html = self::convert($post["text"].$post["after"], false, $htmlmode); - $msg = html2plain($html, 0, true); + $msg = HTML::toPlaintext($html, 0, true); $msg = trim(html_entity_decode($msg, ENT_QUOTES, 'UTF-8')); $link = ""; @@ -764,27 +763,6 @@ class BBCode extends BaseObject return $text . "\n" . $data["after"]; } - private static function cleanCss($input) - { - $cleaned = ""; - - $input = strtolower($input); - - for ($i = 0; $i < strlen($input); $i++) { - $char = substr($input, $i, 1); - - if (($char >= "a") && ($char <= "z")) { - $cleaned .= $char; - } - - if (!(strpos(" #;:0123456789-_.%", $char) === false)) { - $cleaned .= $char; - } - } - - return $cleaned; - } - /** * Converts [url] BBCodes in a format that looks fine on Mastodon. (callback function) * @@ -1629,7 +1607,7 @@ class BBCode extends BaseObject $text = preg_replace_callback( "(\[style=(.*?)\](.*?)\[\/style\])ism", function ($match) { - return "" . $match[2] . ""; + return "" . $match[2] . ""; }, $text ); @@ -1638,7 +1616,7 @@ class BBCode extends BaseObject $text = preg_replace_callback( "(\[class=(.*?)\](.*?)\[\/class\])ism", function ($match) { - return "" . $match[2] . ""; + return "" . $match[2] . ""; }, $text ); diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php new file mode 100644 index 0000000000..f82a254d3d --- /dev/null +++ b/src/Content/Text/HTML.php @@ -0,0 +1,674 @@ += "a") && ($char <= "z")) { + $cleaned .= $char; + } + + if (!(strpos(" #;:0123456789-_.%", $char) === false)) { + $cleaned .= $char; + } + } + + return $cleaned; + } + + private static function tagToBBCode(DOMDocument $doc, $tag, $attributes, $startbb, $endbb) + { + do { + $done = self::tagToBBCodeSub($doc, $tag, $attributes, $startbb, $endbb); + } while ($done); + } + + private static function tagToBBCodeSub(DOMDocument $doc, $tag, $attributes, $startbb, $endbb) + { + $savestart = str_replace('$', '\x01', $startbb); + $replace = false; + + $xpath = new DOMXPath($doc); + + $list = $xpath->query("//" . $tag); + foreach ($list as $node) { + $attr = []; + if ($node->attributes->length) { + foreach ($node->attributes as $attribute) { + $attr[$attribute->name] = $attribute->value; + } + } + + $replace = true; + + $startbb = $savestart; + + $i = 0; + + foreach ($attributes as $attribute => $value) { + $startbb = str_replace('\x01' . ++$i, '$1', $startbb); + if (strpos('*' . $startbb, '$1') > 0) { + if ($replace && (@$attr[$attribute] != '')) { + $startbb = preg_replace($value, $startbb, $attr[$attribute], -1, $count); + + // If nothing could be changed + if ($count == 0) { + $replace = false; + } + } else { + $replace = false; + } + } else { + if (@$attr[$attribute] != $value) { + $replace = false; + } + } + } + + if ($replace) { + $StartCode = $doc->createTextNode($startbb); + $EndCode = $doc->createTextNode($endbb); + + $node->parentNode->insertBefore($StartCode, $node); + + if ($node->hasChildNodes()) { + foreach ($node->childNodes as $child) { + $newNode = $child->cloneNode(true); + $node->parentNode->insertBefore($newNode, $node); + } + } + + $node->parentNode->insertBefore($EndCode, $node); + $node->parentNode->removeChild($node); + } + } + + return $replace; + } + + /** + * Made by: ike@piratenpartei.de + * Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom + * https://github.com/annando/Syncom + * + * @brief Converter for HTML to BBCode + * @param string $message + * @param string $basepath + * @return string + */ + public static function toBBCode($message, $basepath = '') + { + $message = str_replace("\r", "", $message); + + // Removing code blocks before the whitespace removal processing below + $codeblocks = []; + $message = preg_replace_callback( + '#
    (.*)
    #iUs', + function ($matches) use (&$codeblocks) { + $return = '[codeblock-' . count($codeblocks) . ']'; + + $prefix = '[code]'; + if ($matches[1] != '') { + $prefix = '[code=' . $matches[1] . ']'; + } + + $codeblocks[] = $prefix . trim($matches[2]) . '[/code]'; + return $return; + }, + $message + ); + + $message = str_replace( + [ + "
  • ", + "

  • ", + ], [ + "
  • ", + "
  • ", + ], $message + ); + + // remove namespaces + $message = preg_replace('=<(\w+):(.+?)>=', '', $message); + $message = preg_replace('==', '', $message); + + $doc = new DOMDocument(); + $doc->preserveWhiteSpace = false; + + $message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8"); + + @$doc->loadHTML($message); + + XML::deleteNode($doc, 'style'); + XML::deleteNode($doc, 'head'); + XML::deleteNode($doc, 'title'); + XML::deleteNode($doc, 'meta'); + XML::deleteNode($doc, 'xml'); + XML::deleteNode($doc, 'removeme'); + + $xpath = new DomXPath($doc); + $list = $xpath->query("//pre"); + foreach ($list as $node) { + $node->nodeValue = str_replace("\n", "\r", $node->nodeValue); + } + + $message = $doc->saveHTML(); + $message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "
    ", " ", ""], $message); + $message = preg_replace('= [\s]*=i', " ", $message); + @$doc->loadHTML($message); + + self::tagToBBCode($doc, 'html', [], "", ""); + self::tagToBBCode($doc, 'body', [], "", ""); + + // Outlook-Quote - Variant 1 + self::tagToBBCode($doc, 'p', ['class' => 'MsoNormal', 'style' => 'margin-left:35.4pt'], '[quote]', '[/quote]'); + + // Outlook-Quote - Variant 2 + self::tagToBBCode($doc, 'div', ['style' => 'border:none;border-left:solid blue 1.5pt;padding:0cm 0cm 0cm 4.0pt'], + '[quote]', '[/quote]'); + + // MyBB-Stuff + self::tagToBBCode($doc, 'span', ['style' => 'text-decoration: underline;'], '[u]', '[/u]'); + self::tagToBBCode($doc, 'span', ['style' => 'font-style: italic;'], '[i]', '[/i]'); + self::tagToBBCode($doc, 'span', ['style' => 'font-weight: bold;'], '[b]', '[/b]'); + + /* self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[font=$1][size=$2][color=$3]', '[/color][/size][/font]'); + self::node2BBCode($doc, 'font', array('size'=>'/(\d+)/', 'color'=>'/(.+)/'), '[size=$1][color=$2]', '[/color][/size]'); + self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/', 'size'=>'/(.+)/'), '[font=$1][size=$2]', '[/size][/font]'); + self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/', 'color'=>'/(.+)/'), '[font=$1][color=$3]', '[/color][/font]'); + self::node2BBCode($doc, 'font', array('face'=>'/([\w ]+)/'), '[font=$1]', '[/font]'); + self::node2BBCode($doc, 'font', array('size'=>'/(\d+)/'), '[size=$1]', '[/size]'); + self::node2BBCode($doc, 'font', array('color'=>'/(.+)/'), '[color=$1]', '[/color]'); + */ + // Untested + //self::node2BBCode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*font-family:\s*(.+?)[,;].*color:\s*(.+?)[,;].*/'), '[size=$1][font=$2][color=$3]', '[/color][/font][/size]'); + //self::node2BBCode($doc, 'span', array('style'=>'/.*font-size:\s*(\d+)[,;].*/'), '[size=$1]', '[/size]'); + //self::node2BBCode($doc, 'span', array('style'=>'/.*font-size:\s*(.+?)[,;].*/'), '[size=$1]', '[/size]'); + + self::tagToBBCode($doc, 'span', ['style' => '/.*color:\s*(.+?)[,;].*/'], '[color="$1"]', '[/color]'); + + //self::node2BBCode($doc, 'span', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]'); + //self::node2BBCode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)pt.*/'), '[font=$1][size=$2]', '[/size][/font]'); + //self::node2BBCode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*font-size:\s*(\d+?)px.*/'), '[font=$1][size=$2]', '[/size][/font]'); + //self::node2BBCode($doc, 'div', array('style'=>'/.*font-family:\s*(.+?)[,;].*/'), '[font=$1]', '[/font]'); + // Importing the classes - interesting for importing of posts from third party networks that were exported from friendica + // Test + //self::node2BBCode($doc, 'span', array('class'=>'/([\w ]+)/'), '[class=$1]', '[/class]'); + self::tagToBBCode($doc, 'span', ['class' => 'type-link'], '[class=type-link]', '[/class]'); + self::tagToBBCode($doc, 'span', ['class' => 'type-video'], '[class=type-video]', '[/class]'); + + self::tagToBBCode($doc, 'strong', [], '[b]', '[/b]'); + self::tagToBBCode($doc, 'em', [], '[i]', '[/i]'); + self::tagToBBCode($doc, 'b', [], '[b]', '[/b]'); + self::tagToBBCode($doc, 'i', [], '[i]', '[/i]'); + self::tagToBBCode($doc, 'u', [], '[u]', '[/u]'); + + self::tagToBBCode($doc, 'big', [], "[size=large]", "[/size]"); + self::tagToBBCode($doc, 'small', [], "[size=small]", "[/size]"); + + self::tagToBBCode($doc, 'blockquote', [], '[quote]', '[/quote]'); + + self::tagToBBCode($doc, 'br', [], "\n", ''); + + self::tagToBBCode($doc, 'p', ['class' => 'MsoNormal'], "\n", ""); + self::tagToBBCode($doc, 'div', ['class' => 'MsoNormal'], "\r", ""); + + self::tagToBBCode($doc, 'span', [], "", ""); + + self::tagToBBCode($doc, 'span', [], "", ""); + self::tagToBBCode($doc, 'pre', [], "", ""); + + self::tagToBBCode($doc, 'div', [], "\r", "\r"); + self::tagToBBCode($doc, 'p', [], "\n", "\n"); + + self::tagToBBCode($doc, 'ul', [], "[list]", "[/list]"); + self::tagToBBCode($doc, 'ol', [], "[list=1]", "[/list]"); + self::tagToBBCode($doc, 'li', [], "[*]", ""); + + self::tagToBBCode($doc, 'hr', [], "[hr]", ""); + + self::tagToBBCode($doc, 'table', [], "", ""); + self::tagToBBCode($doc, 'tr', [], "\n", ""); + self::tagToBBCode($doc, 'td', [], "\t", ""); + //self::node2BBCode($doc, 'table', array(), "[table]", "[/table]"); + //self::node2BBCode($doc, 'th', array(), "[th]", "[/th]"); + //self::node2BBCode($doc, 'tr', array(), "[tr]", "[/tr]"); + //self::node2BBCode($doc, 'td', array(), "[td]", "[/td]"); + //self::node2BBCode($doc, 'h1', array(), "\n\n[size=xx-large][b]", "[/b][/size]\n"); + //self::node2BBCode($doc, 'h2', array(), "\n\n[size=x-large][b]", "[/b][/size]\n"); + //self::node2BBCode($doc, 'h3', array(), "\n\n[size=large][b]", "[/b][/size]\n"); + //self::node2BBCode($doc, 'h4', array(), "\n\n[size=medium][b]", "[/b][/size]\n"); + //self::node2BBCode($doc, 'h5', array(), "\n\n[size=small][b]", "[/b][/size]\n"); + //self::node2BBCode($doc, 'h6', array(), "\n\n[size=x-small][b]", "[/b][/size]\n"); + + self::tagToBBCode($doc, 'h1', [], "[h1]", "[/h1]"); + self::tagToBBCode($doc, 'h2', [], "[h2]", "[/h2]"); + self::tagToBBCode($doc, 'h3', [], "[h3]", "[/h3]"); + self::tagToBBCode($doc, 'h4', [], "[h4]", "[/h4]"); + self::tagToBBCode($doc, 'h5', [], "[h5]", "[/h5]"); + self::tagToBBCode($doc, 'h6', [], "[h6]", "[/h6]"); + + self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]'); + self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]'); + + self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', + '[/img]'); + self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]'); + + + self::tagToBBCode($doc, 'video', ['src' => '/(.+)/'], '[video]$1', '[/video]'); + self::tagToBBCode($doc, 'audio', ['src' => '/(.+)/'], '[audio]$1', '[/audio]'); + self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], '[iframe]$1', '[/iframe]'); + + self::tagToBBCode($doc, 'key', [], '[code]', '[/code]'); + self::tagToBBCode($doc, 'code', [], '[code]', '[/code]'); + + $message = $doc->saveHTML(); + + // I'm removing something really disturbing + // Don't know exactly what it is + $message = str_replace(chr(194) . chr(160), ' ', $message); + + $message = str_replace(" ", " ", $message); + + // removing multiple DIVs + $message = preg_replace('=\r *\r=i', "\n", $message); + $message = str_replace("\r", "\n", $message); + + Addon::callHooks('html2bbcode', $message); + + $message = strip_tags($message); + + $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8'); + + $message = str_replace(["<"], ["<"], $message); + + // remove quotes if they don't make sense + $message = preg_replace('=\[/quote\][\s]*\[quote\]=i', "\n", $message); + + $message = preg_replace('=\[quote\]\s*=i', "[quote]", $message); + $message = preg_replace('=\s*\[/quote\]=i', "[/quote]", $message); + + do { + $oldmessage = $message; + $message = str_replace("\n \n", "\n\n", $message); + } while ($oldmessage != $message); + + do { + $oldmessage = $message; + $message = str_replace("\n\n\n", "\n\n", $message); + } while ($oldmessage != $message); + + do { + $oldmessage = $message; + $message = str_replace( + [ + "[/size]\n\n", + "\n[hr]", + "[hr]\n", + "\n[list", + "[/list]\n", + "\n[/", + "[list]\n", + "[list=1]\n", + "\n[*]"], + [ + "[/size]\n", + "[hr]", + "[hr]", + "[list", + "[/list]", + "[/", + "[list]", + "[list=1]", + "[*]"], $message + ); + } while ($message != $oldmessage); + + $message = str_replace( + ['[b][b]', '[/b][/b]', '[i][i]', '[/i][/i]'], ['[b]', '[/b]', '[i]', '[/i]'], $message + ); + + // Handling Yahoo style of mails + $message = str_replace('[hr][b]From:[/b]', '[quote][b]From:[/b]', $message); + + // Restore code blocks + $message = preg_replace_callback( + '#\[codeblock-([0-9]+)\]#iU', + function ($matches) use ($codeblocks) { + $return = ''; + if (isset($codeblocks[intval($matches[1])])) { + $return = $codeblocks[$matches[1]]; + } + return $return; + }, + $message + ); + + $message = trim($message); + + if ($basepath != '') { + $message = self::qualifyURLs($message, $basepath); + } + + return $message; + } + + /** + * @brief Sub function to complete incomplete URL + * + * @param array $matches Result of preg_replace_callback + * @param string $basepath Basepath that is used to complete the URL + * + * @return string The expanded URL + */ + private static function qualifyURLsSub($matches, $basepath) + { + $base = parse_url($basepath); + unset($base['query']); + unset($base['fragment']); + + $link = $matches[0]; + $url = $matches[1]; + + $parts = array_merge($base, parse_url($url)); + $url2 = Network::unparseURL($parts); + + return str_replace($url, $url2, $link); + } + + /** + * @brief Complete incomplete URLs in BBCode + * + * @param string $body Body with URLs + * @param string $basepath Base path that is used to complete the URL + * + * @return string Body with expanded URLs + */ + private static function qualifyURLs($body, $basepath) + { + $URLSearchString = "^\[\]"; + + $matches = ["/\[url\=([$URLSearchString]*)\].*?\[\/url\]/ism", + "/\[url\]([$URLSearchString]*)\[\/url\]/ism", + "/\[img\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism", + "/\[img\](.*?)\[\/img\]/ism", + "/\[zmg\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism", + "/\[zmg\](.*?)\[\/zmg\]/ism", + "/\[video\](.*?)\[\/video\]/ism", + "/\[audio\](.*?)\[\/audio\]/ism", + ]; + + foreach ($matches as $match) { + $body = preg_replace_callback( + $match, function ($match) use ($basepath) { + return self::qualifyURLsSub($match, $basepath); + }, + $body + ); + } + return $body; + } + + private static function breakLines($line, $level, $wraplength = 75) + { + if ($wraplength == 0) { + $wraplength = 2000000; + } + + $wraplen = $wraplength - $level; + + $newlines = []; + + do { + $oldline = $line; + + $subline = substr($line, 0, $wraplen); + + $pos = strrpos($subline, ' '); + + if ($pos == 0) { + $pos = strpos($line, ' '); + } + + if (($pos > 0) && strlen($line) > $wraplen) { + $newline = trim(substr($line, 0, $pos)); + if ($level > 0) { + $newline = str_repeat(">", $level) . ' ' . $newline; + } + + $newlines[] = $newline . " "; + $line = substr($line, $pos + 1); + } + } while ((strlen($line) > $wraplen) && !($oldline == $line)); + + if ($level > 0) { + $line = str_repeat(">", $level) . ' ' . $line; + } + + $newlines[] = $line; + + return implode($newlines, "\n"); + } + + private static function quoteLevel($message, $wraplength = 75) + { + $lines = explode("\n", $message); + + $newlines = []; + $level = 0; + foreach ($lines as $line) { + $line = trim($line); + $startquote = false; + while (strpos("*" . $line, '[quote]') > 0) { + $level++; + $pos = strpos($line, '[quote]'); + $line = substr($line, 0, $pos) . substr($line, $pos + 7); + $startquote = true; + } + + $currlevel = $level; + + while (strpos("*" . $line, '[/quote]') > 0) { + $level--; + if ($level < 0) { + $level = 0; + } + + $pos = strpos($line, '[/quote]'); + $line = substr($line, 0, $pos) . substr($line, $pos + 8); + } + + if (!$startquote || ($line != '')) { + $newlines[] = self::breakLines($line, $currlevel, $wraplength); + } + } + + return implode($newlines, "\n"); + } + + private static function collectURLs($message) + { + $pattern = '/(.*?)<\/a>/is'; + preg_match_all($pattern, $message, $result, PREG_SET_ORDER); + + $urls = []; + foreach ($result as $treffer) { + $ignore = false; + + // A list of some links that should be ignored + $list = ["/user/", "/tag/", "/group/", "/profile/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/", + "//facebook.com/profile.php?id=", "//plus.google.com/", "//twitter.com/"]; + foreach ($list as $listitem) { + if (strpos($treffer[1], $listitem) !== false) { + $ignore = true; + } + } + + if ((strpos($treffer[1], "//twitter.com/") !== false) && (strpos($treffer[1], "/status/") !== false)) { + $ignore = false; + } + + if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/posts") !== false)) { + $ignore = false; + } + + if ((strpos($treffer[1], "//plus.google.com/") !== false) && (strpos($treffer[1], "/photos") !== false)) { + $ignore = false; + } + + if (!$ignore) { + $urls[$treffer[1]] = $treffer[1]; + } + } + + return $urls; + } + + public static function toPlaintext($html, $wraplength = 75, $compact = false) + { + global $lang; + + $message = str_replace("\r", "", $html); + + $doc = new DOMDocument(); + $doc->preserveWhiteSpace = false; + + $message = mb_convert_encoding($message, 'HTML-ENTITIES', "UTF-8"); + + @$doc->loadHTML($message); + + $xpath = new DOMXPath($doc); + $list = $xpath->query("//pre"); + foreach ($list as $node) { + $node->nodeValue = str_replace("\n", "\r", $node->nodeValue); + } + + $message = $doc->saveHTML(); + $message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "
    ", " ", ""], $message); + $message = preg_replace('= [\s]*=i', " ", $message); + + // Collecting all links + $urls = self::collectURLs($message); + + @$doc->loadHTML($message); + + self::tagToBBCode($doc, 'html', [], '', ''); + self::tagToBBCode($doc, 'body', [], '', ''); + + // MyBB-Auszeichnungen + /* + self::node2BBCode($doc, 'span', array('style'=>'text-decoration: underline;'), '_', '_'); + self::node2BBCode($doc, 'span', array('style'=>'font-style: italic;'), '/', '/'); + self::node2BBCode($doc, 'span', array('style'=>'font-weight: bold;'), '*', '*'); + + self::node2BBCode($doc, 'strong', array(), '*', '*'); + self::node2BBCode($doc, 'b', array(), '*', '*'); + self::node2BBCode($doc, 'i', array(), '/', '/'); + self::node2BBCode($doc, 'u', array(), '_', '_'); + */ + + if ($compact) { + self::tagToBBCode($doc, 'blockquote', [], "»", "«"); + } else { + self::tagToBBCode($doc, 'blockquote', [], '[quote]', "[/quote]\n"); + } + + self::tagToBBCode($doc, 'br', [], "\n", ''); + + self::tagToBBCode($doc, 'span', [], "", ""); + self::tagToBBCode($doc, 'pre', [], "", ""); + self::tagToBBCode($doc, 'div', [], "\r", "\r"); + self::tagToBBCode($doc, 'p', [], "\n", "\n"); + + //self::node2BBCode($doc, 'ul', array(), "\n[list]", "[/list]\n"); + //self::node2BBCode($doc, 'ol', array(), "\n[list=1]", "[/list]\n"); + self::tagToBBCode($doc, 'li', [], "\n* ", "\n"); + + self::tagToBBCode($doc, 'hr', [], "\n" . str_repeat("-", 70) . "\n", ""); + + self::tagToBBCode($doc, 'tr', [], "\n", ""); + self::tagToBBCode($doc, 'td', [], "\t", ""); + + self::tagToBBCode($doc, 'h1', [], "\n\n*", "*\n"); + self::tagToBBCode($doc, 'h2', [], "\n\n*", "*\n"); + self::tagToBBCode($doc, 'h3', [], "\n\n*", "*\n"); + self::tagToBBCode($doc, 'h4', [], "\n\n*", "*\n"); + self::tagToBBCode($doc, 'h5', [], "\n\n*", "*\n"); + self::tagToBBCode($doc, 'h6', [], "\n\n*", "*\n"); + + // Problem: there is no reliable way to detect if it is a link to a tag or profile + //self::node2BBCode($doc, 'a', array('href'=>'/(.+)/'), ' $1 ', ' ', true); + //self::node2BBCode($doc, 'a', array('href'=>'/(.+)/', 'rel'=>'oembed'), ' $1 ', '', true); + //self::node2BBCode($doc, 'img', array('alt'=>'/(.+)/'), '$1', ''); + //self::node2BBCode($doc, 'img', array('title'=>'/(.+)/'), '$1', ''); + //self::node2BBCode($doc, 'img', array(), '', ''); + if (!$compact) { + self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], ' [img]$1', '[/img] '); + } else { + self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], ' ', ' '); + } + + self::tagToBBCode($doc, 'iframe', ['src' => '/(.+)/'], ' $1 ', ''); + + $message = $doc->saveHTML(); + + if (!$compact) { + $message = str_replace("[img]", "", $message); + $message = str_replace("[/img]", "", $message); + } + + // was ersetze ich da? + // Irgendein stoerrisches UTF-Zeug + $message = str_replace(chr(194) . chr(160), ' ', $message); + + $message = str_replace(" ", " ", $message); + + // Aufeinanderfolgende DIVs + $message = preg_replace('=\r *\r=i', "\n", $message); + $message = str_replace("\r", "\n", $message); + + $message = strip_tags($message); + + $message = html_entity_decode($message, ENT_QUOTES, 'UTF-8'); + + if (!$compact && ($message != '')) { + foreach ($urls as $id => $url) { + if ($url != '' && strpos($message, $url) === false) { + $message .= "\n" . $url . ' '; + } + } + } + + $message = str_replace("\n«", "«\n", $message); + $message = str_replace("»\n", "\n»", $message); + + do { + $oldmessage = $message; + $message = str_replace("\n\n\n", "\n\n", $message); + } while ($oldmessage != $message); + + $message = self::quoteLevel(trim($message), $wraplength); + + return trim($message); + } +} diff --git a/src/Content/Text/Markdown.php b/src/Content/Text/Markdown.php index e7383a3fd7..ff6f890bb5 100644 --- a/src/Content/Text/Markdown.php +++ b/src/Content/Text/Markdown.php @@ -10,8 +10,6 @@ use Friendica\BaseObject; use Friendica\Model\Contact; use Michelf\MarkdownExtra; -require_once 'include/html2bbcode.php'; - /** * Friendica-specific usage of Markdown * @@ -94,7 +92,7 @@ class Markdown extends BaseObject $s = str_replace('#', '#', $s); - $s = html2bbcode($s); + $s = Friendica\Content\Text\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); diff --git a/src/Core/NotificationsManager.php b/src/Core/NotificationsManager.php index 0e552d2e09..95be5cdede 100644 --- a/src/Core/NotificationsManager.php +++ b/src/Core/NotificationsManager.php @@ -19,7 +19,6 @@ use Friendica\Util\Temporal; use Friendica\Util\XML; require_once 'include/dba.php'; -require_once 'include/html2plain.php'; /** * @brief Methods for read and write notifications from/to database @@ -47,7 +46,7 @@ class NotificationsManager extends BaseObject $n['timestamp'] = strtotime($local_time); $n['date_rel'] = Temporal::getRelativeDate($n['date']); $n['msg_html'] = BBCode::convert($n['msg'], false); - $n['msg_plain'] = explode("\n", trim(html2plain($n['msg_html'], 0)))[0]; + $n['msg_plain'] = explode("\n", trim(Friendica\Content\Text\HTML::toPlaintext($n['msg_html'], 0)))[0]; $rets[] = $n; } diff --git a/src/Model/GContact.php b/src/Model/GContact.php index 7b14b2cdc4..7a64751d64 100644 --- a/src/Model/GContact.php +++ b/src/Model/GContact.php @@ -20,7 +20,6 @@ use dba; use Exception; require_once 'include/dba.php'; -require_once 'include/html2bbcode.php'; /** * @brief This class handles GlobalContact related functions diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 5e7cc02a36..3def7d3a8c 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -42,7 +42,6 @@ require_once "include/enotify.php"; require_once "include/items.php"; require_once "include/event.php"; require_once "include/text.php"; -require_once "include/html2bbcode.php"; /** * @brief This class contain functions to create and send DFRN XML files @@ -2454,7 +2453,7 @@ class DFRN $purifier = new HTMLPurifier($config); $item['body'] = $purifier->purify($item['body']); - $item['body'] = @html2bbcode($item['body']); + $item['body'] = @Friendica\Content\Text\HTML::toBBCode($item['body']); } /// @todo We should check for a repeated post and if we know the repeated author. diff --git a/src/Protocol/Email.php b/src/Protocol/Email.php index b1eeb94d62..054a1f4ff7 100644 --- a/src/Protocol/Email.php +++ b/src/Protocol/Email.php @@ -4,7 +4,7 @@ */ namespace Friendica\Protocol; -require_once 'include/html2plain.php'; +use Friendica\Content\Text\HTML; /** * @brief Email class @@ -111,7 +111,7 @@ class Email if (trim($ret['body']) == '') { $ret['body'] = self::messageGetPart($mbox, $uid, $struc, 0, 'plain'); } else { - $ret['body'] = html2bbcode($ret['body']); + $ret['body'] = HTML::toBBCode($ret['body']); } } else { $text = ''; @@ -128,7 +128,7 @@ class Email } } if (trim($html) != '') { - $ret['body'] = html2bbcode($html); + $ret['body'] = HTML::toBBCode($html); } else { $ret['body'] = $text; } @@ -328,7 +328,7 @@ class Email $body .= "Content-Transfer-Encoding: 8bit\n"; $body .= "Content-Type: text/plain; charset=utf-8; format=flowed\n\n"; - $body .= html2plain($html)."\n"; + $body .= Friendica\Content\Text\HTML::toPlaintext($html)."\n"; $body .= "--=_".$part."\n"; $body .= "Content-Transfer-Encoding: 8bit\n"; diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 17234ce45a..c67df646b4 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -15,7 +15,6 @@ use DOMDocument; use DOMXPath; require_once 'include/dba.php'; -require_once 'include/html2bbcode.php'; require_once 'include/items.php'; /** @@ -363,7 +362,7 @@ class Feed { if (self::titleIsBody($item["title"], $body)) { $item["title"] = ""; } - $item["body"] = html2bbcode($body, $basepath); + $item["body"] = Friendica\Content\Text\HTML::toBBCode($body, $basepath); if (($item["body"] == '') && ($item["title"] != '')) { $item["body"] = $item["title"]; diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index c6f840a66e..fd53772fd7 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -5,6 +5,7 @@ namespace Friendica\Protocol; use Friendica\Content\Text\BBCode; +use Friendica\Content\Text\HTML; use Friendica\Core\Cache; use Friendica\Core\Config; use Friendica\Core\L10n; @@ -25,7 +26,6 @@ use DOMDocument; use DOMXPath; require_once 'include/dba.php'; -require_once 'include/html2bbcode.php'; require_once 'include/items.php'; require_once 'mod/share.php'; require_once 'include/enotify.php'; @@ -168,7 +168,7 @@ class OStatus $value = $xpath->evaluate('atom:author/poco:note/text()', $context)->item(0)->nodeValue; if ($value != "") { - $contact["about"] = html2bbcode($value); + $contact["about"] = HTML::toBBCode($value); } $value = $xpath->evaluate('atom:author/poco:address/poco:formatted/text()', $context)->item(0)->nodeValue; @@ -557,7 +557,7 @@ class OStatus */ private static function processPost($xpath, $entry, &$item, $importer) { - $item["body"] = html2bbcode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue); + $item["body"] = HTML::toBBCode($xpath->query('atom:content/text()', $entry)->item(0)->nodeValue); $item["object-type"] = $xpath->query('activity:object-type/text()', $entry)->item(0)->nodeValue; if (($item["object-type"] == ACTIVITY_OBJ_BOOKMARK) || ($item["object-type"] == ACTIVITY_OBJ_EVENT)) { $item["title"] = $xpath->query('atom:title/text()', $entry)->item(0)->nodeValue; @@ -659,7 +659,7 @@ class OStatus if (($item["verb"] == ACTIVITY_POST) && $xpath->evaluate('boolean(atom:summary)', $entry)) { $clear_text = $xpath->query('atom:summary/text()', $entry)->item(0)->nodeValue; - $item["body"] = html2bbcode($clear_text) . '[spoiler]' . $item["body"] . '[/spoiler]'; + $item["body"] = HTML::toBBCode($clear_text) . '[spoiler]' . $item["body"] . '[/spoiler]'; } if (($self != '') && empty($item['protocol'])) { @@ -1014,7 +1014,7 @@ class OStatus $item["author-link"] = $orig_author["author-link"]; $item["author-avatar"] = $orig_author["author-avatar"]; - $item["body"] = html2bbcode($orig_body); + $item["body"] = HTML::toBBCode($orig_body); $item["created"] = $orig_created; $item["edited"] = $orig_edited; diff --git a/src/Protocol/PortableContact.php b/src/Protocol/PortableContact.php index 5b419e42ef..46862b4065 100644 --- a/src/Protocol/PortableContact.php +++ b/src/Protocol/PortableContact.php @@ -9,6 +9,7 @@ namespace Friendica\Protocol; +use Friendica\Content\Text\HTML; use Friendica\Core\Config; use Friendica\Core\Worker; use Friendica\Database\DBM; @@ -23,7 +24,6 @@ use DOMXPath; use Exception; require_once 'include/dba.php'; -require_once 'include/html2bbcode.php'; class PortableContact { @@ -155,7 +155,7 @@ class PortableContact } if (isset($entry->aboutMe)) { - $about = html2bbcode($entry->aboutMe); + $about = HTML::toBBCode($entry->aboutMe); } if (isset($entry->gender)) { @@ -1669,7 +1669,7 @@ class PortableContact } if (isset($entry->aboutMe)) { - $about = html2bbcode($entry->aboutMe); + $about = HTML::toBBCode($entry->aboutMe); } if (isset($entry->gender)) { diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index fe6fad66b0..dc6caab3db 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -17,7 +17,6 @@ use Friendica\Protocol\Diaspora; use Friendica\Protocol\Email; use dba; -require_once 'include/html2plain.php'; require_once 'include/items.php'; /// @todo This is some ugly code that needs to be split into several methods diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index b43639b845..edb0df33ad 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -18,7 +18,6 @@ use Friendica\Protocol\Salmon; use dba; require_once 'include/dba.php'; -require_once 'include/html2plain.php'; require_once 'include/items.php'; /*