X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FContent%2FText%2FHTML.php;h=c127973b13b8493837844b770c8762694f28785f;hb=a947bd0889cfb2eb58692f92ab19a875019d3b79;hp=6e31697e07fa6fca3c28107e22edeb4cd827e81c;hpb=591c00dd5cf2eb73209a849e3efd2088638cf0cc;p=friendica.git diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php index 6e31697e07..c127973b13 100644 --- a/src/Content/Text/HTML.php +++ b/src/Content/Text/HTML.php @@ -7,15 +7,15 @@ namespace Friendica\Content\Text; use DOMDocument; use DOMXPath; -use Friendica\Core\Addon; +use Friendica\Content\Widget\ContactBlock; +use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Config; -use Friendica\Core\PConfig; use Friendica\Core\Renderer; -use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Util\Network; use Friendica\Util\Proxy as ProxyUtils; +use Friendica\Util\Strings; use Friendica\Util\XML; use League\HTMLToMarkdown\HtmlConverter; @@ -56,6 +56,7 @@ class HTML $xpath = new DOMXPath($doc); + /** @var \DOMNode[] $list */ $list = $xpath->query("//" . $tag); foreach ($list as $node) { $attr = []; @@ -98,9 +99,12 @@ class HTML $node->parentNode->insertBefore($StartCode, $node); if ($node->hasChildNodes()) { + /** @var \DOMNode $child */ foreach ($node->childNodes as $child) { - $newNode = $child->cloneNode(true); - $node->parentNode->insertBefore($newNode, $node); + if (trim($child->nodeValue)) { + $newNode = $child->cloneNode(true); + $node->parentNode->insertBefore($newNode, $node); + } } } @@ -115,12 +119,13 @@ class HTML /** * Made by: ike@piratenpartei.de * Originally made for the syncom project: http://wiki.piratenpartei.de/Syncom - * https://github.com/annando/Syncom + * https://github.com/annando/Syncom * * @brief Converter for HTML to BBCode * @param string $message * @param string $basepath * @return string + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function toBBCode($message, $basepath = '') { @@ -177,7 +182,9 @@ class HTML $xpath = new DomXPath($doc); $list = $xpath->query("//pre"); foreach ($list as $node) { - $node->nodeValue = str_replace("\n", "\r", $node->nodeValue); + // Ensure to escape unescaped & - they will otherwise raise a warning + $safe_value = preg_replace('/&(?!\w+;)/', '&', $node->nodeValue); + $node->nodeValue = str_replace("\n", "\r", $safe_value); } $message = $doc->saveHTML(); @@ -287,6 +294,7 @@ class HTML self::tagToBBCode($doc, 'a', ['href' => '/mailto:(.+)/'], '[mail=$1]', '[/mail]'); self::tagToBBCode($doc, 'a', ['href' => '/(.+)/'], '[url=$1]', '[/url]'); + self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'alt' => '/(.+)/'], '[img=$1]$2', '[/img]'); self::tagToBBCode($doc, 'img', ['src' => '/(.+)/', 'width' => '/(\d+)/', 'height' => '/(\d+)/'], '[img=$2x$3]$1', '[/img]'); self::tagToBBCode($doc, 'img', ['src' => '/(.+)/'], '[img]$1', '[/img]'); @@ -310,7 +318,7 @@ class HTML $message = preg_replace('=\r *\r=i', "\n", $message); $message = str_replace("\r", "\n", $message); - Addon::callHooks('html2bbcode', $message); + Hook::callAll('html2bbcode', $message); $message = strip_tags($message); @@ -556,6 +564,8 @@ class HTML $ignore = false; } + $ignore = $ignore || strpos($treffer[1], '#') === 0; + if (!$ignore) { $urls[$treffer[1]] = $treffer[1]; } @@ -564,7 +574,13 @@ class HTML return $urls; } - public static function toPlaintext($html, $wraplength = 75, $compact = false) + /** + * @param string $html + * @param int $wraplength Ensures individual lines aren't longer than this many characters. Doesn't break words. + * @param bool $compact True: Completely strips image tags; False: Keeps image URLs + * @return string + */ + public static function toPlaintext(string $html, $wraplength = 75, $compact = false) { $message = str_replace("\r", "", $html); @@ -573,38 +589,20 @@ class HTML $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); - } + @$doc->loadHTML($message, LIBXML_HTML_NODEFDTD); $message = $doc->saveHTML(); - $message = str_replace(["\n<", ">\n", "\r", "\n", "\xC3\x82\xC2\xA0"], ["<", ">", "
", " ", ""], $message); - $message = preg_replace('= [\s]*=i', " ", $message); + // Remove eventual UTF-8 BOM + $message = str_replace("\xC3\x82\xC2\xA0", "", $message); // Collecting all links $urls = self::collectURLs($message); - @$doc->loadHTML($message); + @$doc->loadHTML($message, LIBXML_HTML_NODEFDTD); 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 { @@ -618,8 +616,6 @@ class HTML 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", ""); @@ -634,12 +630,6 @@ class HTML 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 { @@ -709,8 +699,9 @@ class HTML * @brief Convert video HTML to BBCode tags * * @param string $s + * @return string */ - public static function htmlToBBVideo($s) + public static function toBBCodeVideo($s) { $s = preg_replace( '#]+>(.*?)https?://www.youtube.com/((?:v|cp)/[A-Za-z0-9\-_=]+)(.*?)#ism', @@ -785,7 +776,9 @@ class HTML /** * Loader for infinite scrolling + * * @return string html for loader + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function scrollLoader() { @@ -799,113 +792,43 @@ class HTML /** * Get html for contact block. * - * @template contact_block.tpl - * @hook contact_block_end (contacts=>array, output=>string) + * @deprecated since version 2019.03 + * @see ContactBlock::getHTML() * @return string + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException */ public static function contactBlock() { - $o = ''; - $a = get_app(); - - $shown = PConfig::get($a->profile['uid'], 'system', 'display_friend_count', 24); - if ($shown == 0) { - return; - } - - if (!is_array($a->profile) || $a->profile['hide-friends']) { - return $o; - } - - $r = q("SELECT COUNT(*) AS `total` FROM `contact` - WHERE `uid` = %d AND NOT `self` AND NOT `blocked` - AND NOT `pending` AND NOT `hidden` AND NOT `archive` - AND `network` IN ('%s', '%s', '%s')", - intval($a->profile['uid']), - DBA::escape(Protocol::DFRN), - DBA::escape(Protocol::OSTATUS), - DBA::escape(Protocol::DIASPORA) - ); - - if (DBA::isResult($r)) { - $total = intval($r[0]['total']); - } - - if (!$total) { - $contacts = L10n::t('No contacts'); - $micropro = null; - } else { - // Splitting the query in two parts makes it much faster - $r = q("SELECT `id` FROM `contact` - WHERE `uid` = %d AND NOT `self` AND NOT `blocked` - AND NOT `pending` AND NOT `hidden` AND NOT `archive` - AND `network` IN ('%s', '%s', '%s') - ORDER BY RAND() LIMIT %d", - intval($a->profile['uid']), - DBA::escape(Protocol::DFRN), - DBA::escape(Protocol::OSTATUS), - DBA::escape(Protocol::DIASPORA), - intval($shown) - ); - - if (DBA::isResult($r)) { - $contacts = []; - foreach ($r as $contact) { - $contacts[] = $contact["id"]; - } - - $r = q("SELECT `id`, `uid`, `addr`, `url`, `name`, `thumb`, `network` FROM `contact` WHERE `id` IN (%s)", - DBA::escape(implode(",", $contacts)) - ); + $a = \get_app(); - if (DBA::isResult($r)) { - $contacts = L10n::tt('%d Contact', '%d Contacts', $total); - $micropro = []; - foreach ($r as $rr) { - $micropro[] = self::micropro($rr, true, 'mpfriend'); - } - } - } - } - - $tpl = Renderer::getMarkupTemplate('contact_block.tpl'); - $o = Renderer::replaceMacros($tpl, [ - '$contacts' => $contacts, - '$nickname' => $a->profile['nickname'], - '$viewcontacts' => L10n::t('View Contacts'), - '$micropro' => $micropro, - ]); - - $arr = ['contacts' => $r, 'output' => $o]; - - Addon::callHooks('contact_block_end', $arr); - - return $o; + return ContactBlock::getHTML($a->profile); } /** - * @brief Format contacts as picture links or as texxt links + * @brief Format contacts as picture links or as text links * - * @param array $contact Array with contacts which contains an array with - * int 'id' => The ID of the contact - * int 'uid' => The user ID of the user who owns this data - * string 'name' => The name of the contact - * string 'url' => The url to the profile page of the contact - * string 'addr' => The webbie of the contact (e.g.) username@friendica.com - * string 'network' => The network to which the contact belongs to - * string 'thumb' => The contact picture - * string 'click' => js code which is performed when clicking on the contact - * @param boolean $redirect If true try to use the redir url if it's possible - * @param string $class CSS class for the - * @param boolean $textmode If true display the contacts as text links - * if false display the contacts as picture links - - * @return string Formatted html - */ + * @param array $contact Array with contacts which contains an array with + * int 'id' => The ID of the contact + * int 'uid' => The user ID of the user who owns this data + * string 'name' => The name of the contact + * string 'url' => The url to the profile page of the contact + * string 'addr' => The webbie of the contact (e.g.) username@friendica.com + * string 'network' => The network to which the contact belongs to + * string 'thumb' => The contact picture + * string 'click' => js code which is performed when clicking on the contact + * @param boolean $redirect If true try to use the redir url if it's possible + * @param string $class CSS class for the + * @param boolean $textmode If true display the contacts as text links + * if false display the contacts as picture links + * @return string Formatted html + * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws \ImagickException + */ public static function micropro($contact, $redirect = false, $class = '', $textmode = false) { // Use the contact URL if no address is available - if (!x($contact, "addr")) { + if (empty($contact['addr'])) { $contact["addr"] = $contact["url"]; } @@ -921,7 +844,7 @@ class HTML } // If there is some js available we don't need the url - if (x($contact, 'click')) { + if (!empty($contact['click'])) { $url = ''; } @@ -943,12 +866,12 @@ class HTML * @param string $s Search query. * @param string $id HTML id * @param string $url Search url. - * @param bool $save Show save search button. * @param bool $aside Display the search widgit aside. * * @return string Formatted HTML. + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function search($s, $id = 'search-box', $url = 'search', $save = false, $aside = true) + public static function search($s, $id = 'search-box', $url = 'search', $aside = true) { $mode = 'text'; @@ -958,12 +881,12 @@ class HTML $save_label = $mode === 'text' ? L10n::t('Save') : L10n::t('Follow'); $values = [ - '$s' => htmlspecialchars($s), + '$s' => $s, '$id' => $id, '$action_url' => $url, '$search_label' => L10n::t('Search'), '$save_label' => $save_label, - '$savedsearch' => local_user() && Feature::isEnabled(local_user(), 'savedsearch'), + '$savedsearch' => 'savedsearch', '$search_hint' => L10n::t('@name, !forum, #tags, content'), '$mode' => $mode ]; @@ -986,6 +909,7 @@ class HTML * Replace naked text hyperlink with HTML formatted hyperlink * * @param string $s + * @return string */ public static function toLink($s) { @@ -1002,6 +926,7 @@ class HTML * @param string $html * @param array $reasons * @return string + * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function applyContentFilter($html, array $reasons) { @@ -1009,7 +934,7 @@ class HTML $tpl = Renderer::getMarkupTemplate('wall/content_filter.tpl'); $html = Renderer::replaceMacros($tpl, [ '$reasons' => $reasons, - '$rnd' => random_string(8), + '$rnd' => Strings::getRandomHex(8), '$openclose' => L10n::t('Click to open/close'), '$html' => $html ]);