2 declare(strict_types = 1);
26 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory;
27 use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter;
28 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\AbstractInstruction;
29 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\ArrayValueInstruction;
30 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Internal\TypoScriptInstruction;
31 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
32 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequestContext;
33 use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalResponse;
43 private $siteTitle =
'A Company that Manufactures Everything Inc';
51 'typo3/sysext/backend/Resources/Public/Images/Logo.png' =>
'fileadmin/logo.png'
56 parent::setUpBeforeClass();
57 static::initializeDatabaseSnapshot();
62 static::destroyDatabaseSnapshot();
63 parent::tearDownAfterClass();
66 protected function setUp()
71 $this->internalRequestContext = (
new InternalRequestContext())
72 ->withGlobalSettings([
'TYPO3_CONF_VARS' => static::TYPO3_CONF_VARS]);
84 $this->withDatabaseSnapshot(
function () {
91 $backendUser = $this->setUpBackendUserFromFixture(1);
94 $scenarioFile = __DIR__ .
'/Fixtures/TypoLinkScenario.yaml';
95 $factory = DataHandlerFactory::fromYamlFile($scenarioFile);
96 $writer = DataHandlerWriter::withBackendUser($backendUser);
97 $writer->invokeFactory($factory);
98 static::failIfArrayIsNotEmpty(
103 $connection = GeneralUtility::makeInstance(ConnectionPool::class)
104 ->getConnectionForTable(
'pages');
108 [
'TSconfig' => implode(chr(10), [
109 'TCEMAIN.linkHandler.content {',
110 ' configuration.table = tt_content',
117 $this->setUpFrontendRootPage(
120 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/LinkGenerator.typoscript',
123 'title' =>
'ACME Root',
124 'sitetitle' => $this->siteTitle,
134 $storageRepository =
new StorageRepository();
135 $storageId = $storageRepository->createLocalStorage(
136 'fileadmin/ (auto-created)',
139 'Default storage created in TypoLinkTest',
142 $storage = $storageRepository->findByUid($storageId);
143 (
new Indexer($storage))->processChangesInStorages();
148 unset($this->internalRequestContext);
159 't3://email?email=mailto:user@example.org&other=other#other',
160 '<a href="mailto:user@example.org">user@example.org</a>',
163 't3://email?email=user@example.org&other=other#other',
164 '<a href="mailto:user@example.org">user@example.org</a>',
167 't3://email?email=user@example.org?subject=Hello%20World#other',
168 '<a href="mailto:user@example.org?subject=Hello World">user@example.org?subject=Hello World</a>',
171 't3://file?uid=1&type=1&other=other#other',
172 '<a href="/fileadmin/logo.png#other">fileadmin/logo.png</a>',
175 't3://file?identifier=1:/logo.png&other=other#other',
176 '<a href="/fileadmin/logo.png#other">fileadmin/logo.png</a>',
179 't3://file?identifier=fileadmin/logo.png&other=other#other',
180 '<a href="/fileadmin/logo.png#other">fileadmin/logo.png</a>',
183 't3://folder?identifier=fileadmin&other=other#other',
184 '<a href="/fileadmin/#other">fileadmin/</a>',
187 't3://page?uid=1200&type=1¶m-a=a¶m-b=b#fragment',
188 '<a href="/features?param-a=a&param-b=b&type=1&cHash=92aa5284d0ad18f7934fe94b52f6c1a5#fragment">EN: Features</a>',
191 't3://record?identifier=content&uid=10001&other=other#fragment',
192 '<a href="/features#c10001">EN: Features</a>',
195 't3://url?url=https://typo3.org%3f%26param-a=a%26param-b=b&other=other#other',
196 '<a href="https://typo3.org?&param-a=a&param-b=b">https://typo3.org?&param-a=a&param-b=b</a>',
199 '1200,1 target class title ¶m-a=a',
200 '<a href="/features?param-a=a&type=1&cHash=62ac35c73f425af5e13cfff14c04424e" title="title" target="target" class="class">EN: Features</a>'
203 'user@example.org target class title &other=other',
204 '<a href="mailto:user@example.org" title="title" target="target" class="class">user@example.org</a>'
207 return $this->keysFromTemplate($instructions,
'%1$s;');
220 self::assertSame($expectation, (
string)$response->getBody());
230 't3://email?email=mailto:<bad>thing(1)</bad>',
231 '<a href="mailto:<bad>thing(1)</bad>"><bad>thing(1)</bad></a>',
234 't3://email?email=mailto:<good%20a="a/"%20b="thing(1)">',
235 '<a href="mailto:<good a="a/" b="thing(1)">"><good a="a/" b="thing(1)"></a>',
238 't3://email?email=<bad>thing(1)</bad>',
239 '<a href="mailto:<bad>thing(1)</bad>"><bad>thing(1)</bad></a>',
242 't3://email?email=<good%20a="a/"%20b="thing(1)">',
243 '<a href="mailto:<good a="a/" b="thing(1)">"><good a="a/" b="thing(1)"></a>',
246 't3://folder?identifier=<any>',
250 't3://page?uid=<any>',
254 't3://record?identifier=content&uid=<any>',
258 't3://url?url=<bad>thing(1)</bad>',
259 '<a href="http://<bad>thing(1)</bad>">http://<bad>thing(1)</bad></a>'
262 't3://url?url=<good%20a="a/"%20b="thing(1)">',
263 '<a href="http://<good a="a/" b="thing(1)">">http://<good a="a/" b="thing(1)"></a>'
266 't3://url?url=javascript:good()',
270 "t3://url?url=java\tscript:good()",
271 '<a href="http://java_script:good()">http://java_script:good()</a>'
274 't3://url?url=java	script:good()',
275 '<a href="http://java">http://java</a>'
278 't3://url?url=javascript:good()',
279 '<a href="http://javascript">http://javascript</a>'
282 't3://url?url=data:text/html,<good>',
286 "t3://url?url=da\tsta:text/html,<good>",
287 '<a href="http://da_sta:text/html,<good>">http://da_sta:text/html,<good></a>'
290 't3://url?url=da	ta:text/html,<good>',
291 '<a href="http://da">http://da</a>'
294 't3://url?url=data:text/html,<good>',
295 '<a href="http://data">http://data</a>'
298 't3://url?url=%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2358%3B%26%23103%3B%26%23111%3B%26%23111%3B%26%23100%3B%26%2340%3B%26%2341%3B',
299 '<a href="http://&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#103;&#111;&#111;&#100;&#40;&#41;">http://&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#103;&#111;&#111;&#100;&#40;&#41;</a>',
302 '<bad>thing(1)</bad>',
303 '<a href="/<bad>thing(1)</bad>"><bad>thing(1)</bad></a>'
306 '<good%20a="a/"%20b="thing(1)">',
307 '<a href="/<good%20a="a/"%20b="thing(1)">"><good a="a/" b="thing(1)"></a>'
310 '<good/a="a/"/b="thing(1)"> target class title &other=other',
311 '<a href="/<good/a="a/"/b="thing(1)">" title="title" target="target" class="class"><good/a="a/"/b="thing(1)"></a>'
318 "java\tscript:good()",
322 'java	script:good()',
323 '<a href="java&#09;script:good()"></a>'
326 'javascript:good()',
330 'data:text/html,<good>',
334 "da\tta:text/html,<good>",
338 'da	ta:text/html,<good>',
339 '<a href="da&#09;ta:text/html,<good>"></a>',
342 'data:text/html,<good>',
343 '<a href="/data&colon;text/html,<good>">data&colon;text/html,<good></a>',
346 '%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3B%26%23115%3B%26%2399%3B%26%23114%3B%26%23105%3B%26%23112%3B%26%23116%3B%26%2358%3B%26%23103%3B%26%23111%3B%26%23111%3B%26%23100%3B%26%2340%3B%26%2341%3B',
351 '<a href="/</>" title="<">" target="<">" class="<">"></></a>',
354 return $this->keysFromTemplate($instructions,
'%1$s;');
367 self::assertSame($expectation, (
string)$response->getBody());
380 'allowTags' =>
'good',
382 'nonTypoTagStdWrap.' => [
386 'allowedAttribs' => 0,
392 self::assertSame($expectation, (
string)$response->getBody());
402 't3://page?uid=9911',
403 '<a href="/test/good"><good></a>',
407 't3://page?uid=9911',
408 '<a href="/test/good"><good></good></a>',
412 't3://page?uid=9912',
413 '<a href="/test/good-a-b-spaced"><good a="a/" b="thing(1)"></a>',
417 't3://page?uid=9912',
418 '<a href="/test/good-a-b-spaced"><good></good></a>',
422 't3://page?uid=9913',
423 '<a href="/test/good-a-b-enc-a"><good%20a="a/"%20b="thing(1)"></a>',
427 't3://page?uid=9913',
428 '<a href="/test/good-a-b-enc-a"><good%20a="a/"%20b="thing(1)"></a>',
432 't3://page?uid=9914',
433 '<a href="/test/good-a-b-enc-b"><good/a="a/"/b="thing(1)"></a>',
437 't3://page?uid=9914',
438 '<a href="/test/good-a-b-enc-b"><good/a="a/"/b="thing(1)"></a>',
442 't3://page?uid=9921',
443 '<a href="/test/bad"><bad></a>',
447 't3://page?uid=9921',
448 '<a href="/test/bad"><bad></a>',
465 if ($parseFuncEnabled) {
467 'allowTags' =>
'good',
469 'nonTypoTagStdWrap.' => [
473 'allowedAttribs' => 0,
478 'htmlSanitize' =>
true,
480 'build' => TestSanitizerBuilder::class,
485 self::assertSame($expectation, (
string)$response->getBody());
493 private function invokeTypoLink(
string $parameter, AbstractInstruction ...$instructions): InternalResponse
495 $sourcePageId = 1100;
496 $targetPageId = 1200;
498 $request = (
new InternalRequest(
'https://acme.us/'))
499 ->withPageId($sourcePageId)
503 'parameter' => $targetPageId,
505 'data' =>
'field:uid',
510 'parameter' => $parameter,
515 if (count($instructions) > 0) {
519 return $this->executeFrontendRequest($request, $this->internalRequestContext);
528 return (
new ArrayValueInstruction(LinkHandlingController::class))
532 'typolink.' => $typoLink
543 return (
new TypoScriptInstruction(TemplateService::class))
549 'typolink.' => $typoLink,
562 return (
new TypoScriptInstruction(TemplateService::class))
565 'parseFunc.' => array_replace_recursive(
571 'extTarget' =>
'_blank',
580 'nonTypoTagStdWrap.' => [
583 'keepNonMatchedTags' => 1,
584 'htmlSpecialChars' => 2,