Convert custom profile field URL values to rel="me" links

This commit is contained in:
Hypolite Petovan 2022-12-18 23:24:59 -05:00
parent 76e9c4daa2
commit 39607b20e2
3 changed files with 66 additions and 42 deletions

View File

@ -736,22 +736,22 @@ class HTML
'[youtube]$2[/youtube]', '[youtube]$2[/youtube]',
$s $s
); );
$s = preg_replace( $s = preg_replace(
'#<iframe[^>](.*?)https?://www.youtube.com/embed/([A-Za-z0-9\-_=]+)(.*?)</iframe>#ism', '#<iframe[^>](.*?)https?://www.youtube.com/embed/([A-Za-z0-9\-_=]+)(.*?)</iframe>#ism',
'[youtube]$2[/youtube]', '[youtube]$2[/youtube]',
$s $s
); );
$s = preg_replace( $s = preg_replace(
'#<iframe[^>](.*?)https?://player.vimeo.com/video/([0-9]+)(.*?)</iframe>#ism', '#<iframe[^>](.*?)https?://player.vimeo.com/video/([0-9]+)(.*?)</iframe>#ism',
'[vimeo]$2[/vimeo]', '[vimeo]$2[/vimeo]',
$s $s
); );
return $s; return $s;
} }
/** /**
* transform link href and img src from relative to absolute * transform link href and img src from relative to absolute
* *
@ -764,30 +764,30 @@ class HTML
if (empty($base)) { if (empty($base)) {
return $text; return $text;
} }
$base = rtrim($base, '/'); $base = rtrim($base, '/');
$base2 = $base . "/"; $base2 = $base . "/";
// Replace links // Replace links
$pattern = "/<a([^>]*) href=\"(?!http|https|\/)([^\"]*)\"/"; $pattern = "/<a([^>]*) href=\"(?!http|https|\/)([^\"]*)\"/";
$replace = "<a\${1} href=\"" . $base2 . "\${2}\""; $replace = "<a\${1} href=\"" . $base2 . "\${2}\"";
$text = preg_replace($pattern, $replace, $text); $text = preg_replace($pattern, $replace, $text);
$pattern = "/<a([^>]*) href=\"(?!http|https)([^\"]*)\"/"; $pattern = "/<a([^>]*) href=\"(?!http|https)([^\"]*)\"/";
$replace = "<a\${1} href=\"" . $base . "\${2}\""; $replace = "<a\${1} href=\"" . $base . "\${2}\"";
$text = preg_replace($pattern, $replace, $text); $text = preg_replace($pattern, $replace, $text);
// Replace images // Replace images
$pattern = "/<img([^>]*) src=\"(?!http|https|\/)([^\"]*)\"/"; $pattern = "/<img([^>]*) src=\"(?!http|https|\/)([^\"]*)\"/";
$replace = "<img\${1} src=\"" . $base2 . "\${2}\""; $replace = "<img\${1} src=\"" . $base2 . "\${2}\"";
$text = preg_replace($pattern, $replace, $text); $text = preg_replace($pattern, $replace, $text);
$pattern = "/<img([^>]*) src=\"(?!http|https)([^\"]*)\"/"; $pattern = "/<img([^>]*) src=\"(?!http|https)([^\"]*)\"/";
$replace = "<img\${1} src=\"" . $base . "\${2}\""; $replace = "<img\${1} src=\"" . $base . "\${2}\"";
$text = preg_replace($pattern, $replace, $text); $text = preg_replace($pattern, $replace, $text);
// Done // Done
return $text; return $text;
} }
@ -907,19 +907,6 @@ class HTML
return Renderer::replaceMacros(Renderer::getMarkupTemplate('searchbox.tpl'), $values); return Renderer::replaceMacros(Renderer::getMarkupTemplate('searchbox.tpl'), $values);
} }
/**
* Replace naked text hyperlink with HTML formatted hyperlink
*
* @param string $s
* @return string
*/
public static function toLink(string $s): string
{
$s = preg_replace("/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\'\%\$\!\+]*)/", ' <a href="$1" target="_blank" rel="noopener noreferrer">$1</a>', $s);
$s = preg_replace("/\<(.*?)(src|href)=(.*?)\&amp\;(.*?)\>/ism", '<$1$2=$3&$4>', $s);
return $s;
}
/** /**
* Given a HTML text and a set of filtering reasons, adds a content hiding header with the provided reasons * Given a HTML text and a set of filtering reasons, adds a content hiding header with the provided reasons
* *

View File

@ -26,7 +26,6 @@ use Friendica\Content\Feature;
use Friendica\Content\ForumManager; use Friendica\Content\ForumManager;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
@ -48,6 +47,7 @@ use Friendica\Profile\ProfileField\Repository\ProfileField;
use Friendica\Protocol\ActivityPub; use Friendica\Protocol\ActivityPub;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Strings;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
@ -204,7 +204,11 @@ class Profile extends BaseProfile
} }
if ($profile['homepage']) { if ($profile['homepage']) {
$basic_fields += self::buildField('homepage', $this->t('Homepage:'), HTML::toLink($profile['homepage'])); $basic_fields += self::buildField(
'homepage',
$this->t('Homepage:'),
$this->tryRelMe($profile['homepage']) ?: $profile['homepage']
);
} }
if ( if (
@ -245,7 +249,7 @@ class Profile extends BaseProfile
$custom_fields += self::buildField( $custom_fields += self::buildField(
'custom_' . $profile_field->order, 'custom_' . $profile_field->order,
$profile_field->label, $profile_field->label,
BBCode::convertForUriId($profile['uri-id'], $profile_field->value), $this->tryRelMe($profile_field->value) ?: BBCode::convertForUriId($profile['uri-id'], $profile_field->value),
'aprofile custom' 'aprofile custom'
); );
} }
@ -359,4 +363,19 @@ class Profile extends BaseProfile
return $htmlhead; return $htmlhead;
} }
/**
* Check if the input is an HTTP(S) link and returns a rel="me" link if yes, empty string if not
*
* @param string $input
* @return string
*/
private function tryRelMe(string $input): string
{
if (preg_match(Strings::onlyLinkRegEx(), trim($input))) {
return '<a href="' . trim($input) . '" target="_blank" rel="noopener noreferrer me">' . trim($input) . '</a>';
}
return '';
}
} }

View File

@ -380,29 +380,47 @@ class Strings
* Returns the regular expression string to match URLs in a given text * Returns the regular expression string to match URLs in a given text
* *
* @return string * @return string
* @see https://daringfireball.net/2010/07/improved_regex_for_matching_urls
*/ */
public static function autoLinkRegEx(): string public static function autoLinkRegEx(): string
{ {
return '@ return '@
(?<![=\'\]"/]) # Not preceded by [, =, \', ], ", / (?<![=\'\]"/]) # Not preceded by [, =, \', ], ", /
\b \b
( # Capture 1: entire matched URL ( # Capture 1: entire matched URL
https?:// # http or https protocol ' . self::linkRegEx() . '
)@xiu';
}
/**
* Returns the regular expression string to match only an HTTP URL
*
* @return string
*/
public static function onlyLinkRegEx(): string
{
return '@^' . self::linkRegEx() . '$@xiu';
}
/**
* @return string
* @see https://daringfireball.net/2010/07/improved_regex_for_matching_urls
*/
private static function linkRegEx(): string
{
return 'https?:// # http or https protocol
(?: (?:
[^/\s\xA0`!()\[\]{};:\'",<>?«»“”‘’.] # Domain can\'t start with a . [^/\s\xA0`!()\[\]{};:\'",<>?«»“”‘’.] # Domain can\'t start with a .
[^/\s\xA0`!()\[\]{};:\'",<>?«»“”‘’]+ # Domain can\'t end with a . [^/\s\xA0`!()\[\]{};:\'",<>?«»“”‘’]+ # Domain can\'t end with a .
\. \.
[^/\s\xA0`!()\[\]{};:\'".,<>?«»“”‘’]+/? # Followed by a slash [^/\s\xA0`!()\[\]{};:\'".,<>?«»“”‘’]+/? # Followed by a slash
) )
(?: # One or more: (?: # One or more:
[^\s\xA0()<>]+ # Run of non-space, non-()<> [^\s\xA0()<>]+ # Run of non-space, non-()<>
| # or | # or
\(([^\s\xA0()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels \(([^\s\xA0()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels
| # or | # or
[^\s\xA0`!()\[\]{};:\'".,<>?«»“”‘’] # not a space or one of these punct chars [^\s\xA0`!()\[\]{};:\'".,<>?«»“”‘’] # not a space or one of these punct chars
)* )*';
)@xiu';
} }
/** /**