Commit 90c2181b authored by Benni Mack's avatar Benni Mack
Browse files

[BUGFIX] Use typolink consistently for makelinks functionality

TYPO3's "makelinks" functionality parses for in-text
external URLs and mailto links. This change uses
Typolink under the hood now to consistently check
for invalid content, and have the chance to use
all hooks in typolink for such links as well.

This way, typolink is used, but makelinks is
executed AFTER possible resolved <a> tags
avoiding double-calling parseFunc when <a> tag
processing is configured.

Resolves: #93012
Releases: main, 11.5
Change-Id: I574915e715793f6eccad1bdfc216e82e329179dd
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72871


Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Stefan Bürk's avatarStefan Bürk <stefan@buerk.tech>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 3b54b044
......@@ -3500,11 +3500,6 @@ class ContentObjectRenderer implements LoggerAwareInterface
if ($conf['userFunc'] ?? false) {
$data = $this->callUserFunction($conf['userFunc'], $conf['userFunc.'] ?? [], $data);
}
// Makelinks: (Before search-words as we need the links to be generated when searchwords go on...!)
if ($conf['makelinks'] ?? false) {
$data = $this->http_makelinks($data, $conf['makelinks.']['http.']);
$data = $this->mailto_makelinks($data, $conf['makelinks.']['mailto.'] ?? []);
}
}
// Search for tags to process in current data and
// call this method recursively if found
......@@ -3517,6 +3512,10 @@ class ContentObjectRenderer implements LoggerAwareInterface
}
}
}
if (!is_array($currentTag) && ($conf['makelinks'] ?? false)) {
$data = $this->http_makelinks($data, $conf['makelinks.']['http.'] ?? []);
$data = $this->mailto_makelinks($data, $conf['makelinks.']['mailto.'] ?? []);
}
$contentAccum[$contentAccumP] = isset($contentAccum[$contentAccumP])
? $contentAccum[$contentAccumP] . $data
: $data;
......@@ -3753,7 +3752,7 @@ class ContentObjectRenderer implements LoggerAwareInterface
}
/**
* Finds URLS in text and makes it to a real link.
* Finds URLs in text and makes it to a real link.
* Will find all strings prefixed with "http://" and "https://" in the $data string and make them into a link,
* linking to the URL we should have found.
*
......@@ -3765,7 +3764,6 @@ class ContentObjectRenderer implements LoggerAwareInterface
public function http_makelinks($data, $conf)
{
$parts = [];
$aTagParams = $this->getATagParams($conf);
foreach (['http://', 'https://'] as $scheme) {
$textpieces = explode($scheme, $data);
$pieces = count($textpieces);
......@@ -3780,7 +3778,7 @@ class ContentObjectRenderer implements LoggerAwareInterface
// Included '\/' 3/12
$parts[0] = substr($textpieces[$i], 0, $len);
$parts[1] = substr($textpieces[$i], $len);
$keep = $conf['keep'];
$keep = $conf['keep'] ?? '';
$linkParts = parse_url($scheme . $parts[0]);
$linktxt = '';
if (str_contains($keep, 'scheme')) {
......@@ -3796,22 +3794,9 @@ class ContentObjectRenderer implements LoggerAwareInterface
$linktxt = substr($linktxt, 0, -1);
}
}
$target = (string)$this->stdWrapValue('extTarget', $conf, $this->getTypoScriptFrontendController()->extTarget);
// check for jump URLs or similar
$linkUrl = $this->processUrl(UrlProcessorInterface::CONTEXT_COMMON, $scheme . $parts[0], $conf) ?? '';
$res = '<a href="' . htmlspecialchars($linkUrl) . '"'
. ($target !== '' ? ' target="' . htmlspecialchars($target) . '"' : '')
. $aTagParams . '>';
$wrap = (string)$this->stdWrapValue('wrap', $conf ?? []);
if ((string)($conf['ATagBeforeWrap'] ?? '') !== '') {
$res .= $this->wrap($linktxt, $wrap) . '</a>';
} else {
$res = $this->wrap($res . $linktxt . '</a>', $wrap);
}
$textstr .= $res . $parts[1];
$typolinkConfiguration = $conf;
$typolinkConfiguration['parameter'] = $parts[0];
$textstr .= $this->typoLink($linktxt, $typolinkConfiguration) . $parts[1];
} else {
$textstr .= $scheme . $textpieces[$i];
}
......@@ -3834,12 +3819,10 @@ class ContentObjectRenderer implements LoggerAwareInterface
{
$conf = (array)$conf;
$parts = [];
// http-split
$aTagParams = $this->getATagParams($conf);
// split by mailto logic
$textpieces = explode('mailto:', $data);
$pieces = count($textpieces);
$textstr = $textpieces[0];
$tsfe = $this->getTypoScriptFrontendController();
for ($i = 1; $i < $pieces; $i++) {
$len = strcspn($textpieces[$i], chr(32) . "\t" . CRLF);
if (trim(substr($textstr, -1)) === '' && $len) {
......@@ -3850,18 +3833,9 @@ class ContentObjectRenderer implements LoggerAwareInterface
$parts[0] = substr($textpieces[$i], 0, $len);
$parts[1] = substr($textpieces[$i], $len);
$linktxt = (string)preg_replace('/\\?.*/', '', $parts[0]);
[$mailToUrl, $linktxt, $attributes] = $this->getMailTo($parts[0], $linktxt);
$mailToUrl = $tsfe->spamProtectEmailAddresses === 'ascii' ? $mailToUrl : htmlspecialchars($mailToUrl);
$mailtoAttrs = GeneralUtility::implodeAttributes($attributes ?? [], true);
$aTagParams .= ($mailtoAttrs !== '' ? ' ' . $mailtoAttrs : '');
$res = '<a href="' . $mailToUrl . '"' . $aTagParams . '>';
$wrap = (string)$this->stdWrapValue('wrap', $conf);
if ((string)$conf['ATagBeforeWrap'] !== '') {
$res = $res . $this->wrap($linktxt, $wrap) . '</a>';
} else {
$res = $this->wrap($res . $linktxt . '</a>', $wrap);
}
$textstr .= $res . $parts[1];
$typolinkConfiguration = $conf;
$typolinkConfiguration['parameter'] = 'mailto:' . $parts[0];
$textstr .= $this->typoLink($linktxt, $typolinkConfiguration) . $parts[1];
} else {
$textstr .= 'mailto:' . $textpieces[$i];
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment