3namespace Bitrix\Main\UrlPreview;
5use Bitrix\Main\ArgumentException;
6use Bitrix\Main\Config\Option;
8use Bitrix\Main\Security\Random;
9use Bitrix\Main\Security\Sign\Signer;
10use Bitrix\Main\Web\HttpClient;
11use Bitrix\Main\Web\Uri;
12use Bitrix\Main\Web\IpAddress;
13use Bitrix\Main\Web\Http\Response;
14use Bitrix\Main\File\Image;
15use Bitrix\Main\Web\MimeType;
20 const USER_AGENT =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 (Bitrix link preview)';
32 'youtube.com' =>
'youtube.com',
33 'youtu.be' =>
'youtu.be',
34 'youtube-nocookie.com' =>
'youtube-nocookie.com',
35 'www.youtube-nocookie.com' =>
'www.youtube-nocookie.com',
36 'vimeo.com' =>
'vimeo.com',
37 'player.vimeo.com' =>
'player.vimeo.com',
38 'rutube.ru' =>
'rutube.ru',
39 'www.rutube.ru' =>
'www.rutube.ru',
40 'facebook.com' =>
'facebook.com',
41 'fb.watch' =>
'fb.watch',
44 'instagram.com' =>
'instagram.com',
57 if (!static::isEnabled())
68 if ($reuseExistingMetadata)
74 $metadata = static::resolveTemporaryMetadata($metadata[
'ID']);
78 || !isset($metadata[
'DATE_EXPIRE'])
79 || $metadata[
'DATE_EXPIRE']->getTimestamp() > time()
84 if (static::refreshMetadata($metadata))
96 $metadataId = static::reserveIdForUrl(
$url);
97 $metadata = static::fetchUrlMetadata(
$url);
98 if (is_array($metadata) && !empty($metadata))
101 $metadata[
'ID'] =
$result->getId();
117 public static function showView($userField, $userFieldParams, &$cacheTag, $edit =
false)
123 if (!static::isEnabled())
128 $metadataId = (int)$userField[
'VALUE'][0];
135 $metadata = static::resolveTemporaryMetadata($metadata[
'ID']);
139 if (is_array($metadata))
141 $fullUrl = static::unfoldShortLink($metadata[
'URL']);
148 $className = $routeRecord[
'CLASS'];
149 $routeRecord[
'PARAMETERS'][
'URL'] = $metadata[
'URL'];
150 $parameters = $routeRecord[
'PARAMETERS'];
152 if ($edit && (!method_exists($className,
'checkUserReadAccess') || !$className::checkUserReadAccess($parameters, static::getCurrentUserId())))
157 if (method_exists($className,
'buildPreview'))
159 $metadata[
'HANDLER'] = $routeRecord;
160 $metadata[
'HANDLER'][
'BUILD_METHOD'] =
'buildPreview';
163 if (method_exists($className,
'getCacheTag'))
165 $cacheTag = $className::getCacheTag();
181 'bitrix:main.urlpreview',
184 'USER_FIELD' => $userField,
185 'METADATA' => is_array($metadata) ? $metadata : [],
186 'PARAMS' => $userFieldParams,
187 'EDIT' => ($edit ?
'Y' :
'N'),
188 'CHECK_ACCESS' => ($edit ?
'Y' :
'N'),
191 return ob_get_clean();
201 public static function showEdit($userField, $userFieldParams)
203 return static::showView($userField, $userFieldParams, $cacheTag,
true);
234 $metadata = static::getMetadataByUrl(
$url, $addIfNew, $reuseExistingMetadata);
235 if ($metadata ===
false)
246 if ($preview = static::getDynamicPreview(
$url))
248 $metadata[
'HTML'] = $preview;
267 if (!static::isEnabled())
281 while ($metadata = $queryResult->fetch())
285 $metadata[
'HTML'] = static::getDynamicPreview($metadata[
'URL'], $checkAccess,
$userId);
286 if ($metadata[
'HTML'] ===
false)
292 && isset($metadata[
'DATE_EXPIRE'])
293 && $metadata[
'DATE_EXPIRE']->getTimestamp() <= time()
296 $refreshResult = static::refreshMetadata($metadata);
302 $result[$metadata[
'ID']] = $metadata;
310 if (!static::isEnabled())
324 while ($metadata = $queryResult->fetch())
327 && isset($metadata[
'DATE_EXPIRE'])
328 && $metadata[
'DATE_EXPIRE']->getTimestamp() <= time()
331 $refreshResult = static::refreshMetadata($metadata);
337 $result[$metadata[
'ID']] = $metadata;
353 $id = $metadata[
'ID'];
378 if (!is_array($metadata))
385 $metadata[
'URL'] = static::normalizeUrl($metadata[
'URL']);
386 $metadata = static::fetchUrlMetadata($metadata[
'URL']);
387 if ($metadata ===
false)
402 if ($preview = static::getDynamicPreview($metadata[
'URL'], $checkAccess,
$userId))
404 $metadata[
'HTML'] = $preview;
418 $url = static::normalizeUrl($metadata[
'URL']);
419 $refreshedMetadata = static::fetchUrlMetadata(
$url);
420 if (!$refreshedMetadata)
427 $refreshedMetadata[
'ID'] = $metadata[
'ID'];
429 $metadata = $refreshedMetadata;
444 if ($routeRecord ===
false)
451 $className = $routeRecord[
'CLASS'];
452 $parameters = $routeRecord[
'PARAMETERS'];
453 $parameters[
'URL'] =
$url;
457 $userId = static::getCurrentUserId();
460 if ($checkAccess && (!method_exists($className,
'checkUserReadAccess') ||
$userId == 0 || !$className::checkUserReadAccess($parameters,
$userId)))
463 if (method_exists($className,
'buildPreview'))
465 $preview = $className::buildPreview($parameters);
466 return ($preview <>
'' ? $preview :
false);
481 return self::getUrlInfoFromExternal(
$url,
'getImAttach', $checkAccess,
$userId);
492 return self::getUrlInfoFromExternal(
$url,
'getImRich', $checkAccess,
$userId);
504 if ($routeRecord ===
false)
511 $className = $routeRecord[
'CLASS'];
512 $parameters = $routeRecord[
'PARAMETERS'];
516 $userId = static::getCurrentUserId();
519 return (method_exists($className,
'checkUserReadAccess') &&
$userId > 0 && $className::checkUserReadAccess($parameters,
$userId));
537 if (!is_string($imageUrl) && !is_null($imageUrl))
543 'select' =>
array(
'IMAGE',
'IMAGE_ID',
'EXTRA'),
544 'filter' =>
array(
'=ID' => $id)
547 if (isset($metadata[
'EXTRA'][
'IMAGES']))
549 $imageIndex = array_search($imageUrl, $metadata[
'EXTRA'][
'IMAGES']);
550 if ($imageIndex ===
false)
552 unset($metadata[
'EXTRA'][
'SELECTED_IMAGE']);
556 $metadata[
'EXTRA'][
'SELECTED_IMAGE'] = $imageIndex;
560 static::fetchImageMetadata($imageUrl, $metadata);
574 $result = Option::get(
'main',
'url_preview_enable',
'N') ===
'Y';
585 public static function sign($id)
588 return $signer->sign((
string)$id, static::SIGN_SALT);
595 if ($routeRecord ===
false)
602 $userId = static::getCurrentUserId();
607 $className = $routeRecord[
'CLASS'];
608 $parameters = $routeRecord[
'PARAMETERS'];
609 $parameters[
'URL'] =
$url;
611 if ($checkAccess && (!method_exists($className,
'checkUserReadAccess') ||
$userId == 0 || !$className::checkUserReadAccess($parameters,
$userId)))
614 if (method_exists($className,
$method))
616 return $className::$method($parameters);
628 $fullUrl = static::unfoldShortLink(
$url);
629 $uriParser =
new Uri($fullUrl);
630 if (static::isUrlLocal($uriParser))
642 $metadataRemote = static::getRemoteUrlMetadata($uriParser);
643 if (is_array($metadataRemote) && !empty($metadataRemote))
648 'TITLE' => $metadataRemote[
'TITLE'] ??
'',
649 'DESCRIPTION' => $metadataRemote[
'DESCRIPTION'] ??
'',
650 'IMAGE_ID' => $metadataRemote[
'IMAGE_ID'] ??
null,
651 'IMAGE' => $metadataRemote[
'IMAGE'] ??
null,
652 'EMBED' => $metadataRemote[
'EMBED'] ??
null,
653 'EXTRA' => $metadataRemote[
'EXTRA'] ??
null,
654 'DATE_EXPIRE' => $metadataRemote[
'DATE_EXPIRE'] ??
null,
659 if (isset($metadata[
'TYPE']))
674 if (
$uri->getHost() ==
'')
679 $host = \Bitrix\Main\Context::getCurrent()->getRequest()->getHttpHost();
690 ->setPrivateIp(
false)
692 ->setStreamTimeout(5)
693 ->setHeader(
'User-Agent', self::USER_AGENT)
703 if (!$httpClient->query(
'GET',
$uri->getUri()))
708 catch (\ErrorException)
713 if ($httpClient->getStatus() !== 200)
718 $peerIpAddress = $httpClient->getPeerAddress();
720 if ($httpClient->getHeaders()->getContentType() !==
'text/html')
722 $metadata = static::getFileMetadata($httpClient);
723 $metadata[
'EXTRA'][
'PEER_IP_ADDRESS'] = $peerIpAddress;
724 $metadata[
'EXTRA'][
'PEER_IP_PRIVATE'] = (
new IpAddress($peerIpAddress))->isPrivate();
729 $html = $httpClient->getResult();
732 $htmlDocument->setEncoding($httpClient->getCharset());
733 ParserChain::extractMetadata($htmlDocument);
734 $metadata = $htmlDocument->getMetadata();
736 if (is_array($metadata) && static::validateRemoteMetadata($metadata))
738 if (isset($metadata[
'IMAGE']))
740 static::fetchImageMetadata($metadata[
'IMAGE'], $metadata);
743 if (isset($metadata[
'DESCRIPTION']) && mb_strlen($metadata[
'DESCRIPTION']) > static::MAX_DESCRIPTION)
745 $metadata[
'DESCRIPTION'] = mb_substr($metadata[
'DESCRIPTION'], 0, static::MAX_DESCRIPTION);
748 if (!isset($metadata[
'EXTRA']) || !is_array($metadata[
'EXTRA']))
750 $metadata[
'EXTRA'] =
array();
753 $metadata[
'EXTRA'] = array_merge($metadata[
'EXTRA'],
array(
754 'PEER_IP_ADDRESS' => $peerIpAddress,
755 'PEER_IP_PRIVATE' => (
new IpAddress($peerIpAddress))->isPrivate(),
756 'X_FRAME_OPTIONS' => $httpClient->getHeaders()->get(
'X-Frame-Options',
true),
757 'EFFECTIVE_URL' => $httpClient->getEffectiveUrl(),
769 $tempPath = \CFile::GetTempName(
'', $tempFileName);
777 ->setPrivateIp(
false)
779 ->setStreamTimeout(5)
780 ->setBodyLengthMax(self::MAX_FILE_SIZE)
785 $httpClient->setHeader(
'Range',
'bytes=0-' . $range);
788 $urlComponents = parse_url(
$url);
789 $fileName = ($urlComponents && $urlComponents[
"path"] <>
'')
794 $tempPath = static::getTempPath(
$fileName);
798 if (!$httpClient->download(
$url, $tempPath))
803 catch (\ErrorException)
808 if ((
$name = $httpClient->getHeaders()->getFilename()) !==
null)
825 $localFile = \CFile::MakeFileArray($tempPath);
827 if (is_array($localFile))
829 $localFile[
'MODULE_ID'] =
'main';
835 if (\CFile::CheckImageFile($localFile, 0, 0, 0,
array(
"IMAGE")) ===
null)
837 $fileId = \CFile::SaveFile($localFile,
'urlpreview',
true);
841 return ($fileId ===
false ?
null : $fileId);
846 $saveImage = static::getOptionSaveImages();
848 $tempPath = static::downloadFile($imageUrl,
$fileName, ($saveImage ?
null : self::FILE_RANGE));
850 if ($tempPath !==
null)
855 $metadata[
'EXTRA'][
'IMAGE_INFO'] = [
856 'WIDTH' =>
$info->getWidth(),
857 'HEIGHT' =>
$info->getHeight(),
863 $metadata[
'IMAGE_ID'] = static::saveImage($tempPath,
$fileName);
864 $metadata[
'IMAGE'] =
null;
868 $metadata[
'IMAGE'] = $imageUrl;
869 $metadata[
'IMAGE_ID'] =
null;
882 if (str_starts_with(
$url,
'https://') || str_starts_with(
$url,
'http://'))
896 $url =
'http://'.$url;
900 $parsedUrl->setHost(mb_strtolower($parsedUrl->getHost()));
902 return $parsedUrl->getUri();
914 $result = Option::get(
'main',
'url_preview_save_images',
'N') ===
'Y';
926 $result = ((isset($metadata[
'TITLE']) && isset($metadata[
'IMAGE'])) || (isset($metadata[
'TITLE']) && isset($metadata[
'DESCRIPTION'])) || isset($metadata[
'EMBED']));
947 if (isset($cache[$shortUrl]))
949 return $cache[$shortUrl];
971 $mimeType = $httpHeaders->getContentType();
979 'ATTACHMENT' => strtolower($httpHeaders->getContentDisposition()) ===
'attachment' ?
'Y' :
'N',
980 'MIME_TYPE' => $mimeType,
982 'SIZE' => $httpHeaders->get(
'Content-Length')
986 if (MimeType::isImage($mimeType))
989 $tempPath = static::getTempPath(
$filename);
996 $result[
'EXTRA'][
'IMAGE_INFO'] = [
997 'WIDTH' =>
$info->getWidth(),
998 'HEIGHT' =>
$info->getHeight(),
1013 return (
new IpAddress($ipAddress))->isPrivate();
1025 $domainNameParts = explode(
'.',
$uri->getHost());
1026 if (is_array($domainNameParts) && ($partsCount =
count($domainNameParts)) >= 2)
1028 $domainName = $domainNameParts[$partsCount-2] .
'.' . $domainNameParts[$partsCount-1];
1029 $result = isset(static::$trustedHosts[$domainName]);
1042 $url = static::unfoldShortLink(
$url);
1044 if (static::isHostTrusted(
$uri) || static::isEnabled())
1047 $metadataId = static::reserveIdForUrl(
$url);
1048 $metadata = static::fetchUrlMetadata(
$url);
1049 if (is_array($metadata) && !empty($metadata))
1052 $metadata[
'ID'] =
$result->getId();
1058 if (!empty($metadata[
'EMBED']) && !str_contains($metadata[
'EMBED'],
'<iframe'))
1060 $url = static::getInnerFrameUrl($metadata[
'ID'], $metadata[
'EXTRA'][
'PROVIDER_NAME']);
1061 if (intval($metadata[
'EXTRA'][
'VIDEO_WIDTH']) <= 0)
1063 $metadata[
'EXTRA'][
'VIDEO_WIDTH'] = self::IFRAME_MAX_WIDTH;
1065 if (intval($metadata[
'EXTRA'][
'VIDEO_HEIGHT']) <= 0)
1067 $metadata[
'EXTRA'][
'VIDEO_HEIGHT'] = self::IFRAME_MAX_HEIGHT;
1069 $metadata[
'EMBED'] =
'<iframe src="'.$url.
'" allowfullscreen="" width="'.$metadata[
'EXTRA'][
'VIDEO_WIDTH'].
'" height="'.$metadata[
'EXTRA'][
'VIDEO_HEIGHT'].
'" frameborder="0"></iframe>';
1072 if ($metadata[
'EMBED'] || !empty($metadata[
'EXTRA'][
'VIDEO']))
1098 $result = static::normalizeUrl(
$uri->getLocator());
if(!Loader::includeModule('messageservice')) $provider
if(!is_object($USER)||! $USER->IsAuthorized()) $userId
static includeModule($moduleName)
static getRowById($id, array $parameters=[])
static getList(array $parameters=array())
static update($primary, array $data)
static dispatch(Uri $uri)
static getImAttach($url, $checkAccess=true, $userId=0)
static reserveIdForUrl($url)
static getRemoteUrlMetadata(Uri $uri)
static fetchImageMetadata(string $imageUrl, array &$metadata)
static normalizeUrl($url)
static getDynamicPreview($url, $checkAccess=true, $userId=0)
static refreshMetadata(array &$metadata)
static fetchVideoMetaData($url)
static saveImage(string $tempPath, ?string $fileName)
static getOptionSaveImages()
static getUrlInfoFromExternal($url, $method, $checkAccess=true, $userId=0)
static downloadFile(string $url, ?string &$fileName=null, ?int $range=null)
static getMetadataByIds(array $ids)
static getMetadataByUrl($url, $addIfNew=true, $reuseExistingMetadata=true)
static getMetadataAndHtmlByUrl($url, $addIfNew=true, $reuseExistingMetadata=true)
static getImRich($url, $checkAccess=true, $userId=0)
static showView($userField, $userFieldParams, &$cacheTag, $edit=false)
static isHostTrusted(Uri $uri)
static getCurrentUserId()
static checkDynamicPreviewAccess($url, $userId=0)
static getTempPath(string $fileName)
static fetchUrlMetadata($url)
static isIpAddressPrivate($ipAddress)
static getFileMetadata(HttpClient $client)
static getMetadataAndHtmlByIds(array $ids, $checkAccess=true, $userId=0)
static isUrlLocal(Uri $uri)
static showEdit($userField, $userFieldParams)
static resolveTemporaryMetadata($id, $checkAccess=true, $userId=0)
static setMetadataImage($id, $imageUrl)
static getInnerFrameUrl($id, $provider='')
static validateRemoteMetadata(array $metadata)
static unfoldShortLink($shortUrl)
static makeComponentPath($componentName)
if( $strWarning=="") if($strWarning=="") $componentPath
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
if(file_exists($_SERVER['DOCUMENT_ROOT'] . "/urlrewrite.php")) $uri
if($NS['step']==6) if( $NS[ 'step']==7) if(COption::GetOptionInt('main', 'disk_space', 0) > 0) $info
bx_basename($path, $ext="")
getLocalPath($path, $baseFolder="/bitrix")
$GLOBALS['____1690880296']
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)
</p ></td >< td valign=top style='border-top:none;border-left:none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;padding:0cm 2.0pt 0cm 2.0pt;height:9.0pt'>< p class=Normal align=center style='margin:0cm;margin-bottom:.0001pt;text-align:center;line-height:normal'>< a name=ТекстовоеПоле54 ></a ><?=($taxRate > count( $arTaxList) > 0) ? $taxRate."%"