From 682b5838cce8d6c77004ee30ce60d202a010218f Mon Sep 17 00:00:00 2001 From: "roman.lesnikov@gmail.com" Date: Fri, 19 Apr 2024 10:46:58 +0300 Subject: [PATCH] #4695 - Embeds improvements --- api.php | 6 +- inc/classes/BxDolEmbed.php | 5 + inc/utils.inc.php | 45 +++++- install/sql/system.sql | 13 +- .../timeline/classes/BxTimelineModule.php | 18 +-- .../timeline/classes/BxTimelineTemplate.php | 2 + oembed.php | 45 ++---- template/scripts/BxBaseEmbedSystem.php | 152 ++++++++++++++++++ template/scripts_templ/BxTemplEmbedSystem.php | 21 +++ 9 files changed, 255 insertions(+), 52 deletions(-) create mode 100644 template/scripts/BxBaseEmbedSystem.php create mode 100644 template/scripts_templ/BxTemplEmbedSystem.php diff --git a/api.php b/api.php index 23e3400402..42afad3e82 100644 --- a/api.php +++ b/api.php @@ -10,8 +10,9 @@ bx_api_check_access(); -if (bx_get('cnf') ){ - echo getParam('sys_api_config'); +if (bx_get('cnf') ){ + $sCnf = getParam('sys_api_config'); + echo json_encode(['data' => $sCnf, 'hash' => md5($sCnf)]); exit(); } @@ -98,6 +99,7 @@ 'method' => $sMethod, 'params' => $aParams, 'data' => $mixedRet, + 'hash' => md5(getParam('sys_api_config')), ]; echo json_encode($aRv); diff --git a/inc/classes/BxDolEmbed.php b/inc/classes/BxDolEmbed.php index 56fd5ebbe4..f0e3e2070a 100644 --- a/inc/classes/BxDolEmbed.php +++ b/inc/classes/BxDolEmbed.php @@ -84,6 +84,11 @@ public function getData ($sUrl, $sTheme) $aData = json_decode($sData, true); return $aData; } + + public function getHtml ($sUrl, $sTheme) + { + // override this function in particular editor class + } } /** @} */ diff --git a/inc/utils.inc.php b/inc/utils.inc.php index 2b839e4bcd..492e3c6175 100644 --- a/inc/utils.inc.php +++ b/inc/utils.inc.php @@ -1188,17 +1188,27 @@ function bx_get_site_info_fix_relative_url ($sSourceUrl, $s) function bx_parse_html_tag ($sContent, $sTag, $sAttrNameName, $sAttrNameValue, $sAttrContentName, $sCharset = false, $bSpecialCharsDecode = true) { - if (!preg_match("/<{$sTag}\s+{$sAttrNameName}[='\" ]+{$sAttrNameValue}['\"]\s+{$sAttrContentName}[='\" ]+([^'>\"]*)['\"][^>]*>/i", $sContent, $aMatch) || !isset($aMatch[1])) - preg_match("/<{$sTag}\s+{$sAttrContentName}[='\" ]+([^'>\"]*)['\"]\s+{$sAttrNameName}[='\" ]+{$sAttrNameValue}['\"][^>]*>/i", $sContent, $aMatch); + // This regex is designed to be more flexible with attribute orders and spacing + $regex = "/<{$sTag}\s+(?:[^>]*?\s+)?{$sAttrNameName}\s*=\s*['\"]?{$sAttrNameValue}['\"]?\s+[^>]*{$sAttrContentName}\s*=\s*['\"]([^'\"]*)['\"][^>]*>/i"; + if (!preg_match($regex, $sContent, $aMatch)) { + // Try reversing the attribute order in case the first regex fails + $regex = "/<{$sTag}\s+(?:[^>]*?\s+)?{$sAttrContentName}\s*=\s*['\"]([^'\"]*)['\"]\s+[^>]*{$sAttrNameName}\s*=\s*['\"]?{$sAttrNameValue}['\"]?[^>]*>/i"; + preg_match($regex, $sContent, $aMatch); + } + // Extract the attribute content if available $s = isset($aMatch[1]) ? $aMatch[1] : ''; - if ($s && $sCharset) + // Optionally convert character encoding + if ($s && $sCharset) { $s = mb_convert_encoding($s, 'UTF-8', $sCharset); + } - if ($bSpecialCharsDecode) + // Optionally decode special HTML characters + if ($bSpecialCharsDecode) { $s = htmlspecialchars_decode($s); - + } + return $s; } @@ -2153,6 +2163,31 @@ function bx_linkify($text, $sAttrs = '', $bHtmlSpecialChars = false) return $text; } +function bx_linkify_embeded($text) +{ + $urlRegex = '/\b((https?:\/\/)|(www\.))((([0-9a-zA-Z_!~*\'().&=+$%-]+:)?[0-9a-zA-Z_!~*\'().&=+$%-]+@)?(([0-9]{1,3}\.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*\'()-]+\.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\.[a-zA-Z]{2,16})(:[0-9]{1,4})?((\/[0-9a-zA-Z_!~*\'().;?:@&=+$,%#-]*)*))/'; + preg_match_all($urlRegex, $text, $matches, PREG_SET_ORDER); + + // Reverse the matches to mimic JavaScript's reverse order processing + $matches = array_reverse($matches); + $sLink = ''; + foreach ($matches as $match) { + // Assuming APP_URL and UNA_URL are defined constants + if (!strstr($match[0], 'https://ci.una.io/') && !strstr($match[0], 'https://ci.una.io/')) { + $sLink = $match[0]; // Returns the first URL that doesn't include the restricted domains + } + } + + $text = ''; + if ($sLink){ + bx_import('BxDolEmbed'); + $oEmbed = BxDolEmbed::getObjectInstance('sys_system'); + $text = $oEmbed->getHtml($sLink, ''); + } + + return $text; +} + /** * Wrap in A tag links in HTML string, which aren't wrapped in A tag yet * @param $sHtmlOrig - HTML string diff --git a/install/sql/system.sql b/install/sql/system.sql index c13b16ca0a..fa71d2c186 100644 --- a/install/sql/system.sql +++ b/install/sql/system.sql @@ -75,6 +75,7 @@ CREATE TABLE `sys_objects_embeds` ( INSERT INTO `sys_objects_embeds` (`object`, `title`, `override_class_name`, `override_class_file`) VALUES +('sys_system', 'System', 'BxTemplEmbedSystem', ''), ('sys_embedly', 'Embedly', 'BxTemplEmbedEmbedly', ''), ('sys_iframely', 'Iframely', 'BxTemplEmbedIframely', ''), ('sys_oembed', 'Oembed', 'BxTemplEmbedOembed', ''); @@ -89,6 +90,16 @@ CREATE TABLE `sys_iframely_data` ( PRIMARY KEY (id) ); + + +CREATE TABLE `sys_embeded_data` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `url` varchar(255) DEFAULT NULL, + `data` text DEFAULT NULL, + `added` int(11) DEFAULT NULL, + `theme` varchar(10) DEFAULT NULL, + PRIMARY KEY (id) +); -- -------------------------------------------------------- @@ -505,7 +516,7 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex (@iCategoryId, 'useLikeOperator', '_adm_stg_cpt_option_use_like_operator', 'on', 'checkbox', '', '', '', 45), -(@iCategoryId, 'sys_embed_default', '_adm_stg_cpt_option_sys_embed_default', 'sys_oembed', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_options_embed_default";s:5:"class";s:13:"TemplServices";}', '', '', 79), +(@iCategoryId, 'sys_embed_default', '_adm_stg_cpt_option_sys_embed_default', 'sys_system', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_options_embed_default";s:5:"class";s:13:"TemplServices";}', '', '', 79), (@iCategoryId, 'sys_embedly_api_key', '_adm_stg_cpt_option_sys_embedly_api_key', '', 'digit', '', '', '', 80), (@iCategoryId, 'sys_iframely_api_key', '_adm_stg_cpt_option_sys_iframely_api_key', '', 'digit', '', '', '', 90); diff --git a/modules/boonex/timeline/classes/BxTimelineModule.php b/modules/boonex/timeline/classes/BxTimelineModule.php index af45ad3d62..dbb92159ad 100644 --- a/modules/boonex/timeline/classes/BxTimelineModule.php +++ b/modules/boonex/timeline/classes/BxTimelineModule.php @@ -2241,23 +2241,9 @@ public function serviceGetBlockItem() )); $aItemData = $this->getItemData($iItemId, $aParams); - - if (bx_is_api()){ - $aEventAdd = [ - 'author_data' => BxDolProfile::getData($aItemData['event']['object_owner_id']) - ]; - - $oMenuActions = BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_item_actions_all')); - if(!$oMenuActions) - $oMenuActions = BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_item_actions')); - if($oMenuActions !== false) { - $oMenuActions->setEvent($aItemData['event'], $aParams); - - $aEventAdd['menu_actions'] = $oMenuActions->getCodeAPI(); - } - - $aItemData['event'] = array_merge($aItemData['event'], $aEventAdd); + if (bx_is_api()){ + $aItemData['event'] = $this->_oTemplate->_getPostApi($aItemData['event'], $aParams); return [bx_api_get_block('feed_item', $aItemData)]; } diff --git a/modules/boonex/timeline/classes/BxTimelineTemplate.php b/modules/boonex/timeline/classes/BxTimelineTemplate.php index 71c6f7aa13..1f0b7b518f 100644 --- a/modules/boonex/timeline/classes/BxTimelineTemplate.php +++ b/modules/boonex/timeline/classes/BxTimelineTemplate.php @@ -1950,6 +1950,7 @@ public function _getPostApi(&$aEvent, $aParams = [], $aEventAdd = []) ]; } + if ($aEvent['content']['url']) $aEvent['url'] = bx_ltrim_str($aEvent['content']['url'], BX_DOL_URL_ROOT); if(!empty($aEvent['content']) && !empty($aEvent['content']['text'])) { @@ -1958,6 +1959,7 @@ public function _getPostApi(&$aEvent, $aParams = [], $aEventAdd = []) $sMethodPrepare .= 'BriefCard'; $aEvent['content']['text'] = $this->$sMethodPrepare($aEvent['content']['text'], $aEvent['id']); + $aEvent['content']['embed'] = bx_linkify_embeded($aEvent['content']['text']); } if(empty($aEventAdd['menu_actions'])) { diff --git a/oembed.php b/oembed.php index 41bf66a407..b59c3b85a5 100644 --- a/oembed.php +++ b/oembed.php @@ -11,38 +11,27 @@ require_once(BX_DIRECTORY_PATH_INC . "design.inc.php"); $aLinks = bx_get('l'); - bx_import('BxDolEmbed'); -$oEmbed = BxDolEmbed::getObjectInstance('sys_iframely'); +$oEmbed = BxDolEmbed::getObjectInstance('sys_system'); +/* + +echo bx_file_get_contents('https://publish.twitter.com/oembed?url=https://twitter.com/callmehouck/status/1780211820424569127', [], 'get', ['Accept: text/html'], $iHttpCode, [], 0, [CURLOPT_USERAGENT => false]);*/ + +//, bx_get('theme') if (bx_get('html')){ - echo '
' . $oEmbed->getDataHtml($aLinks, bx_get('theme')) . '
'; + print_r( $a);*/ + echo '
+ '.$oEmbed->getHtml($aLinks, ''); exit(); } echoJson($oEmbed->parseLinks($aLinks)); \ No newline at end of file diff --git a/template/scripts/BxBaseEmbedSystem.php b/template/scripts/BxBaseEmbedSystem.php new file mode 100644 index 0000000000..a00ed32637 --- /dev/null +++ b/template/scripts/BxBaseEmbedSystem.php @@ -0,0 +1,152 @@ +_sTableName = 'sys_embeded_data'; + parent::__construct ($aObject); + + if ($oTemplate) + $this->_oTemplate = $oTemplate; + else + $this->_oTemplate = BxDolTemplate::getInstance(); + } + + public function getLinkHTML ($sLink, $sTitle = '', $sMaxWidth = '') + { + $aAttrs = array( + 'title' => bx_html_attribute($sTitle), + ); + + // check for external link + if (strncmp(BX_DOL_URL_ROOT, $sLink, strlen(BX_DOL_URL_ROOT)) !== 0) { + $aAttrs['target'] = '_blank'; + + if (getParam('sys_add_nofollow') == 'on') + $aAttrs['rel'] = 'nofollow'; + } + + return $this->_oTemplate->parseHtmlByName('embed_iframely_link.html', array( + 'link' => $sLink, + 'title' => $sTitle, + 'attrs' => bx_convert_array2attrs($aAttrs), + 'width' => $sMaxWidth, + )); + } + + public function addProcessLinkMethod () + { + return " + "; + } + + + + public function getDataFromApi ($sUrl, $sTheme) + { + $a = bx_get_site_info($sUrl, array( + 'thumbnailUrl' => array('tag' => 'link', 'content_attr' => 'href'), + 'OGImage' => array('name_attr' => 'property', 'name' => 'og:image'), + 'icon' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'shortcut icon', 'content_attr' => 'href'), + 'icon2' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'icon', 'content_attr' => 'href'), + 'icon3' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'apple-touch-icon', 'content_attr' => 'href'), + )); + + $a['image'] = $a['OGImage'] ? $a['OGImage'] : $a['thumbnailUrl']; + $a['logo'] = $a['icon2'] ? $a['icon2'] : ($a['icon3'] ? $a['icon3'] : $a['icon']); + $a['url'] = $sUrl; + + + unset($a['OGImage']); + unset($a['thumbnailUrl']); + unset($a['icon2']); + unset($a['icon3']); + unset($a['icon']); + + if ($a['image']){ + $oStorage = BxDolStorage::getObjectInstance('sys_images'); + + $iMediaId = $oStorage->storeFileFromUrl($a['image'], false); + if ($iMediaId){ + $a['image'] = $oStorage->getFileUrlById($iMediaId); + } + } + + if ($a['image'] == ''){ + $b = json_decode(bx_file_get_contents("https://api.microlink.io/?url=" . $sUrl), true); + $a = [ + 'title' => $b['data']['title'], + 'description' => $b['data']['description'], + 'image' => $b['data']['image']['url'], + 'logo' => $b['data']['logo']['url'], + 'url' => $sUrl, + ]; + } + + $aU = parse_url($sUrl); + $a['domain'] = $aU['host']; + return json_encode($a); + } + + public function getDataHtml ($sUrl, $sTheme) + { + $aData = $this->getData($sUrl, $sTheme); + return $aData; + } + + public function getHtml ($sUrl, $sTheme) + { + $aData = $this->getData($sUrl, $sTheme); + + return ' +
+
+
+
+
'.$aData['title'].'
+
+ '.$aData['description'].' +
+
+ '.$aData['domain'].' +
+
+
+
'; + + } + + public function parseLinks(&$aLinks) { + $aResult = []; + if ($aLinks && is_array($aLinks)) { + $oEmbera = $this->getEmberaInstance(); + + foreach ($aLinks as $sLink) { + $sHtml = $oEmbera->autoEmbed($sLink); + //if nothing to change/embed then return empty string to not replace anything on a frontend + $aResult[] = ['html' => $sHtml != $sLink ? $sHtml : '']; + } + } + return $aResult; + } + +} + +/** @} */ diff --git a/template/scripts_templ/BxTemplEmbedSystem.php b/template/scripts_templ/BxTemplEmbedSystem.php new file mode 100644 index 0000000000..668699cb56 --- /dev/null +++ b/template/scripts_templ/BxTemplEmbedSystem.php @@ -0,0 +1,21 @@ +