3 declare(strict_types=1);
34 private const URL_PATTERN =
'(^|[^[:alnum:]])(((https?:\/\/)|(www.))[^[:cntrl:][:space:]<>\'"]+)([^[:alnum:]]|$)';
47 return $this->
replaceMatches($from, fn (
int $startOfMatch,
int $endOfMatch,
string $url,
string $protocol):
string => (
49 $this->
replace($url, $protocol) :
59 while (null !== ($matches = $this->
match(self::URL_PATTERN, substr($from, $endOfLastMatch)))) {
60 $startOfMatch = $endOfLastMatch + strpos(substr($from, $endOfLastMatch), $matches[0]);
61 $endOfMatch = $startOfMatch + strlen($matches[1] . $matches[2]);
63 $stringParts[] = substr($from, $endOfLastMatch, $startOfMatch - $endOfLastMatch);
64 $stringParts[] = $matches[1] . $replace($startOfMatch, $endOfMatch, $matches[2], $matches[4]);
66 $endOfLastMatch = $endOfMatch;
69 $stringParts[] = substr($from, $endOfLastMatch);
71 return implode(
'', $stringParts);
74 private function regexPos(
string $regexp,
string $string):
int 76 $matches = $this->
match($regexp, $string);
77 if (null !== $matches) {
78 return strpos($string, $matches[0]);
81 return strlen($string);
90 if (!is_string($maybeHTML)) {
95 private function shouldReplace(
string $maybeHTML,
int $startOfMatch,
int $endOfMatch): bool
97 $isNotInAnchor = $this->
regexPos(
'<a.*</a>', substr($maybeHTML, $endOfMatch)) <= $this->
regexPos(
'</a>', substr($maybeHTML, $endOfMatch));
98 $isNotATagAttribute = null === $this->
match(
'^[^>]*[[:space:]][[:alpha:]]+<', strrev(substr($maybeHTML, 0, $startOfMatch)));
100 return $isNotInAnchor && $isNotATagAttribute;
107 private function match(
string $pattern,
string $haystack): ?array
109 $pattern = str_replace(
'@',
'\@', $pattern);
110 return 1 === preg_match(
'@' . $pattern .
'@', $haystack, $matches) ? $matches : null;
115 $maybeProtocol = !$protocol ?
'https://' :
'';
117 '<a%s href="%s">%s</a>',
119 $maybeProtocol . $url,
126 if ($this->open_in_new_tab) {
127 return ' target="_blank" rel="noopener"';
transform($from)
Perform the transformation.
requireString($maybeHTML)
trait DeriveApplyToFromTransform
replace(string $url, string $protocol)
match(string $pattern, string $haystack)
trait DeriveInvokeFromTransform
replaceMatches(string $from, callable $replace)
__construct($open_in_new_tab=true)
regexPos(string $regexp, string $string)
shouldReplace(string $maybeHTML, int $startOfMatch, int $endOfMatch)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...