19 declare(strict_types=1);
33 private const URL_PATTERN =
'(^|[^[:alnum:]])(((https?:\/\/)|(www.))[^[:cntrl:][:space:]<>\'"]+)([^[:alnum:]]|$)';
46 return $this->
replaceMatches($from, fn(
int $startOfMatch,
int $endOfMatch,
string $url,
string $protocol):
string => (
48 $this->
replace($url, $protocol) :
58 while (
null !== ($matches = $this->
match(self::URL_PATTERN, substr($from, $endOfLastMatch)))) {
59 $startOfMatch = $endOfLastMatch + strpos(substr($from, $endOfLastMatch), $matches[0]);
60 $endOfMatch = $startOfMatch + strlen($matches[1] . $matches[2]);
62 $stringParts[] = substr($from, $endOfLastMatch, $startOfMatch - $endOfLastMatch);
63 $stringParts[] = $matches[1] . $replace($startOfMatch, $endOfMatch, $matches[2], $matches[4]);
65 $endOfLastMatch = $endOfMatch;
68 $stringParts[] = substr($from, $endOfLastMatch);
70 return implode(
'', $stringParts);
73 private function regexPos(
string $regexp,
string $string):
int 75 $matches = $this->
match($regexp, $string);
76 if (
null !== $matches) {
77 return strpos($string, $matches[0]);
80 return strlen($string);
89 if (!is_string($maybeHTML)) {
94 private function shouldReplace(
string $maybeHTML,
int $startOfMatch,
int $endOfMatch): bool
96 $isNotInAnchor = $this->
regexPos(
'<a.*</a>', substr($maybeHTML, $endOfMatch)) <= $this->
regexPos(
'</a>', substr($maybeHTML, $endOfMatch));
97 $isNotATagAttribute =
null === $this->
match(
'^[^>]*[[:space:]][[:alpha:]]+<', strrev(substr($maybeHTML, 0, $startOfMatch)));
99 return $isNotInAnchor && $isNotATagAttribute;
106 private function match(
string $pattern,
string $haystack): ?array
108 $pattern = str_replace(
'@',
'\@', $pattern);
109 return 1 === preg_match(
'@' . $pattern .
'@', $haystack, $matches) ? $matches :
null;
114 $maybeProtocol = !$protocol ?
'https://' :
'';
116 '<a%s href="%s">%s</a>',
118 $maybeProtocol . $url,
125 if ($this->open_in_new_tab) {
126 return ' target="_blank" rel="noopener"';
transform($from)
Perform the transformation.
trait DeriveInvokeFromTransform
trait DeriveApplyToFromTransform
requireString($maybeHTML)
replace(string $url, string $protocol)
match(string $pattern, string $haystack)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
replaceMatches(string $from, callable $replace)
__construct($open_in_new_tab=true)
regexPos(string $regexp, string $string)
shouldReplace(string $maybeHTML, int $startOfMatch, int $endOfMatch)