TYPO3 CMS  TYPO3_8-7
TypoLinkGeneratorTest.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
23 
27 class TypoLinkGeneratorTest extends FunctionalTestCase
28 {
32  protected $coreExtensionsToLoad = ['frontend', 'workspaces'];
33 
38  'typo3/sysext/core/Tests/Functional/Fixtures/Frontend/AdditionalConfiguration.php' => 'typo3conf/AdditionalConfiguration.php',
39  ];
40 
42  'typo3/sysext/backend/Resources/Public/Images/Logo.png' => 'fileadmin/logo.png'
43  ];
44 
45  protected function setUp()
46  {
47  parent::setUp();
48 
49  $this->importDataSet(ORIGINAL_ROOT . 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/TypoLinkScenario.xml');
50  $this->setUpBackendUserFromFixture(1);
51  $this->setUpFileStorage();
52  $this->setUpFrontendRootPage(
53  1000,
54  [
55  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/TypoLinkGenerator.typoscript',
56  ]
57  );
58  }
59 
63  private function setUpFileStorage()
64  {
65  $storageRepository = new StorageRepository();
66  $storageId = $storageRepository->createLocalStorage(
67  'fileadmin/ (auto-created)',
68  'fileadmin/',
69  'relative',
70  'Default storage created in TypoLinkTest',
71  true
72  );
73  $storage = $storageRepository->findByUid($storageId);
74  (new Indexer($storage))->processChangesInStorages();
75  }
76 
80  public function linkIsGeneratedDataProvider(): array
81  {
82  $instructions = [
83  [
84  't3://email?email=mailto:user@example.org&other=other#other',
85  '<a href="mailto:user@example.org">user@example.org</a>',
86  ],
87  [
88  't3://email?email=user@example.org&other=other#other',
89  '<a href="mailto:user@example.org">user@example.org</a>',
90  ],
91  [
92  't3://email?email=user@example.org?subject=Hello%20World#other',
93  '<a href="mailto:user@example.org?subject=Hello World">user@example.org?subject=Hello World</a>',
94  ],
95  [
96  't3://file?uid=1&type=1&other=other#other',
97  '<a href="/fileadmin/logo.png">fileadmin/logo.png</a>',
98  ],
99  [
100  't3://file?identifier=1:/logo.png&other=other#other',
101  '<a href="/fileadmin/logo.png">fileadmin/logo.png</a>',
102  ],
103  [
104  't3://file?identifier=fileadmin/logo.png&other=other#other',
105  '<a href="/fileadmin/logo.png">fileadmin/logo.png</a>',
106  ],
107  [
108  't3://folder?identifier=fileadmin&other=other#other',
109  '<a href="/fileadmin/">fileadmin/</a>',
110  ],
111  [
112  't3://page?uid=1200&type=1&param-a=a&param-b=b#fragment',
113  '<a href="/index.php?id=1200&amp;type=1&amp;param-a=a&amp;param-b=b&amp;cHash=cd025eb18f2cb1fc578ab2273dbb137a#fragment">EN: Features</a>',
114  ],
115  [
116  't3://record?identifier=content&uid=10001&other=other#fragment',
117  '<a href="/index.php?id=1200#c10001">EN: Features</a>',
118  ],
119  [
120  't3://url?url=https://typo3.org%3f%26param-a=a%26param-b=b&other=other#other',
121  '<a href="https://typo3.org?&amp;param-a=a&amp;param-b=b">https://typo3.org?&amp;param-a=a&amp;param-b=b</a>',
122  ],
123  [
124  '1200,1 target class title &param-a=a',
125  '<a href="/index.php?id=1200&amp;type=1&amp;param-a=a&amp;cHash=c51665e6be366043d32971eeecca9495" title="title" target="target" class="class">EN: Features</a>'
126  ],
127  [
128  'user@example.org target class title &other=other',
129  '<a href="mailto:user@example.org" title="title" target="target" class="class">user@example.org</a>'
130  ],
131  ];
132  return $this->keysFromTemplate($instructions, '%1$s;');
133  }
134 
142  public function linkIsGenerated(string $parameter, string $expectation)
143  {
144  $this->assignTypoScriptConstant('typolink.parameter', $parameter, 1000);
145  $response = $this->getFrontendResponse(1100);
146  static::assertSame($expectation, $response->getContent());
147  }
148 
152  public function linkIsEncodedDataProvider(): array
153  {
154  $instructions = [
155  [
156  't3://email?email=mailto:<bad>thing(1)</bad>',
157  '<a href="mailto:&lt;bad&gt;thing(1)&lt;/bad&gt;">&lt;bad&gt;thing(1)&lt;/bad&gt;</a>',
158  ],
159  [
160  't3://email?email=mailto:<good%20a="a/"%20b="thing(1)">',
161  '<a href="mailto:&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;">&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;</a>',
162  ],
163  [
164  't3://email?email=<bad>thing(1)</bad>',
165  '<a href="mailto:&lt;bad&gt;thing(1)&lt;/bad&gt;">&lt;bad&gt;thing(1)&lt;/bad&gt;</a>',
166  ],
167  [
168  't3://email?email=<good%20a="a/"%20b="thing(1)">',
169  '<a href="mailto:&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;">&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;</a>',
170  ],
171  [
172  't3://folder?identifier=<any>',
173  '',
174  ],
175  [
176  't3://page?uid=<any>',
177  '',
178  ],
179  [
180  't3://record?identifier=content&uid=<any>',
181  '',
182  ],
183  [
184  't3://url?url=<bad>thing(1)</bad>',
185  '<a href="http://&lt;bad&gt;thing(1)&lt;/bad&gt;">http://&lt;bad&gt;thing(1)&lt;/bad&gt;</a>'
186  ],
187  [
188  't3://url?url=<good%20a="a/"%20b="thing(1)">',
189  '<a href="http://&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;">http://&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;</a>'
190  ],
191  [
192  't3://url?url=javascript:good()',
193  '<a ></a>'
194  ],
195  [
196  "t3://url?url=java\tscript:good()",
197  '<a href="http://java_script:good()">http://java_script:good()</a>'
198  ],
199  [
200  't3://url?url=java&#09;script:good()',
201  '<a href="http://java">http://java</a>'
202  ],
203  [
204  't3://url?url=javascript&colon;good()',
205  '<a href="http://javascript">http://javascript</a>'
206  ],
207  [
208  't3://url?url=data:text/html,<good>',
209  '<a ></a>'
210  ],
211  [
212  "t3://url?url=da\tsta:text/html,<good>",
213  '<a href="http://da_sta:text/html,&lt;good&gt;">http://da_sta:text/html,&lt;good&gt;</a>'
214  ],
215  [
216  't3://url?url=da&#09;ta:text/html,<good>',
217  '<a href="http://da">http://da</a>'
218  ],
219  [
220  't3://url?url=data&colon;text/html,<good>',
221  '<a href="http://data">http://data</a>'
222  ],
223  [
224  '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',
225  '<a href="http://&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;#115;&amp;#99;&amp;#114;&amp;#105;&amp;#112;&amp;#116;&amp;#58;&amp;#103;&amp;#111;&amp;#111;&amp;#100;&amp;#40;&amp;#41;">http://&amp;#106;&amp;#97;&amp;#118;&amp;#97;&amp;#115;&amp;#99;&amp;#114;&amp;#105;&amp;#112;&amp;#116;&amp;#58;&amp;#103;&amp;#111;&amp;#111;&amp;#100;&amp;#40;&amp;#41;</a>',
226  ],
227  [
228  '<bad>thing(1)</bad>',
229  '<a href="/&lt;bad&gt;thing(1)&lt;/bad&gt;">&lt;bad&gt;thing(1)&lt;/bad&gt;</a>'
230  ],
231  [
232  '<good%20a="a/"%20b="thing(1)">',
233  '<a href="/&lt;good%20a=&quot;a/&quot;%20b=&quot;thing(1)&quot;&gt;">&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;</a>'
234  ],
235  [
236  '<good/a="a/"/b="thing(1)"> target class title &other=other',
237  '<a href="/&lt;good/a=&quot;a/&quot;/b=&quot;thing(1)&quot;&gt;" title="title" target="target" class="class">&lt;good/a=&quot;a/&quot;/b=&quot;thing(1)&quot;&gt;</a>'
238  ],
239  [
240  'javascript:good()',
241  '',
242  ],
243  [
244  "java\tscript:good()",
245  '',
246  ],
247  [
248  'java&#09;script:good()',
249  '<a href="java&amp;#09;script:good()"></a>'
250  ],
251  [
252  'javascript&colon;good()',
253  ''
254  ],
255  [
256  'data:text/html,<good>',
257  '',
258  ],
259  [
260  "da\tta:text/html,<good>",
261  '',
262  ],
263  [
264  'da&#09;ta:text/html,<good>',
265  '<a href="da&amp;#09;ta:text/html,&lt;good&gt;"></a>',
266  ],
267  [
268  'data&colon;text/html,<good>',
269  '<a href="/data&amp;colon;text/html,&lt;good&gt;">data&amp;colon;text/html,&lt;good&gt;</a>',
270  ],
271  [
272  '%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',
273  '',
274  ],
275  [
276  '</> <"> <"> <">',
277  '<a href="/&lt;/&gt;" title="&lt;&quot;&gt;" target="&lt;&quot;&gt;" class="&lt;&quot;&gt;">&lt;/&gt;</a>',
278  ],
279  ];
280  return $this->keysFromTemplate($instructions, '%1$s;');
281  }
282 
290  public function linkIsEncodedPerDefault(string $parameter, string $expectation)
291  {
292  $this->assignTypoScriptConstant('typolink.parameter', $parameter, 1000);
293  $response = $this->getFrontendResponse(1100);
294  static::assertSame($expectation, $response->getContent());
295  }
296 
304  public function linkIsEncodedHavingParseFunc(string $parameter, string $expectation)
305  {
306  $this->setUpFrontendRootPage(
307  1000,
308  [
309  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/TypoLinkGenerator.typoscript',
310  'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/TypoLinkGenerator.libParseFunc.typoscript',
311  ]
312  );
313  $this->assignTypoScriptConstant('typolink.parameter', $parameter, 1000);
314  $response = $this->getFrontendResponse(1100);
315  static::assertSame($expectation, $response->getContent());
316  }
317 
321  public function linkToPageIsProcessedDataProvider(): array
322  {
323  return [
324  [
325  't3://page?uid=9911',
326  '<a href="/index.php?id=9911">&lt;good&gt;</a>',
327  false,
328  ],
329  [
330  't3://page?uid=9911',
331  '<a href="/index.php?id=9911"><good></a>',
332  true,
333  ],
334  [
335  't3://page?uid=9912',
336  '<a href="/index.php?id=9912">&lt;good a=&quot;a/&quot; b=&quot;thing(1)&quot;&gt;</a>',
337  false,
338  ],
339  [
340  't3://page?uid=9912',
341  '<a href="/index.php?id=9912"><good></a>',
342  true,
343  ],
344  [
345  't3://page?uid=9913',
346  '<a href="/index.php?id=9913">&lt;good%20a=&quot;a/&quot;%20b=&quot;thing(1)&quot;&gt;</a>',
347  false,
348  ],
349  [
350  't3://page?uid=9913',
351  '<a href="/index.php?id=9913">&lt;good%20a=&quot;a/&quot;%20b=&quot;thing(1)&quot;&gt;</a>',
352  true,
353  ],
354  [
355  't3://page?uid=9914',
356  '<a href="/index.php?id=9914">&lt;good/a=&quot;a/&quot;/b=&quot;thing(1)&quot;&gt;</a>',
357  false,
358  ],
359  [
360  't3://page?uid=9914',
361  '<a href="/index.php?id=9914">&lt;good/a=&quot;a/&quot;/b=&quot;thing(1)&quot;&gt;</a>',
362  true,
363  ],
364  [
365  't3://page?uid=9921',
366  '<a href="/index.php?id=9921">&lt;bad&gt;</a>',
367  false,
368  ],
369  [
370  't3://page?uid=9921',
371  '<a href="/index.php?id=9921">&lt;bad&gt;</a>',
372  true,
373  ],
374  ];
375  }
376 
385  public function linkToPageIsProcessed(string $parameter, string $expectation, bool $parseFuncEnabled)
386  {
387  $typoScriptFiles = ['typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/TypoLinkGenerator.typoscript'];
388  if ($parseFuncEnabled) {
389  $typoScriptFiles[] = 'typo3/sysext/frontend/Tests/Functional/SiteHandling/Fixtures/TypoLinkGenerator.libParseFunc.typoscript';
390  }
391 
392  $this->setUpFrontendRootPage(1000, $typoScriptFiles);
393  $this->assignTypoScriptConstant('typolink.parameter', $parameter, 1000);
394  $response = $this->getFrontendResponse(1100);
395  static::assertSame($expectation, $response->getContent());
396  }
397 
403  private function assignTypoScriptConstant(string $name, string $value, int $pageId)
404  {
406  $connection = GeneralUtility::makeInstance(ConnectionPool::class)
407  ->getConnectionForTable('sys_template');
408  $connection->update(
409  'sys_template',
410  ['constants' => sprintf("%s = %s\n", $name, $value)],
411  ['pid' => $pageId]
412  );
413  }
414 
430  private function keysFromTemplate(array $array, string $template, callable $callback = null): array
431  {
432  $keys = array_unique(
433  array_map(
434  function (array $values) use ($template, $callback) {
435  if ($callback !== null) {
436  $values = call_user_func($callback, $values);
437  }
438  return vsprintf($template, $values);
439  },
440  $array
441  )
442  );
443 
444  if (count($keys) !== count($array)) {
445  throw new \LogicException(
446  'Amount of generated keys does not match to item count.',
447  1534682840
448  );
449  }
450 
451  return array_combine($keys, $array);
452  }
453 }
static makeInstance($className,... $constructorArguments)