TYPO3 CMS  TYPO3_7-6
GeneralUtilityTest.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
29 
34 {
38  protected $singletonInstances = [];
39 
40  protected function setUp()
41  {
45  $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] = GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL;
46  $this->singletonInstances = GeneralUtility::getSingletonInstances();
47  }
48 
49  protected function tearDown()
50  {
51  GeneralUtility::resetSingletonInstances($this->singletonInstances);
52  parent::tearDown();
53  }
54 
61  public function isConnected()
62  {
63  $isConnected = false;
64  $connected = @fsockopen('typo3.org', 80);
65  if ($connected) {
66  $isConnected = true;
67  fclose($connected);
68  }
69  return $isConnected;
70  }
71 
79  protected function getVirtualTestDir($prefix = 'root_')
80  {
81  $root = vfsStream::setup();
82  $path = $root->url() . '/typo3temp/' . $this->getUniqueId($prefix);
84  return $path;
85  }
86 
88  // Tests concerning _GP
90 
94  public function canRetrieveValueWithGP($key, $get, $post, $expected)
95  {
96  $_GET = $get;
97  $_POST = $post;
98  $this->assertSame($expected, GeneralUtility::_GP($key));
99  }
100 
107  public function gpDataProvider()
108  {
109  return [
110  'No key parameter' => [null, [], [], null],
111  'Key not found' => ['cake', [], [], null],
112  'Value only in GET' => ['cake', ['cake' => 'li\\e'], [], 'li\\e'],
113  'Value only in POST' => ['cake', [], ['cake' => 'l\\ie'], 'l\\ie'],
114  'Value from POST preferred over GET' => ['cake', ['cake' => 'is a'], ['cake' => '\\lie'], '\\lie'],
115  'Value can be an array' => [
116  'cake',
117  ['cake' => ['is a' => 'l\\ie']],
118  [],
119  ['is a' => 'l\\ie']
120  ]
121  ];
122  }
123 
125  // Tests concerning _GPmerged
127 
131  public function gpMergedWillMergeArraysFromGetAndPost($get, $post, $expected)
132  {
133  $_POST = $post;
134  $_GET = $get;
135  $this->assertEquals($expected, GeneralUtility::_GPmerged('cake'));
136  }
137 
143  public function gpMergedDataProvider()
144  {
145  $fullDataArray = ['cake' => ['a' => 'is a', 'b' => 'lie']];
146  $postPartData = ['cake' => ['b' => 'lie']];
147  $getPartData = ['cake' => ['a' => 'is a']];
148  $getPartDataModified = ['cake' => ['a' => 'is not a']];
149  return [
150  'Key doesn\' exist' => [['foo'], ['bar'], []],
151  'No POST data' => [$fullDataArray, [], $fullDataArray['cake']],
152  'No GET data' => [[], $fullDataArray, $fullDataArray['cake']],
153  'POST and GET are merged' => [$getPartData, $postPartData, $fullDataArray['cake']],
154  'POST is preferred over GET' => [$getPartDataModified, $fullDataArray, $fullDataArray['cake']]
155  ];
156  }
157 
159  // Tests concerning _GET / _POST
161 
167  public function getAndPostDataProvider()
168  {
169  return [
170  'Requested input data doesn\'t exist' => ['cake', [], null],
171  'No key will return entire input data' => [null, ['cake' => 'l\\ie'], ['cake' => 'l\\ie']],
172  'Can retrieve specific input' => ['cake', ['cake' => 'l\\ie', 'foo'], 'l\\ie'],
173  'Can retrieve nested input data' => ['cake', ['cake' => ['is a' => 'l\\ie']], ['is a' => 'l\\ie']]
174  ];
175  }
176 
181  public function canRetrieveGlobalInputsThroughGet($key, $get, $expected)
182  {
183  $_GET = $get;
184  $this->assertSame($expected, GeneralUtility::_GET($key));
185  }
186 
191  public function canRetrieveGlobalInputsThroughPost($key, $post, $expected)
192  {
193  $_POST = $post;
194  $this->assertSame($expected, GeneralUtility::_POST($key));
195  }
196 
198  // Tests concerning _GETset
200 
204  public function canSetNewGetInputValues($input, $key, $expected, $getPreset = [])
205  {
206  $_GET = $getPreset;
207  GeneralUtility::_GETset($input, $key);
208  $this->assertSame($expected, $_GET);
209  }
210 
216  public function getSetDataProvider()
217  {
218  return [
219  'No input data used without target key' => [null, null, []],
220  'No input data used with target key' => ['', 'cake', ['cake' => '']],
221  'No target key used with string input data' => ['data', null, []],
222  'No target key used with array input data' => [['cake' => 'lie'], null, ['cake' => 'lie']],
223  'Target key and string input data' => ['lie', 'cake', ['cake' => 'lie']],
224  'Replace existing GET data' => ['lie', 'cake', ['cake' => 'lie'], ['cake' => 'is a lie']],
225  'Target key pointing to sublevels and string input data' => ['lie', 'cake|is', ['cake' => ['is' => 'lie']]],
226  'Target key pointing to sublevels and array input data' => [['a' => 'lie'], 'cake|is', ['cake' => ['is' => ['a' => 'lie']]]]
227  ];
228  }
229 
231  // Tests concerning cmpIPv4
233 
238  public static function cmpIPv4DataProviderMatching()
239  {
240  return [
241  'host with full IP address' => ['127.0.0.1', '127.0.0.1'],
242  'host with two wildcards at the end' => ['127.0.0.1', '127.0.*.*'],
243  'host with wildcard at third octet' => ['127.0.0.1', '127.0.*.1'],
244  'host with wildcard at second octet' => ['127.0.0.1', '127.*.0.1'],
245  '/8 subnet' => ['127.0.0.1', '127.1.1.1/8'],
246  '/32 subnet (match only name)' => ['127.0.0.1', '127.0.0.1/32'],
247  '/30 subnet' => ['10.10.3.1', '10.10.3.3/30'],
248  'host with wildcard in list with IPv4/IPv6 addresses' => ['192.168.1.1', '127.0.0.1, 1234:5678::/126, 192.168.*'],
249  'host in list with IPv4/IPv6 addresses' => ['192.168.1.1', '::1, 1234:5678::/126, 192.168.1.1'],
250  ];
251  }
252 
257  public function cmpIPv4ReturnsTrueForMatchingAddress($ip, $list)
258  {
259  $this->assertTrue(GeneralUtility::cmpIPv4($ip, $list));
260  }
261 
267  public static function cmpIPv4DataProviderNotMatching()
268  {
269  return [
270  'single host' => ['127.0.0.1', '127.0.0.2'],
271  'single host with wildcard' => ['127.0.0.1', '127.*.1.1'],
272  'single host with /32 subnet mask' => ['127.0.0.1', '127.0.0.2/32'],
273  '/31 subnet' => ['127.0.0.1', '127.0.0.2/31'],
274  'list with IPv4/IPv6 addresses' => ['127.0.0.1', '10.0.2.3, 192.168.1.1, ::1'],
275  'list with only IPv6 addresses' => ['10.20.30.40', '::1, 1234:5678::/127']
276  ];
277  }
278 
283  public function cmpIPv4ReturnsFalseForNotMatchingAddress($ip, $list)
284  {
285  $this->assertFalse(GeneralUtility::cmpIPv4($ip, $list));
286  }
287 
289  // Tests concerning cmpIPv6
291 
296  public static function cmpIPv6DataProviderMatching()
297  {
298  return [
299  'empty address' => ['::', '::'],
300  'empty with netmask in list' => ['::', '::/0'],
301  'empty with netmask 0 and host-bits set in list' => ['::', '::123/0'],
302  'localhost' => ['::1', '::1'],
303  'localhost with leading zero blocks' => ['::1', '0:0::1'],
304  'host with submask /128' => ['::1', '0:0::1/128'],
305  '/16 subnet' => ['1234::1', '1234:5678::/16'],
306  '/126 subnet' => ['1234:5678::3', '1234:5678::/126'],
307  '/126 subnet with host-bits in list set' => ['1234:5678::3', '1234:5678::2/126'],
308  'list with IPv4/IPv6 addresses' => ['1234:5678::3', '::1, 127.0.0.1, 1234:5678::/126, 192.168.1.1']
309  ];
310  }
311 
316  public function cmpIPv6ReturnsTrueForMatchingAddress($ip, $list)
317  {
318  $this->assertTrue(GeneralUtility::cmpIPv6($ip, $list));
319  }
320 
326  public static function cmpIPv6DataProviderNotMatching()
327  {
328  return [
329  'empty against localhost' => ['::', '::1'],
330  'empty against localhost with /128 netmask' => ['::', '::1/128'],
331  'localhost against different host' => ['::1', '::2'],
332  'localhost against host with prior bits set' => ['::1', '::1:1'],
333  'host against different /17 subnet' => ['1234::1', '1234:f678::/17'],
334  'host against different /127 subnet' => ['1234:5678::3', '1234:5678::/127'],
335  'host against IPv4 address list' => ['1234:5678::3', '127.0.0.1, 192.168.1.1'],
336  'host against mixed list with IPv6 host in different subnet' => ['1234:5678::3', '::1, 1234:5678::/127']
337  ];
338  }
339 
344  public function cmpIPv6ReturnsFalseForNotMatchingAddress($ip, $list)
345  {
346  $this->assertFalse(GeneralUtility::cmpIPv6($ip, $list));
347  }
348 
350  // Tests concerning IPv6Hex2Bin
352 
357  public static function IPv6Hex2BinDataProviderCorrect()
358  {
359  return [
360  'empty 1' => ['::', str_pad('', 16, "\x00")],
361  'empty 2, already normalized' => ['0000:0000:0000:0000:0000:0000:0000:0000', str_pad('', 16, "\x00")],
362  'already normalized' => ['0102:0304:0000:0000:0000:0000:0506:0078', "\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78"],
363  'expansion in middle 1' => ['1::2', "\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02"],
364  'expansion in middle 2' => ['beef::fefa', "\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa"],
365  ];
366  }
367 
372  public function IPv6Hex2BinCorrectlyConvertsAddresses($hex, $binary)
373  {
374  $this->assertTrue(GeneralUtility::IPv6Hex2Bin($hex) === $binary);
375  }
376 
378  // Tests concerning IPv6Bin2Hex
380 
385  public static function IPv6Bin2HexDataProviderCorrect()
386  {
387  return [
388  'empty' => [str_pad('', 16, "\x00"), '::'],
389  'non-empty front' => ["\x01" . str_pad('', 15, "\x00"), '100::'],
390  'non-empty back' => [str_pad('', 15, "\x00") . "\x01", '::1'],
391  'normalized' => ["\x01\x02\x03\x04" . str_pad('', 8, "\x00") . "\x05\x06\x00\x78", '102:304::506:78'],
392  'expansion in middle 1' => ["\x00\x01" . str_pad('', 12, "\x00") . "\x00\x02", '1::2'],
393  'expansion in middle 2' => ["\xbe\xef" . str_pad('', 12, "\x00") . "\xfe\xfa", 'beef::fefa'],
394  ];
395  }
396 
401  public function IPv6Bin2HexCorrectlyConvertsAddresses($binary, $hex)
402  {
403  $this->assertEquals(GeneralUtility::IPv6Bin2Hex($binary), $hex);
404  }
405 
407  // Tests concerning normalizeIPv6 / compressIPv6
409 
415  {
416  return [
417  'empty' => ['::', '0000:0000:0000:0000:0000:0000:0000:0000'],
418  'localhost' => ['::1', '0000:0000:0000:0000:0000:0000:0000:0001'],
419  'expansion in middle 1' => ['1::2', '0001:0000:0000:0000:0000:0000:0000:0002'],
420  'expansion in middle 2' => ['1:2::3', '0001:0002:0000:0000:0000:0000:0000:0003'],
421  'expansion in middle 3' => ['1::2:3', '0001:0000:0000:0000:0000:0000:0002:0003'],
422  'expansion in middle 4' => ['1:2::3:4:5', '0001:0002:0000:0000:0000:0003:0004:0005']
423  ];
424  }
425 
430  public function normalizeIPv6CorrectlyNormalizesAddresses($compressed, $normalized)
431  {
432  $this->assertEquals($normalized, GeneralUtility::normalizeIPv6($compressed));
433  }
434 
439  public function compressIPv6CorrectlyCompressesAdresses($compressed, $normalized)
440  {
441  $this->assertEquals($compressed, GeneralUtility::compressIPv6($normalized));
442  }
443 
448  {
449  if (strtolower(PHP_OS) === 'darwin') {
450  $this->markTestSkipped('This test does not work on OSX / Darwin OS.');
451  }
452  $this->assertEquals('::f0f', GeneralUtility::compressIPv6('0000:0000:0000:0000:0000:0000:0000:0f0f'));
453  }
454 
456  // Tests concerning validIP
458 
463  public static function validIpDataProvider()
464  {
465  return [
466  '0.0.0.0' => ['0.0.0.0'],
467  'private IPv4 class C' => ['192.168.0.1'],
468  'private IPv4 class A' => ['10.0.13.1'],
469  'private IPv6' => ['fe80::daa2:5eff:fe8b:7dfb']
470  ];
471  }
472 
477  public function validIpReturnsTrueForValidIp($ip)
478  {
479  $this->assertTrue(GeneralUtility::validIP($ip));
480  }
481 
487  public static function invalidIpDataProvider()
488  {
489  return [
490  'null' => [null],
491  'zero' => [0],
492  'string' => ['test'],
493  'string empty' => [''],
494  'string NULL' => ['NULL'],
495  'out of bounds IPv4' => ['300.300.300.300'],
496  'dotted decimal notation with only two dots' => ['127.0.1']
497  ];
498  }
499 
504  public function validIpReturnsFalseForInvalidIp($ip)
505  {
506  $this->assertFalse(GeneralUtility::validIP($ip));
507  }
508 
510  // Tests concerning cmpFQDN
512 
517  public static function cmpFqdnValidDataProvider()
518  {
519  return [
520  'localhost should usually resolve, IPv4' => ['127.0.0.1', '*'],
521  'localhost should usually resolve, IPv6' => ['::1', '*'],
522  // other testcases with resolving not possible since it would
523  // require a working IPv4/IPv6-connectivity
524  'aaa.bbb.ccc.ddd.eee, full' => ['aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.ddd.eee'],
525  'aaa.bbb.ccc.ddd.eee, wildcard first' => ['aaa.bbb.ccc.ddd.eee', '*.ccc.ddd.eee'],
526  'aaa.bbb.ccc.ddd.eee, wildcard last' => ['aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.*'],
527  'aaa.bbb.ccc.ddd.eee, wildcard middle' => ['aaa.bbb.ccc.ddd.eee', 'aaa.*.eee'],
528  'list-matches, 1' => ['aaa.bbb.ccc.ddd.eee', 'xxx, yyy, zzz, aaa.*.eee'],
529  'list-matches, 2' => ['aaa.bbb.ccc.ddd.eee', '127:0:0:1,,aaa.*.eee,::1']
530  ];
531  }
532 
537  public function cmpFqdnReturnsTrue($baseHost, $list)
538  {
539  if ($baseHost === '::1' && !gethostbyaddr($baseHost)) {
540  $this->markTestSkipped('Skip test for IPv6 resolution where this is not properly working on the system. Like Travis CI.');
541  }
542  $this->assertTrue(GeneralUtility::cmpFQDN($baseHost, $list));
543  }
544 
550  public static function cmpFqdnInvalidDataProvider()
551  {
552  return [
553  'num-parts of hostname to check can only be less or equal than hostname, 1' => ['aaa.bbb.ccc.ddd.eee', 'aaa.bbb.ccc.ddd.eee.fff'],
554  'num-parts of hostname to check can only be less or equal than hostname, 2' => ['aaa.bbb.ccc.ddd.eee', 'aaa.*.bbb.ccc.ddd.eee']
555  ];
556  }
557 
562  public function cmpFqdnReturnsFalse($baseHost, $list)
563  {
564  $this->assertFalse(GeneralUtility::cmpFQDN($baseHost, $list));
565  }
566 
568  // Tests concerning inList
570 
575  public function inListForItemContainedReturnsTrue($haystack)
576  {
577  $this->assertTrue(GeneralUtility::inList($haystack, 'findme'));
578  }
579 
586  {
587  return [
588  'Element as second element of four items' => ['one,findme,three,four'],
589  'Element at beginning of list' => ['findme,one,two'],
590  'Element at end of list' => ['one,two,findme'],
591  'One item list' => ['findme']
592  ];
593  }
594 
600  public function inListForItemNotContainedReturnsFalse($haystack)
601  {
602  $this->assertFalse(GeneralUtility::inList($haystack, 'findme'));
603  }
604 
611  {
612  return [
613  'Four item list' => ['one,two,three,four'],
614  'One item list' => ['one'],
615  'Empty list' => ['']
616  ];
617  }
618 
620  // Tests concerning rmFromList
622 
628  public function rmFromListRemovesElementsFromCommaSeparatedList($initialList, $listWithElementRemoved)
629  {
630  $this->assertSame($listWithElementRemoved, GeneralUtility::rmFromList('removeme', $initialList));
631  }
632 
639  {
640  return [
641  'Element as second element of three' => ['one,removeme,two', 'one,two'],
642  'Element at beginning of list' => ['removeme,one,two', 'one,two'],
643  'Element at end of list' => ['one,two,removeme', 'one,two'],
644  'One item list' => ['removeme', ''],
645  'Element not contained in list' => ['one,two,three', 'one,two,three'],
646  'Empty element survives' => ['one,,three,,removeme', 'one,,three,'],
647  'Empty element survives at start' => [',removeme,three,removeme', ',three'],
648  'Empty element survives at end' => ['removeme,three,removeme,', 'three,'],
649  'Empty list' => ['', ''],
650  'List contains removeme multiple times' => ['removeme,notme,removeme,removeme', 'notme'],
651  'List contains removeme multiple times nothing else' => ['removeme,removeme,removeme', ''],
652  'List contains removeme multiple times nothing else 2x' => ['removeme,removeme', ''],
653  'List contains removeme multiple times nothing else 3x' => ['removeme,removeme,removeme', ''],
654  'List contains removeme multiple times nothing else 4x' => ['removeme,removeme,removeme,removeme', ''],
655  'List contains removeme multiple times nothing else 5x' => ['removeme,removeme,removeme,removeme,removeme', ''],
656  ];
657  }
658 
660  // Tests concerning expandList
662 
668  public function expandListExpandsIntegerRanges($list, $expectation)
669  {
670  $this->assertSame($expectation, GeneralUtility::expandList($list));
671  }
672 
679  {
680  return [
681  'Expand for the same number' => ['1,2-2,7', '1,2,7'],
682  'Small range expand with parameters reversed ignores reversed items' => ['1,5-3,7', '1,7'],
683  'Small range expand' => ['1,3-5,7', '1,3,4,5,7'],
684  'Expand at beginning' => ['3-5,1,7', '3,4,5,1,7'],
685  'Expand at end' => ['1,7,3-5', '1,7,3,4,5'],
686  'Multiple small range expands' => ['1,3-5,7-10,12', '1,3,4,5,7,8,9,10,12'],
687  'One item list' => ['1-5', '1,2,3,4,5'],
688  'Nothing to expand' => ['1,2,3,4', '1,2,3,4'],
689  'Empty list' => ['', '']
690  ];
691  }
692 
697  {
698  $list = GeneralUtility::expandList('1-2000');
699  $this->assertSame(1000, count(explode(',', $list)));
700  }
701 
703  // Tests concerning uniqueList
705 
711  public function uniqueListUnifiesCommaSeparatedList($initialList, $unifiedList)
712  {
713  $this->assertSame($unifiedList, GeneralUtility::uniqueList($initialList));
714  }
715 
722  {
723  return [
724  'List without duplicates' => ['one,two,three', 'one,two,three'],
725  'List with two consecutive duplicates' => ['one,two,two,three,three', 'one,two,three'],
726  'List with non-consecutive duplicates' => ['one,two,three,two,three', 'one,two,three'],
727  'One item list' => ['one', 'one'],
728  'Empty list' => ['', '']
729  ];
730  }
731 
733  // Tests concerning isFirstPartOfStr
735 
741  {
742  return [
743  'match first part of string' => ['hello world', 'hello'],
744  'match whole string' => ['hello', 'hello'],
745  'integer is part of string with same number' => ['24', 24],
746  'string is part of integer with same number' => [24, '24'],
747  'integer is part of string starting with same number' => ['24 beer please', 24]
748  ];
749  }
750 
755  public function isFirstPartOfStrReturnsTrueForMatchingFirstPart($string, $part)
756  {
757  $this->assertTrue(GeneralUtility::isFirstPartOfStr($string, $part));
758  }
759 
766  {
767  return [
768  'no string match' => ['hello', 'bye'],
769  'no case sensitive string match' => ['hello world', 'Hello'],
770  'array is not part of string' => ['string', []],
771  'string is not part of array' => [[], 'string'],
772  'NULL is not part of string' => ['string', null],
773  'string is not part of NULL' => [null, 'string'],
774  'NULL is not part of array' => [[], null],
775  'array is not part of NULL' => [null, []],
776  'empty string is not part of empty string' => ['', ''],
777  'NULL is not part of empty string' => ['', null],
778  'false is not part of empty string' => ['', false],
779  'empty string is not part of NULL' => [null, ''],
780  'empty string is not part of false' => [false, ''],
781  'empty string is not part of zero integer' => [0, ''],
782  'zero integer is not part of NULL' => [null, 0],
783  'zero integer is not part of empty string' => ['', 0]
784  ];
785  }
786 
792  {
793  $this->assertFalse(GeneralUtility::isFirstPartOfStr($string, $part));
794  }
795 
797  // Tests concerning formatSize
799 
803  public function formatSizeTranslatesBytesToHigherOrderRepresentation($size, $labels, $base, $expected)
804  {
805  $this->assertEquals($expected, GeneralUtility::formatSize($size, $labels, $base));
806  }
807 
813  public function formatSizeDataProvider()
814  {
815  return [
816  'IEC Bytes stay bytes (min)' => [1, '', 0, '1 '],
817  'IEC Bytes stay bytes (max)' => [921, '', 0, '921 '],
818  'IEC Kilobytes are used (min)' => [922, '', 0, '0.90 Ki'],
819  'IEC Kilobytes are used (max)' => [943718, '', 0, '922 Ki'],
820  'IEC Megabytes are used (min)' => [943719, '', 0, '0.90 Mi'],
821  'IEC Megabytes are used (max)' => [966367641, '', 0, '922 Mi'],
822  'IEC Gigabytes are used (min)' => [966367642, '', 0, '0.90 Gi'],
823  'IEC Gigabytes are used (max)' => [989560464998, '', 0, '922 Gi'],
824  'IEC Decimal is omitted for large kilobytes' => [31080, '', 0, '30 Ki'],
825  'IEC Decimal is omitted for large megabytes' => [31458000, '', 0, '30 Mi'],
826  'IEC Decimal is omitted for large gigabytes' => [32212254720, '', 0, '30 Gi'],
827  'SI Bytes stay bytes (min)' => [1, 'si', 0, '1 '],
828  'SI Bytes stay bytes (max)' => [899, 'si', 0, '899 '],
829  'SI Kilobytes are used (min)' => [901, 'si', 0, '0.90 k'],
830  'SI Kilobytes are used (max)' => [900000, 'si', 0, '900 k'],
831  'SI Megabytes are used (min)' => [900001, 'si', 0, '0.90 M'],
832  'SI Megabytes are used (max)' => [900000000, 'si', 0, '900 M'],
833  'SI Gigabytes are used (min)' => [900000001, 'si', 0, '0.90 G'],
834  'SI Gigabytes are used (max)' => [900000000000, 'si', 0, '900 G'],
835  'SI Decimal is omitted for large kilobytes' => [30000, 'si', 0, '30 k'],
836  'SI Decimal is omitted for large megabytes' => [30000000, 'si', 0, '30 M'],
837  'SI Decimal is omitted for large gigabytes' => [30000000000, 'si', 0, '30 G'],
838  'Label for bytes can be exchanged (binary unit)' => [1, ' Foo|||', 0, '1 Foo'],
839  'Label for kilobytes can be exchanged (binary unit)' => [1024, '| Foo||', 0, '1.00 Foo'],
840  'Label for megabyes can be exchanged (binary unit)' => [1048576, '|| Foo|', 0, '1.00 Foo'],
841  'Label for gigabytes can be exchanged (binary unit)' => [1073741824, '||| Foo', 0, '1.00 Foo'],
842  'Label for bytes can be exchanged (decimal unit)' => [1, ' Foo|||', 1000, '1 Foo'],
843  'Label for kilobytes can be exchanged (decimal unit)' => [1000, '| Foo||', 1000, '1.00 Foo'],
844  'Label for megabyes can be exchanged (decimal unit)' => [1000000, '|| Foo|', 1000, '1.00 Foo'],
845  'Label for gigabytes can be exchanged (decimal unit)' => [1000000000, '||| Foo', 1000, '1.00 Foo'],
846  'IEC Base is ignored' => [1024, 'iec', 1000, '1.00 Ki'],
847  'SI Base is ignored' => [1000, 'si', 1024, '1.00 k'],
848  'Use binary base for unexpected base' => [2048, '| Bar||', 512, '2.00 Bar']
849  ];
850  }
851 
853  // Tests concerning splitCalc
855 
860  public function splitCalcDataProvider()
861  {
862  return [
863  'empty string returns empty array' => [
864  [],
865  ''
866  ],
867  'number without operator returns array with plus and number' => [
868  [['+', 42]],
869  '42'
870  ],
871  'two numbers with asterisk return first number with plus and second number with asterisk' => [
872  [['+', 42], ['*', 31]],
873  '42 * 31'
874  ]
875  ];
876  }
877 
882  public function splitCalcCorrectlySplitsExpression($expected, $expression)
883  {
884  $this->assertEquals($expected, GeneralUtility::splitCalc($expression, '+-*/'));
885  }
886 
888  // Tests concerning htmlspecialchars_decode
890 
894  {
895  $string = '<typo3 version="6.0">&nbsp;</typo3>';
896  $encoded = htmlspecialchars($string);
897  $decoded = htmlspecialchars_decode($encoded);
898  $this->assertEquals($string, $decoded);
899  }
900 
902  // Tests concerning deHSCentities
904 
908  public function deHSCentitiesReturnsDecodedString($input, $expected)
909  {
910  $this->assertEquals($expected, GeneralUtility::deHSCentities($input));
911  }
912 
919  {
920  return [
921  'Empty string' => ['', ''],
922  'Double encoded &' => ['&amp;amp;', '&amp;'],
923  'Double encoded numeric entity' => ['&amp;#1234;', '&#1234;'],
924  'Double encoded hexadecimal entity' => ['&amp;#x1b;', '&#x1b;'],
925  'Single encoded entities are not touched' => ['&amp; &#1234; &#x1b;', '&amp; &#1234; &#x1b;']
926  ];
927  }
928 
930  // Tests concerning slashJS
932 
936  public function slashJsEscapesSingleQuotesAndSlashes($input, $extended, $expected)
937  {
938  $this->assertEquals($expected, GeneralUtility::slashJS($input, $extended));
939  }
940 
946  public function slashJsDataProvider()
947  {
948  return [
949  'Empty string is not changed' => ['', false, ''],
950  'Normal string is not changed' => ['The cake is a lie √', false, 'The cake is a lie √'],
951  'String with single quotes' => ['The \'cake\' is a lie', false, 'The \\\'cake\\\' is a lie'],
952  'String with single quotes and backslashes - just escape single quotes' => ['The \\\'cake\\\' is a lie', false, 'The \\\\\'cake\\\\\' is a lie'],
953  'String with single quotes and backslashes - escape both' => ['The \\\'cake\\\' is a lie', true, 'The \\\\\\\'cake\\\\\\\' is a lie']
954  ];
955  }
956 
958  // Tests concerning rawUrlEncodeJS
960 
964  {
965  $input = 'Encode \'me\', but leave my spaces √';
966  $expected = 'Encode %27me%27%2C but leave my spaces %E2%88%9A';
967  $this->assertEquals($expected, GeneralUtility::rawUrlEncodeJS($input));
968  }
969 
971  // Tests concerning rawUrlEncodeJS
973 
977  {
978  $input = 'Encode \'me\', but leave my / √';
979  $expected = 'Encode%20%27me%27%2C%20but%20leave%20my%20/%20%E2%88%9A';
980  $this->assertEquals($expected, GeneralUtility::rawUrlEncodeFP($input));
981  }
982 
984  // Tests concerning strtoupper / strtolower
986 
991  public function strtouppperDataProvider()
992  {
993  return [
994  'Empty string' => ['', ''],
995  'String containing only latin characters' => ['the cake is a lie.', 'THE CAKE IS A LIE.'],
996  'String with umlauts and accent characters' => ['the càkê is ä lie.', 'THE CàKê IS ä LIE.']
997  ];
998  }
999 
1004  public function strtoupperConvertsOnlyLatinCharacters($input, $expected)
1005  {
1006  $this->assertEquals($expected, GeneralUtility::strtoupper($input));
1007  }
1008 
1013  public function strtolowerConvertsOnlyLatinCharacters($expected, $input)
1014  {
1015  $this->assertEquals($expected, GeneralUtility::strtolower($input));
1016  }
1017 
1019  // Tests concerning validEmail
1021 
1027  {
1028  return [
1029  'short mail address' => ['a@b.c'],
1030  'simple mail address' => ['test@example.com'],
1031  'uppercase characters' => ['QWERTYUIOPASDFGHJKLZXCVBNM@QWERTYUIOPASDFGHJKLZXCVBNM.NET'],
1032  'equal sign in local part' => ['test=mail@example.com'],
1033  'dash in local part' => ['test-mail@example.com'],
1034  'plus in local part' => ['test+mail@example.com'],
1035  'question mark in local part' => ['test?mail@example.com'],
1036  'slash in local part' => ['foo/bar@example.com'],
1037  'hash in local part' => ['foo#bar@example.com'],
1038  'dot in local part' => ['firstname.lastname@employee.2something.com'],
1039  'dash as local part' => ['-@foo.com'],
1040  'umlauts in domain part' => ['foo@äöüfoo.com']
1041  ];
1042  }
1043 
1049  {
1050  $this->assertTrue(GeneralUtility::validEmail($address));
1051  }
1052 
1059  {
1060  return [
1061  'empty string' => [''],
1062  'empty array' => [[]],
1063  'integer' => [42],
1064  'float' => [42.23],
1065  'array' => [['foo']],
1066  'object' => [new \stdClass()],
1067  '@ sign only' => ['@'],
1068  'string longer than 320 characters' => [str_repeat('0123456789', 33)],
1069  'duplicate @' => ['test@@example.com'],
1070  'duplicate @ combined with further special characters in local part' => ['test!.!@#$%^&*@example.com'],
1071  'opening parenthesis in local part' => ['foo(bar@example.com'],
1072  'closing parenthesis in local part' => ['foo)bar@example.com'],
1073  'opening square bracket in local part' => ['foo[bar@example.com'],
1074  'closing square bracket as local part' => [']@example.com'],
1075  'top level domain only' => ['test@com'],
1076  'dash as second level domain' => ['foo@-.com'],
1077  'domain part starting with dash' => ['foo@-foo.com'],
1078  'domain part ending with dash' => ['foo@foo-.com'],
1079  'number as top level domain' => ['foo@bar.123'],
1080  'dot at beginning of domain part' => ['test@.com'],
1081  'local part ends with dot' => ['e.x.a.m.p.l.e.@example.com'],
1082  'umlauts in local part' => ['äöüfoo@bar.com'],
1083  'trailing whitespace' => ['test@example.com '],
1084  'trailing carriage return' => ['test@example.com' . CR],
1085  'trailing linefeed' => ['test@example.com' . LF],
1086  'trailing carriage return linefeed' => ['test@example.com' . CRLF],
1087  'trailing tab' => ['test@example.com' . TAB],
1088  'prohibited input characters' => ['“mailto:test@example.com”'],
1089  ];
1090  }
1091 
1097  {
1098  $this->assertFalse(GeneralUtility::validEmail($address));
1099  }
1100 
1102  // Tests concerning intExplode
1104 
1108  {
1109  $testString = '1,foo,2';
1110  $expectedArray = [1, 0, 2];
1111  $actualArray = GeneralUtility::intExplode(',', $testString);
1112  $this->assertEquals($expectedArray, $actualArray);
1113  }
1114 
1116  // Tests concerning implodeArrayForUrl / explodeUrl2Array
1118 
1125  {
1126  $valueArray = ['one' => '√', 'two' => 2];
1127  return [
1128  'Empty input' => ['foo', [], ''],
1129  'String parameters' => ['foo', $valueArray, '&foo[one]=%E2%88%9A&foo[two]=2'],
1130  'Nested array parameters' => ['foo', [$valueArray], '&foo[0][one]=%E2%88%9A&foo[0][two]=2'],
1131  'Keep blank parameters' => ['foo', ['one' => '√', ''], '&foo[one]=%E2%88%9A&foo[0]=']
1132  ];
1133  }
1134 
1139  public function implodeArrayForUrlBuildsValidParameterString($name, $input, $expected)
1140  {
1141  $this->assertSame($expected, GeneralUtility::implodeArrayForUrl($name, $input));
1142  }
1143 
1148  {
1149  $input = ['one' => '√', ''];
1150  $expected = '&foo[one]=%E2%88%9A';
1151  $this->assertSame($expected, GeneralUtility::implodeArrayForUrl('foo', $input, '', true));
1152  }
1153 
1158  {
1159  $input = ['one' => '√', ''];
1160  $expected = '&foo%5Bone%5D=%E2%88%9A&foo%5B0%5D=';
1161  $this->assertSame($expected, GeneralUtility::implodeArrayForUrl('foo', $input, '', false, true));
1162  }
1163 
1168  public function explodeUrl2ArrayTransformsParameterStringToNestedArray($name, $array, $input)
1169  {
1170  $expected = $array ? [$name => $array] : [];
1171  $this->assertEquals($expected, GeneralUtility::explodeUrl2Array($input, true));
1172  }
1173 
1178  public function explodeUrl2ArrayTransformsParameterStringToFlatArray($input, $expected)
1179  {
1180  $this->assertEquals($expected, GeneralUtility::explodeUrl2Array($input, false));
1181  }
1182 
1189  {
1190  return [
1191  'Empty string' => ['', []],
1192  'Simple parameter string' => ['&one=%E2%88%9A&two=2', ['one' => '√', 'two' => 2]],
1193  'Nested parameter string' => ['&foo[one]=%E2%88%9A&two=2', ['foo[one]' => '√', 'two' => 2]]
1194  ];
1195  }
1196 
1198  // Tests concerning compileSelectedGetVarsFromArray
1200 
1204  {
1205  $filter = 'foo,bar';
1206  $getArray = ['foo' => 1, 'cake' => 'lie'];
1207  $expected = ['foo' => 1];
1208  $result = GeneralUtility::compileSelectedGetVarsFromArray($filter, $getArray, false);
1209  $this->assertSame($expected, $result);
1210  }
1211 
1216  {
1217  $_GET['bar'] = '2';
1218  $filter = 'foo,bar';
1219  $getArray = ['foo' => 1, 'cake' => 'lie'];
1220  $expected = ['foo' => 1, 'bar' => '2'];
1221  $result = GeneralUtility::compileSelectedGetVarsFromArray($filter, $getArray, true);
1222  $this->assertSame($expected, $result);
1223  }
1224 
1226  // Tests concerning array_merge
1228 
1236  {
1237  $array1 = [10 => 'FOO', '20' => 'BAR'];
1238  $array2 = ['5' => 'PLONK'];
1239  $expected = ['5' => 'PLONK', 10 => 'FOO', '20' => 'BAR'];
1240  $this->assertEquals($expected, GeneralUtility::array_merge($array1, $array2));
1241  }
1242 
1244  // Tests concerning revExplode
1246 
1250  public function revExplodeDataProvider()
1251  {
1252  return [
1253  'limit 0 should return unexploded string' => [
1254  ':',
1255  'my:words:here',
1256  0,
1257  ['my:words:here']
1258  ],
1259  'limit 1 should return unexploded string' => [
1260  ':',
1261  'my:words:here',
1262  1,
1263  ['my:words:here']
1264  ],
1265  'limit 2 should return two pieces' => [
1266  ':',
1267  'my:words:here',
1268  2,
1269  ['my:words', 'here']
1270  ],
1271  'limit 3 should return unexploded string' => [
1272  ':',
1273  'my:words:here',
1274  3,
1275  ['my', 'words', 'here']
1276  ],
1277  'limit 0 should return unexploded string if no delimiter is contained' => [
1278  ':',
1279  'mywordshere',
1280  0,
1281  ['mywordshere']
1282  ],
1283  'limit 1 should return unexploded string if no delimiter is contained' => [
1284  ':',
1285  'mywordshere',
1286  1,
1287  ['mywordshere']
1288  ],
1289  'limit 2 should return unexploded string if no delimiter is contained' => [
1290  ':',
1291  'mywordshere',
1292  2,
1293  ['mywordshere']
1294  ],
1295  'limit 3 should return unexploded string if no delimiter is contained' => [
1296  ':',
1297  'mywordshere',
1298  3,
1299  ['mywordshere']
1300  ],
1301  'multi character delimiter is handled properly with limit 2' => [
1302  '[]',
1303  'a[b][c][d]',
1304  2,
1305  ['a[b][c', 'd]']
1306  ],
1307  'multi character delimiter is handled properly with limit 3' => [
1308  '[]',
1309  'a[b][c][d]',
1310  3,
1311  ['a[b', 'c', 'd]']
1312  ],
1313  ];
1314  }
1315 
1320  public function revExplodeCorrectlyExplodesStringForGivenPartsCount($delimiter, $testString, $count, $expectedArray)
1321  {
1322  $actualArray = GeneralUtility::revExplode($delimiter, $testString, $count);
1323  $this->assertEquals($expectedArray, $actualArray);
1324  }
1325 
1330  {
1331  $testString = 'even:more:of:my:words:here';
1332  $expectedArray = ['even:more:of:my', 'words', 'here'];
1333  $actualArray = GeneralUtility::revExplode(':', $testString, 3);
1334  $this->assertEquals($expectedArray, $actualArray);
1335  }
1336 
1338  // Tests concerning trimExplode
1340 
1350  public function trimExplodeReturnsCorrectResult($delimiter, $testString, $removeEmpty, $limit, $expectedResult)
1351  {
1352  $this->assertSame($expectedResult, GeneralUtility::trimExplode($delimiter, $testString, $removeEmpty, $limit));
1353  }
1354 
1359  {
1360  return [
1361  'spaces at element start and end' => [
1362  ',',
1363  ' a , b , c ,d ,, e,f,',
1364  false,
1365  0,
1366  ['a', 'b', 'c', 'd', '', 'e', 'f', '']
1367  ],
1368  'removes newline' => [
1369  ',',
1370  ' a , b , ' . LF . ' ,d ,, e,f,',
1371  true,
1372  0,
1373  ['a', 'b', 'd', 'e', 'f']
1374  ],
1375  'removes empty elements' => [
1376  ',',
1377  'a , b , c , ,d ,, ,e,f,',
1378  true,
1379  0,
1380  ['a', 'b', 'c', 'd', 'e', 'f']
1381  ],
1382  'keeps remaining results with empty items after reaching limit with positive parameter' => [
1383  ',',
1384  ' a , b , c , , d,, ,e ',
1385  false,
1386  3,
1387  ['a', 'b', 'c , , d,, ,e']
1388  ],
1389  'keeps remaining results without empty items after reaching limit with positive parameter' => [
1390  ',',
1391  ' a , b , c , , d,, ,e ',
1392  true,
1393  3,
1394  ['a', 'b', 'c , d,e']
1395  ],
1396  'keeps remaining results with empty items after reaching limit with negative parameter' => [
1397  ',',
1398  ' a , b , c , d, ,e, f , , ',
1399  false,
1400  -3,
1401  ['a', 'b', 'c', 'd', '', 'e']
1402  ],
1403  'keeps remaining results without empty items after reaching limit with negative parameter' => [
1404  ',',
1405  ' a , b , c , d, ,e, f , , ',
1406  true,
1407  -3,
1408  ['a', 'b', 'c']
1409  ],
1410  'returns exact results without reaching limit with positive parameter' => [
1411  ',',
1412  ' a , b , , c , , , ',
1413  true,
1414  4,
1415  ['a', 'b', 'c']
1416  ],
1417  'keeps zero as string' => [
1418  ',',
1419  'a , b , c , ,d ,, ,e,f, 0 ,',
1420  true,
1421  0,
1422  ['a', 'b', 'c', 'd', 'e', 'f', '0']
1423  ],
1424  'keeps whitespace inside elements' => [
1425  ',',
1426  'a , b , c , ,d ,, ,e,f, g h ,',
1427  true,
1428  0,
1429  ['a', 'b', 'c', 'd', 'e', 'f', 'g h']
1430  ],
1431  'can use internal regex delimiter as explode delimiter' => [
1432  '/',
1433  'a / b / c / /d // /e/f/ g h /',
1434  true,
1435  0,
1436  ['a', 'b', 'c', 'd', 'e', 'f', 'g h']
1437  ],
1438  'can use whitespaces as delimiter' => [
1439  ' ',
1440  '* * * * *',
1441  true,
1442  0,
1443  ['*', '*', '*', '*', '*']
1444  ],
1445  'can use words as delimiter' => [
1446  'All',
1447  'HelloAllTogether',
1448  true,
1449  0,
1450  ['Hello', 'Together']
1451  ],
1452  'can use word with appended and prepended spaces as delimiter' => [
1453  ' all ',
1454  'Hello all together',
1455  true,
1456  0,
1457  ['Hello', 'together']
1458  ],
1459  'can use word with appended and prepended spaces as delimiter and do not remove empty' => [
1460  ' all ',
1461  'Hello all together all there all all are all none',
1462  false,
1463  0,
1464  ['Hello', 'together', 'there', '', 'are', 'none']
1465  ],
1466  'can use word with appended and prepended spaces as delimiter, do not remove empty and limit' => [
1467  ' all ',
1468  'Hello all together all there all all are all none',
1469  false,
1470  5,
1471  ['Hello', 'together', 'there', '', 'are all none']
1472  ],
1473  'can use word with appended and prepended spaces as delimiter, do not remove empty, limit and multiple delimiter in last' => [
1474  ' all ',
1475  'Hello all together all there all all are all none',
1476  false,
1477  4,
1478  ['Hello', 'together', 'there', 'all are all none']
1479  ],
1480  'can use word with appended and prepended spaces as delimiter, remove empty and limit' => [
1481  ' all ',
1482  'Hello all together all there all all are all none',
1483  true,
1484  4,
1485  ['Hello', 'together', 'there', 'are all none']
1486  ],
1487  'can use word with appended and prepended spaces as delimiter, remove empty and limit and multiple delimiter in last' => [
1488  ' all ',
1489  'Hello all together all there all all are all none',
1490  true,
1491  5,
1492  ['Hello', 'together', 'there', 'are' , 'none']
1493  ],
1494  'can use words as delimiter and do not remove empty' => [
1495  'all there',
1496  'Helloall theretogether all there all there are all there none',
1497  false,
1498  0,
1499  ['Hello', 'together', '', 'are', 'none']
1500  ],
1501  'can use words as delimiter, do not remove empty and limit' => [
1502  'all there',
1503  'Helloall theretogether all there all there are all there none',
1504  false,
1505  4,
1506  ['Hello', 'together', '', 'are all there none']
1507  ],
1508  'can use words as delimiter, do not remove empty, limit and multiple delimiter in last' => [
1509  'all there',
1510  'Helloall theretogether all there all there are all there none',
1511  false,
1512  3,
1513  ['Hello', 'together', 'all there are all there none']
1514  ],
1515  'can use words as delimiter, remove empty' => [
1516  'all there',
1517  'Helloall theretogether all there all there are all there none',
1518  true,
1519  0,
1520  ['Hello', 'together', 'are', 'none']
1521  ],
1522  'can use words as delimiter, remove empty and limit' => [
1523  'all there',
1524  'Helloall theretogether all there all there are all there none',
1525  true,
1526  3,
1527  ['Hello', 'together', 'are all there none']
1528  ],
1529  'can use words as delimiter, remove empty and limit and multiple delimiter in last' => [
1530  'all there',
1531  'Helloall theretogether all there all there are all there none',
1532  true,
1533  4,
1534  ['Hello', 'together', 'are' , 'none']
1535  ],
1536  'can use new line as delimiter' => [
1537  LF,
1538  "Hello\nall\ntogether",
1539  true,
1540  0,
1541  ['Hello', 'all', 'together']
1542  ],
1543  'works with whitespace separator' => [
1544  "\t",
1545  " a b \t c \t \t d \t e \t u j \t s",
1546  false,
1547  0,
1548  ['a b', 'c', '', 'd', 'e', 'u j', 's']
1549  ],
1550  'works with whitespace separator and limit' => [
1551  "\t",
1552  " a b \t c \t \t d \t e \t u j \t s",
1553  false,
1554  4,
1555  ['a b', 'c', '', "d \t e \t u j \t s"]
1556  ],
1557  'works with whitespace separator and remove empty' => [
1558  "\t",
1559  " a b \t c \t \t d \t e \t u j \t s",
1560  true,
1561  0,
1562  ['a b', 'c', 'd', 'e', 'u j', 's']
1563  ],
1564  'works with whitespace separator remove empty and limit' => [
1565  "\t",
1566  " a b \t c \t \t d \t e \t u j \t s",
1567  true,
1568  3,
1569  ['a b', 'c', "d \t e \t u j \t s"]
1570  ],
1571  ];
1572  }
1573 
1575  // Tests concerning getBytesFromSizeMeasurement
1577 
1583  {
1584  return [
1585  '100 kilo Bytes' => ['102400', '100k'],
1586  '100 mega Bytes' => ['104857600', '100m'],
1587  '100 giga Bytes' => ['107374182400', '100g']
1588  ];
1589  }
1590 
1595  public function getBytesFromSizeMeasurementCalculatesCorrectByteValue($expected, $byteString)
1596  {
1597  $this->assertEquals($expected, GeneralUtility::getBytesFromSizeMeasurement($byteString));
1598  }
1599 
1601  // Tests concerning getIndpEnv
1603 
1607  {
1608  $this->assertTrue(strlen(GeneralUtility::getIndpEnv('TYPO3_SITE_PATH')) >= 1);
1609  }
1610 
1615  {
1616  if (TYPO3_OS === 'WIN') {
1617  $this->markTestSkipped('Test not available on Windows OS.');
1618  }
1619  $result = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
1620  $this->assertEquals('/', $result[0]);
1621  }
1622 
1627  {
1628  if (TYPO3_OS !== 'WIN') {
1629  $this->markTestSkipped('Test available only on Windows OS.');
1630  }
1631  $result = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
1632  $this->assertRegExp('/^[a-z]:\//i', $result);
1633  }
1634 
1639  {
1640  $result = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
1641  $this->assertEquals('/', $result[strlen($result) - 1]);
1642  }
1643 
1647  public static function hostnameAndPortDataProvider()
1648  {
1649  return [
1650  'localhost ipv4 without port' => ['127.0.0.1', '127.0.0.1', ''],
1651  'localhost ipv4 with port' => ['127.0.0.1:81', '127.0.0.1', '81'],
1652  'localhost ipv6 without port' => ['[::1]', '[::1]', ''],
1653  'localhost ipv6 with port' => ['[::1]:81', '[::1]', '81'],
1654  'ipv6 without port' => ['[2001:DB8::1]', '[2001:DB8::1]', ''],
1655  'ipv6 with port' => ['[2001:DB8::1]:81', '[2001:DB8::1]', '81'],
1656  'hostname without port' => ['lolli.did.this', 'lolli.did.this', ''],
1657  'hostname with port' => ['lolli.did.this:42', 'lolli.did.this', '42']
1658  ];
1659  }
1660 
1665  public function getIndpEnvTypo3HostOnlyParsesHostnamesAndIpAdresses($httpHost, $expectedIp)
1666  {
1668  $_SERVER['HTTP_HOST'] = $httpHost;
1669  $this->assertEquals($expectedIp, GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'));
1670  }
1671 
1676  {
1677  unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern']);
1678  $this->assertFalse(GeneralUtilityFixture::isAllowedHostHeaderValue('evil.foo.bar'));
1679  }
1680 
1685  {
1686  return [
1687  'hostname without port matching' => ['lolli.did.this', '.*\.did\.this'],
1688  'other hostname without port matching' => ['helmut.did.this', '.*\.did\.this'],
1689  'two different hostnames without port matching 1st host' => ['helmut.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
1690  'two different hostnames without port matching 2nd host' => ['lolli.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
1691  'hostname with port matching' => ['lolli.did.this:42', '.*\.did\.this:42'],
1692  'hostnames are case insensitive 1' => ['lolli.DID.this:42', '.*\.did.this:42'],
1693  'hostnames are case insensitive 2' => ['lolli.did.this:42', '.*\.DID.this:42'],
1694  ];
1695  }
1696 
1701  {
1702  return [
1703  'hostname without port' => ['lolli.did.this', 'helmut\.did\.this'],
1704  'hostname with port, but port not allowed' => ['lolli.did.this:42', 'helmut\.did\.this'],
1705  'two different hostnames in pattern but host header starts with differnet value #1' => ['sub.helmut.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
1706  'two different hostnames in pattern but host header starts with differnet value #2' => ['sub.lolli.is.secure', '(helmut\.is\.secure|lolli\.is\.secure)'],
1707  'two different hostnames in pattern but host header ends with differnet value #1' => ['helmut.is.secure.tld', '(helmut\.is\.secure|lolli\.is\.secure)'],
1708  'two different hostnames in pattern but host header ends with differnet value #2' => ['lolli.is.secure.tld', '(helmut\.is\.secure|lolli\.is\.secure)'],
1709  ];
1710  }
1711 
1718  public function isAllowedHostHeaderValueReturnsTrueIfHostValueMatches($httpHost, $hostNamePattern)
1719  {
1720  $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] = $hostNamePattern;
1721  $this->assertTrue(GeneralUtilityFixture::isAllowedHostHeaderValue($httpHost));
1722  }
1723 
1730  public function isAllowedHostHeaderValueReturnsFalseIfHostValueMatches($httpHost, $hostNamePattern)
1731  {
1732  $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] = $hostNamePattern;
1733  $this->assertFalse(GeneralUtilityFixture::isAllowedHostHeaderValue($httpHost));
1734  }
1735 
1737  {
1738  return [
1739  'host value matches server name and server port is default http' => [
1740  'httpHost' => 'secure.web.server',
1741  'serverName' => 'secure.web.server',
1742  'isAllowed' => true,
1743  'serverPort' => '80',
1744  'ssl' => 'Off',
1745  ],
1746  'host value matches server name if compared case insensitive 1' => [
1747  'httpHost' => 'secure.web.server',
1748  'serverName' => 'secure.WEB.server',
1749  'isAllowed' => true,
1750  ],
1751  'host value matches server name if compared case insensitive 2' => [
1752  'httpHost' => 'secure.WEB.server',
1753  'serverName' => 'secure.web.server',
1754  'isAllowed' => true,
1755  ],
1756  'host value matches server name and server port is default https' => [
1757  'httpHost' => 'secure.web.server',
1758  'serverName' => 'secure.web.server',
1759  'isAllowed' => true,
1760  'serverPort' => '443',
1761  'ssl' => 'On',
1762  ],
1763  'host value matches server name and server port' => [
1764  'httpHost' => 'secure.web.server:88',
1765  'serverName' => 'secure.web.server',
1766  'isAllowed' => true,
1767  'serverPort' => '88',
1768  ],
1769  'host value matches server name case insensitive 1 and server port' => [
1770  'httpHost' => 'secure.WEB.server:88',
1771  'serverName' => 'secure.web.server',
1772  'isAllowed' => true,
1773  'serverPort' => '88',
1774  ],
1775  'host value matches server name case insensitive 2 and server port' => [
1776  'httpHost' => 'secure.web.server:88',
1777  'serverName' => 'secure.WEB.server',
1778  'isAllowed' => true,
1779  'serverPort' => '88',
1780  ],
1781  'host value is ipv6 but matches server name and server port' => [
1782  'httpHost' => '[::1]:81',
1783  'serverName' => '[::1]',
1784  'isAllowed' => true,
1785  'serverPort' => '81',
1786  ],
1787  'host value does not match server name' => [
1788  'httpHost' => 'insecure.web.server',
1789  'serverName' => 'secure.web.server',
1790  'isAllowed' => false,
1791  ],
1792  'host value does not match server port' => [
1793  'httpHost' => 'secure.web.server:88',
1794  'serverName' => 'secure.web.server',
1795  'isAllowed' => false,
1796  'serverPort' => '89',
1797  ],
1798  'host value has default port that does not match server port' => [
1799  'httpHost' => 'secure.web.server',
1800  'serverName' => 'secure.web.server',
1801  'isAllowed' => false,
1802  'serverPort' => '81',
1803  'ssl' => 'Off',
1804  ],
1805  'host value has default port that does not match server ssl port' => [
1806  'httpHost' => 'secure.web.server',
1807  'serverName' => 'secure.web.server',
1808  'isAllowed' => false,
1809  'serverPort' => '444',
1810  'ssl' => 'On',
1811  ],
1812  ];
1813  }
1814 
1825  public function isAllowedHostHeaderValueWorksCorrectlyWithWithServerNamePattern($httpHost, $serverName, $isAllowed, $serverPort = '80', $ssl = 'Off')
1826  {
1827  $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] = GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME;
1828  $_SERVER['SERVER_NAME'] = $serverName;
1829  $_SERVER['SERVER_PORT'] = $serverPort;
1830  $_SERVER['HTTPS'] = $ssl;
1831  $this->assertSame($isAllowed, GeneralUtilityFixture::isAllowedHostHeaderValue($httpHost));
1832  }
1833 
1838  {
1839  GeneralUtilityFixture::getIndpEnv('HTTP_HOST');
1841  GeneralUtilityFixture::getIndpEnv('TYPO3_HOST_ONLY');
1843  GeneralUtilityFixture::getIndpEnv('TYPO3_REQUEST_HOST');
1845  GeneralUtilityFixture::getIndpEnv('TYPO3_REQUEST_URL');
1847  }
1848 
1857  public function getIndpEnvForHostThrowsExceptionForNotAllowedHostnameValues($httpHost, $hostNamePattern)
1858  {
1859  $_SERVER['HTTP_HOST'] = $httpHost;
1860  $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] = $hostNamePattern;
1861  GeneralUtilityFixture::getIndpEnv('HTTP_HOST');
1862  }
1863 
1871  {
1872  $_SERVER['HTTP_HOST'] = $httpHost;
1873  $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] = GeneralUtility::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL;
1874  $this->assertSame($httpHost, GeneralUtility::getIndpEnv('HTTP_HOST'));
1875  }
1876 
1881  public function getIndpEnvTypo3PortParsesHostnamesAndIpAdresses($httpHost, $dummy, $expectedPort)
1882  {
1883  $_SERVER['HTTP_HOST'] = $httpHost;
1884  $this->assertEquals($expectedPort, GeneralUtility::getIndpEnv('TYPO3_PORT'));
1885  }
1886 
1888  // Tests concerning underscoredToUpperCamelCase
1890 
1896  {
1897  return [
1898  'single word' => ['Blogexample', 'blogexample'],
1899  'multiple words' => ['BlogExample', 'blog_example']
1900  ];
1901  }
1902 
1907  public function underscoredToUpperCamelCase($expected, $inputString)
1908  {
1909  $this->assertEquals($expected, GeneralUtility::underscoredToUpperCamelCase($inputString));
1910  }
1911 
1913  // Tests concerning underscoredToLowerCamelCase
1915 
1921  {
1922  return [
1923  'single word' => ['minimalvalue', 'minimalvalue'],
1924  'multiple words' => ['minimalValue', 'minimal_value']
1925  ];
1926  }
1927 
1932  public function underscoredToLowerCamelCase($expected, $inputString)
1933  {
1934  $this->assertEquals($expected, GeneralUtility::underscoredToLowerCamelCase($inputString));
1935  }
1936 
1938  // Tests concerning camelCaseToLowerCaseUnderscored
1940 
1946  {
1947  return [
1948  'single word' => ['blogexample', 'blogexample'],
1949  'single word starting upper case' => ['blogexample', 'Blogexample'],
1950  'two words starting lower case' => ['minimal_value', 'minimalValue'],
1951  'two words starting upper case' => ['blog_example', 'BlogExample']
1952  ];
1953  }
1954 
1959  public function camelCaseToLowerCaseUnderscored($expected, $inputString)
1960  {
1961  $this->assertEquals($expected, GeneralUtility::camelCaseToLowerCaseUnderscored($inputString));
1962  }
1963 
1965  // Tests concerning lcFirst
1967 
1972  public function lcfirstDataProvider()
1973  {
1974  return [
1975  'single word' => ['blogexample', 'blogexample'],
1976  'single Word starting upper case' => ['blogexample', 'Blogexample'],
1977  'two words' => ['blogExample', 'BlogExample']
1978  ];
1979  }
1980 
1985  public function lcFirst($expected, $inputString)
1986  {
1987  $this->assertEquals($expected, GeneralUtility::lcfirst($inputString));
1988  }
1989 
1991  // Tests concerning encodeHeader
1993 
1997  {
1998  $this->assertEquals('=?utf-8?Q?We_test_whether_the_copyright_character_=C2=A9_is_encoded_correctly?=', GeneralUtility::encodeHeader('We test whether the copyright character © is encoded correctly', 'quoted-printable', 'utf-8'));
1999  }
2000 
2005  {
2006  $this->assertEquals('=?utf-8?Q?Is_the_copyright_character_=C2=A9_really_encoded_correctly=3F_Really=3F?=', GeneralUtility::encodeHeader('Is the copyright character © really encoded correctly? Really?', 'quoted-printable', 'utf-8'));
2007  }
2008 
2010  // Tests concerning isValidUrl
2012 
2018  {
2019  return [
2020  'http' => ['http://www.example.org/'],
2021  'http without trailing slash' => ['http://qwe'],
2022  'http directory with trailing slash' => ['http://www.example/img/dir/'],
2023  'http directory without trailing slash' => ['http://www.example/img/dir'],
2024  'http index.html' => ['http://example.com/index.html'],
2025  'http index.php' => ['http://www.example.com/index.php'],
2026  'http test.png' => ['http://www.example/img/test.png'],
2027  'http username password querystring and ancher' => ['https://user:pw@www.example.org:80/path?arg=value#fragment'],
2028  'file' => ['file:///tmp/test.c'],
2029  'file directory' => ['file://foo/bar'],
2030  'ftp directory' => ['ftp://ftp.example.com/tmp/'],
2031  'mailto' => ['mailto:foo@bar.com'],
2032  'news' => ['news:news.php.net'],
2033  'telnet' => ['telnet://192.0.2.16:80/'],
2034  'ldap' => ['ldap://[2001:db8::7]/c=GB?objectClass?one'],
2035  'http punycode domain name' => ['http://www.xn--bb-eka.at'],
2036  'http punicode subdomain' => ['http://xn--h-zfa.oebb.at'],
2037  'http domain-name umlauts' => ['http://www.öbb.at'],
2038  'http subdomain umlauts' => ['http://äh.oebb.at'],
2039  ];
2040  }
2041 
2047  {
2048  $this->assertTrue(GeneralUtility::isValidUrl($url));
2049  }
2050 
2057  {
2058  return [
2059  'http missing colon' => ['http//www.example/wrong/url/'],
2060  'http missing slash' => ['http:/www.example'],
2061  'hostname only' => ['www.example.org/'],
2062  'file missing protocol specification' => ['/tmp/test.c'],
2063  'slash only' => ['/'],
2064  'string http://' => ['http://'],
2065  'string http:/' => ['http:/'],
2066  'string http:' => ['http:'],
2067  'string http' => ['http'],
2068  'empty string' => [''],
2069  'string -1' => ['-1'],
2070  'string array()' => ['array()'],
2071  'random string' => ['qwe'],
2072  'http directory umlauts' => ['http://www.oebb.at/äöü/'],
2073  'prohibited input characters' => ['https://{$unresolved_constant}'],
2074  ];
2075  }
2076 
2082  {
2083  $this->assertFalse(GeneralUtility::isValidUrl($url));
2084  }
2085 
2087  // Tests concerning isOnCurrentHost
2089 
2093  {
2094  $testUrl = GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL');
2095  $this->assertTrue(GeneralUtility::isOnCurrentHost($testUrl));
2096  }
2097 
2104  {
2105  return [
2106  'empty string' => [''],
2107  'arbitrary string' => ['arbitrary string'],
2108  'localhost IP' => ['127.0.0.1'],
2109  'relative path' => ['./relpath/file.txt'],
2110  'absolute path' => ['/abspath/file.txt?arg=value'],
2111  'differnt host' => [GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST') . '.example.org']
2112  ];
2113  }
2114 
2116  // Tests concerning sanitizeLocalUrl
2118 
2124  {
2125  return [
2126  'alt_intro.php' => ['alt_intro.php'],
2127  'alt_intro.php?foo=1&bar=2' => ['alt_intro.php?foo=1&bar=2'],
2128  '../index.php' => ['../index.php'],
2129  '../typo3/alt_intro.php' => ['../typo3/alt_intro.php'],
2130  '../~userDirectory/index.php' => ['../~userDirectory/index.php'],
2131  '../typo3/index.php?var1=test-case&var2=~user' => ['../typo3/index.php?var1=test-case&var2=~user'],
2132  PATH_site . 'typo3/alt_intro.php' => [PATH_site . 'typo3/alt_intro.php'],
2133  ];
2134  }
2135 
2142  {
2143  $this->assertEquals($path, GeneralUtility::sanitizeLocalUrl($path));
2144  }
2145 
2152  {
2153  $this->assertEquals(rawurlencode($path), GeneralUtility::sanitizeLocalUrl(rawurlencode($path)));
2154  }
2155 
2162  {
2163  $host = 'localhost';
2164  $subDirectory = '/cms/';
2165 
2166  return [
2167  $subDirectory . 'typo3/alt_intro.php' => [
2168  $subDirectory . 'typo3/alt_intro.php',
2169  $host,
2170  $subDirectory,
2171  ],
2172  $subDirectory . 'index.php' => [
2173  $subDirectory . 'index.php',
2174  $host,
2175  $subDirectory,
2176  ],
2177  'http://' . $host . '/typo3/alt_intro.php' => [
2178  'http://' . $host . '/typo3/alt_intro.php',
2179  $host,
2180  '',
2181  ],
2182  'http://' . $host . $subDirectory . 'typo3/alt_intro.php' => [
2183  'http://' . $host . $subDirectory . 'typo3/alt_intro.php',
2184  $host,
2185  $subDirectory,
2186  ],
2187  ];
2188  }
2189 
2197  public function sanitizeLocalUrlAcceptsNotEncodedValidUrls($url, $host, $subDirectory)
2198  {
2199  $_SERVER['HTTP_HOST'] = $host;
2200  $_SERVER['SCRIPT_NAME'] = $subDirectory . 'typo3/index.php';
2202  $this->assertEquals($url, GeneralUtility::sanitizeLocalUrl($url));
2203  }
2204 
2212  public function sanitizeLocalUrlAcceptsEncodedValidUrls($url, $host, $subDirectory)
2213  {
2214  $_SERVER['HTTP_HOST'] = $host;
2215  $_SERVER['SCRIPT_NAME'] = $subDirectory . 'typo3/index.php';
2217  $this->assertEquals(rawurlencode($url), GeneralUtility::sanitizeLocalUrl(rawurlencode($url)));
2218  }
2219 
2226  {
2227  return [
2228  'empty string' => [''],
2229  'http domain' => ['http://www.google.de/'],
2230  'https domain' => ['https://www.google.de/'],
2231  'relative path with XSS' => ['../typo3/whatever.php?argument=javascript:alert(0)'],
2232  'base64 encoded string' => ['data:%20text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4='],
2233  ];
2234  }
2235 
2241  {
2242  $this->assertEquals('', GeneralUtility::sanitizeLocalUrl($url));
2243  }
2244 
2250  {
2251  $this->assertEquals('', GeneralUtility::sanitizeLocalUrl(rawurlencode($url)));
2252  }
2253 
2255  // Tests concerning unlink_tempfile
2257 
2262  {
2263  $fixtureFile = __DIR__ . '/Fixtures/clear.gif';
2264  $testFilename = PATH_site . 'typo3temp/' . $this->getUniqueId('test_') . '.gif';
2265  @copy($fixtureFile, $testFilename);
2266  GeneralUtility::unlink_tempfile($testFilename);
2267  $fileExists = file_exists($testFilename);
2268  $this->assertFalse($fileExists);
2269  }
2270 
2275  {
2276  $fixtureFile = __DIR__ . '/Fixtures/clear.gif';
2277  $testFilename = PATH_site . 'typo3temp/' . $this->getUniqueId('.test_') . '.gif';
2278  @copy($fixtureFile, $testFilename);
2279  GeneralUtility::unlink_tempfile($testFilename);
2280  $fileExists = file_exists($testFilename);
2281  $this->assertFalse($fileExists);
2282  }
2283 
2288  {
2289  $fixtureFile = __DIR__ . '/Fixtures/clear.gif';
2290  $testFilename = PATH_site . 'typo3temp/' . $this->getUniqueId('test_') . '.gif';
2291  @copy($fixtureFile, $testFilename);
2292  $returnValue = GeneralUtility::unlink_tempfile($testFilename);
2293  $this->assertTrue($returnValue);
2294  }
2295 
2300  {
2301  $returnValue = GeneralUtility::unlink_tempfile(PATH_site . 'typo3temp/' . $this->getUniqueId('i_do_not_exist'));
2302  $this->assertNull($returnValue);
2303  }
2304 
2309  {
2310  $returnValue = GeneralUtility::unlink_tempfile('/tmp/typo3-unit-test-unlink_tempfile');
2311  $this->assertNull($returnValue);
2312  }
2313 
2315  // Tests concerning tempnam
2317 
2322  {
2323  $filePath = GeneralUtility::tempnam('foo');
2324  $this->testFilesToDelete[] = $filePath;
2325  $fileName = basename($filePath);
2326  $this->assertStringStartsWith('foo', $fileName);
2327  }
2328 
2333  {
2334  $filePath = GeneralUtility::tempnam('foo');
2335  $this->testFilesToDelete[] = $filePath;
2336  $this->assertNotContains('\\', $filePath);
2337  }
2338 
2343  {
2344  $filePath = GeneralUtility::tempnam('foo');
2345  $this->testFilesToDelete[] = $filePath;
2346  $this->assertStringStartsWith(PATH_site, $filePath);
2347  }
2348 
2350  // Tests concerning addSlashesOnArray
2352 
2356  {
2357  $inputArray = [
2358  'key1' => [
2359  'key11' => 'val\'ue1',
2360  'key12' => 'val"ue2'
2361  ],
2362  'key2' => 'val\\ue3'
2363  ];
2364  $expectedResult = [
2365  'key1' => [
2366  'key11' => 'val\\\'ue1',
2367  'key12' => 'val\\"ue2'
2368  ],
2369  'key2' => 'val\\\\ue3'
2370  ];
2371  GeneralUtility::addSlashesOnArray($inputArray);
2372  $this->assertEquals($expectedResult, $inputArray);
2373  }
2374 
2376  // Tests concerning addSlashesOnArray
2378 
2382  {
2383  $inputArray = [
2384  'key1' => [
2385  'key11' => 'val\\\'ue1',
2386  'key12' => 'val\\"ue2'
2387  ],
2388  'key2' => 'val\\\\ue3'
2389  ];
2390  $expectedResult = [
2391  'key1' => [
2392  'key11' => 'val\'ue1',
2393  'key12' => 'val"ue2'
2394  ],
2395  'key2' => 'val\\ue3'
2396  ];
2398  $this->assertEquals($expectedResult, $inputArray);
2399  }
2400 
2402  // Tests concerning removeDotsFromTS
2404 
2408  {
2409  $typoScript = [
2410  'propertyA.' => [
2411  'keyA.' => [
2412  'valueA' => 1
2413  ],
2414  'keyB' => 2
2415  ],
2416  'propertyB' => 3
2417  ];
2418  $expectedResult = [
2419  'propertyA' => [
2420  'keyA' => [
2421  'valueA' => 1
2422  ],
2423  'keyB' => 2
2424  ],
2425  'propertyB' => 3
2426  ];
2427  $this->assertEquals($expectedResult, GeneralUtility::removeDotsFromTS($typoScript));
2428  }
2429 
2434  {
2435  $typoScript = [
2436  'propertyA.' => [
2437  'keyA' => 'getsOverridden',
2438  'keyA.' => [
2439  'valueA' => 1
2440  ],
2441  'keyB' => 2
2442  ],
2443  'propertyB' => 3
2444  ];
2445  $expectedResult = [
2446  'propertyA' => [
2447  'keyA' => [
2448  'valueA' => 1
2449  ],
2450  'keyB' => 2
2451  ],
2452  'propertyB' => 3
2453  ];
2454  $this->assertEquals($expectedResult, GeneralUtility::removeDotsFromTS($typoScript));
2455  }
2456 
2461  {
2462  $typoScript = [
2463  'propertyA.' => [
2464  'keyA.' => [
2465  'valueA' => 1
2466  ],
2467  'keyA' => 'willOverride',
2468  'keyB' => 2
2469  ],
2470  'propertyB' => 3
2471  ];
2472  $expectedResult = [
2473  'propertyA' => [
2474  'keyA' => 'willOverride',
2475  'keyB' => 2
2476  ],
2477  'propertyB' => 3
2478  ];
2479  $this->assertEquals($expectedResult, GeneralUtility::removeDotsFromTS($typoScript));
2480  }
2481 
2483  // Tests concerning get_dirs
2485 
2489  {
2490  $path = PATH_typo3conf;
2491  $directories = GeneralUtility::get_dirs($path);
2492  $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $directories);
2493  }
2494 
2499  {
2500  $path = 'foo';
2501  $result = GeneralUtility::get_dirs($path);
2502  $expectedResult = 'error';
2503  $this->assertEquals($expectedResult, $result);
2504  }
2505 
2507  // Tests concerning hmac
2509 
2513  {
2514  $hmac = GeneralUtility::hmac('message');
2515  $this->assertTrue(!empty($hmac) && is_string($hmac));
2516  $this->assertTrue(strlen($hmac) == 40);
2517  }
2518 
2523  {
2524  $msg0 = 'message';
2525  $msg1 = 'message';
2526  $this->assertEquals(GeneralUtility::hmac($msg0), GeneralUtility::hmac($msg1));
2527  }
2528 
2533  {
2534  $msg0 = 'message0';
2535  $msg1 = 'message1';
2536  $this->assertNotEquals(GeneralUtility::hmac($msg0), GeneralUtility::hmac($msg1));
2537  }
2538 
2540  // Tests concerning quoteJSvalue
2542 
2547  public function quoteJsValueDataProvider()
2548  {
2549  return [
2550  'Immune characters are returned as is' => [
2551  '._,',
2552  '._,'
2553  ],
2554  'Alphanumerical characters are returned as is' => [
2555  'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
2556  'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
2557  ],
2558  'Angle brackets and ampersand are encoded' => [
2559  '<>&',
2560  '\\u003C\\u003E\\u0026'
2561  ],
2562  'Quotes and backslashes are encoded' => [
2563  '"\'\\',
2564  '\\u0022\\u0027\\u005C'
2565  ],
2566  'Forward slashes are escaped' => [
2567  '</script>',
2568  '\\u003C\\/script\\u003E'
2569  ],
2570  'Empty string stays empty' => [
2571  '',
2572  ''
2573  ],
2574  'Exclamation mark and space are properly encoded' => [
2575  'Hello World!',
2576  'Hello\\u0020World\\u0021'
2577  ],
2578  'Whitespaces are properly encoded' => [
2579  TAB . LF . CR . ' ',
2580  '\\u0009\\u000A\\u000D\\u0020'
2581  ],
2582  'Null byte is properly encoded' => [
2583  chr(0),
2584  '\\u0000'
2585  ],
2586  'Umlauts are properly encoded' => [
2587  'ÜüÖöÄä',
2588  '\\u00dc\\u00fc\\u00d6\\u00f6\\u00c4\\u00e4'
2589  ]
2590  ];
2591  }
2592 
2599  public function quoteJsValueTest($input, $expected)
2600  {
2601  $this->assertSame('\'' . $expected . '\'', GeneralUtility::quoteJSvalue($input));
2602  }
2603 
2605  // Tests concerning _GETset()
2607 
2611  {
2612  $_GET = [];
2613  $GLOBALS['HTTP_GET_VARS'] = [];
2614  $getParameters = ['foo' => 'bar'];
2615  GeneralUtility::_GETset($getParameters);
2616  $this->assertSame($getParameters, $_GET);
2617  }
2618 
2623  {
2624  $_GET = [];
2625  $GLOBALS['HTTP_GET_VARS'] = [];
2626  $getParameters = ['foo' => 'bar'];
2627  GeneralUtility::_GETset($getParameters);
2628  $this->assertSame($getParameters, $GLOBALS['HTTP_GET_VARS']);
2629  }
2630 
2635  {
2636  $_GET = [];
2637  $GLOBALS['HTTP_GET_VARS'] = [];
2638  GeneralUtility::_GETset(['foo' => 'bar']);
2639  GeneralUtility::_GETset(['oneKey' => 'oneValue']);
2640  $this->assertEquals(['oneKey' => 'oneValue'], $GLOBALS['HTTP_GET_VARS']);
2641  }
2642 
2647  {
2648  $_GET = [];
2649  $GLOBALS['HTTP_GET_VARS'] = [];
2650  GeneralUtility::_GETset('oneValue', 'oneKey');
2651  $this->assertEquals('oneValue', $GLOBALS['HTTP_GET_VARS']['oneKey']);
2652  }
2653 
2658  {
2659  $_GET = [];
2660  $GLOBALS['HTTP_GET_VARS'] = [];
2661  GeneralUtility::_GETset(['foo' => 'bar']);
2662  GeneralUtility::_GETset('oneValue', 'oneKey');
2663  $this->assertEquals(['foo' => 'bar', 'oneKey' => 'oneValue'], $GLOBALS['HTTP_GET_VARS']);
2664  }
2665 
2670  {
2671  $_GET = [];
2672  $GLOBALS['HTTP_GET_VARS'] = [];
2673  GeneralUtility::_GETset(['childKey' => 'oneValue'], 'parentKey');
2674  $this->assertEquals(['parentKey' => ['childKey' => 'oneValue']], $GLOBALS['HTTP_GET_VARS']);
2675  }
2676 
2681  {
2682  $_GET = [];
2683  $GLOBALS['HTTP_GET_VARS'] = [];
2684  GeneralUtility::_GETset('oneValue', 'parentKey|childKey');
2685  $this->assertEquals(['parentKey' => ['childKey' => 'oneValue']], $GLOBALS['HTTP_GET_VARS']);
2686  }
2687 
2692  {
2693  $_GET = [];
2694  $GLOBALS['HTTP_GET_VARS'] = [];
2695  GeneralUtility::_GETset(['key1' => 'value1', 'key2' => 'value2'], 'parentKey|childKey');
2696  $this->assertEquals([
2697  'parentKey' => [
2698  'childKey' => ['key1' => 'value1', 'key2' => 'value2']
2699  ]
2700  ], $GLOBALS['HTTP_GET_VARS']);
2701  }
2702 
2704  // Tests concerning minifyJavaScript
2706 
2710  {
2711  unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript']);
2712  $testString = $this->getUniqueId('string');
2713  $this->assertSame($testString, GeneralUtility::minifyJavaScript($testString));
2714  }
2715 
2723  {
2724  $hookClassName = $this->getUniqueId('tx_coretest');
2725  $minifyHookMock = $this->getMock('stdClass', ['minify'], [], $hookClassName);
2726  $functionName = $hookClassName . '->minify';
2727  $GLOBALS['T3_VAR']['callUserFunction'][$functionName] = [];
2728  $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['obj'] = $minifyHookMock;
2729  $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['method'] = 'minify';
2730  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'][] = $functionName;
2731  $minifyHookMock->expects($this->once())->method('minify')->will($this->returnCallback([$this, 'isMinifyJavaScriptHookCalledCallback']));
2733  }
2734 
2741  {
2742  // We can not throw an exception here, because that would be caught by the
2743  // minifyJavaScript method under test itself. Thus, we just die if the
2744  // input string is not ok.
2745  if ($params['script'] !== 'foo') {
2746  die('broken');
2747  }
2748  }
2749 
2757  {
2758  $hookClassName = $this->getUniqueId('tx_coretest');
2759  $minifyHookMock = $this->getMock('stdClass', ['minify'], [], $hookClassName);
2760  $functionName = '&' . $hookClassName . '->minify';
2761  $GLOBALS['T3_VAR']['callUserFunction'][$functionName] = [];
2762  $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['obj'] = $minifyHookMock;
2763  $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['method'] = 'minify';
2764  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'][] = $functionName;
2765  $minifyHookMock->expects($this->any())->method('minify')->will($this->returnCallback([$this, 'minifyJavaScriptErroneousCallback']));
2766  $error = '';
2767  GeneralUtility::minifyJavaScript('string to compress', $error);
2768  $this->assertSame('Error minifying java script: foo', $error);
2769  }
2770 
2778  {
2779  $hookClassName = $this->getUniqueId('tx_coretest');
2780  $minifyHookMock = $this->getMock('stdClass', ['minify'], [], $hookClassName);
2781  $functionName = '&' . $hookClassName . '->minify';
2782  $GLOBALS['T3_VAR']['callUserFunction'][$functionName] = [];
2783  $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['obj'] = $minifyHookMock;
2784  $GLOBALS['T3_VAR']['callUserFunction'][$functionName]['method'] = 'minify';
2785  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'][] = $functionName;
2786  $minifyHookMock->expects($this->any())->method('minify')->will($this->returnCallback([$this, 'minifyJavaScriptErroneousCallback']));
2787  $this->setExpectedException('\\RuntimeException');
2789  }
2790 
2799  {
2800  throw new \RuntimeException('foo', 1344888548);
2801  }
2802 
2804  // Tests concerning fixPermissions
2806 
2809  public function fixPermissionsSetsGroup()
2810  {
2811  if (TYPO3_OS === 'WIN') {
2812  $this->markTestSkipped('fixPermissionsSetsGroup() tests not available on Windows');
2813  }
2814  if (!function_exists('posix_getegid')) {
2815  $this->markTestSkipped('Function posix_getegid() not available, fixPermissionsSetsGroup() tests skipped');
2816  }
2817  if (posix_getegid() === -1) {
2818  $this->markTestSkipped('The fixPermissionsSetsGroup() is not available on Mac OS because posix_getegid() always returns -1 on Mac OS.');
2819  }
2820  // Create and prepare test file
2821  $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2823  $currentGroupId = posix_getegid();
2824  // Set target group and run method
2825  $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $currentGroupId;
2827  clearstatcache();
2828  $this->assertEquals($currentGroupId, filegroup($filename));
2829  }
2830 
2835  {
2836  if (TYPO3_OS === 'WIN') {
2837  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2838  }
2839  // Create and prepare test file
2840  $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2842  chmod($filename, 482);
2843  // Set target permissions and run method
2844  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
2845  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($filename);
2846  clearstatcache();
2847  $this->assertTrue($fixPermissionsResult);
2848  $this->assertEquals('0660', substr(decoct(fileperms($filename)), 2));
2849  }
2850 
2855  {
2856  if (TYPO3_OS === 'WIN') {
2857  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2858  }
2859  // Create and prepare test file
2860  $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2862  chmod($filename, 482);
2863  // Set target permissions and run method
2864  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
2865  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($filename);
2866  clearstatcache();
2867  $this->assertTrue($fixPermissionsResult);
2868  $this->assertEquals('0660', substr(decoct(fileperms($filename)), 2));
2869  }
2870 
2875  {
2876  if (TYPO3_OS === 'WIN') {
2877  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2878  }
2879  // Create and prepare test directory
2880  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2882  chmod($directory, 1551);
2883  // Set target permissions and run method
2884  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
2885  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory);
2886  clearstatcache();
2887  $this->assertTrue($fixPermissionsResult);
2888  $this->assertEquals('0770', substr(decoct(fileperms($directory)), 1));
2889  }
2890 
2895  {
2896  if (TYPO3_OS === 'WIN') {
2897  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2898  }
2899  // Create and prepare test directory
2900  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2902  chmod($directory, 1551);
2903  // Set target permissions and run method
2904  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
2905  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory . '/');
2906  // Get actual permissions and clean up
2907  clearstatcache();
2908  $this->assertTrue($fixPermissionsResult);
2909  $this->assertEquals('0770', substr(decoct(fileperms($directory)), 1));
2910  }
2911 
2916  {
2917  if (TYPO3_OS === 'WIN') {
2918  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2919  }
2920  // Create and prepare test directory
2921  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2923  chmod($directory, 1551);
2924  // Set target permissions and run method
2925  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
2926  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory);
2927  // Get actual permissions and clean up
2928  clearstatcache();
2929  $this->assertTrue($fixPermissionsResult);
2930  $this->assertEquals('0770', substr(decoct(fileperms($directory)), 1));
2931  }
2932 
2937  {
2938  if (TYPO3_OS === 'WIN') {
2939  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2940  }
2941  // Create and prepare test directory and file structure
2942  $baseDirectory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
2944  chmod($baseDirectory, 1751);
2945  GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($baseDirectory . '/file', '42');
2946  chmod($baseDirectory . '/file', 482);
2947  GeneralUtilityFilesystemFixture::mkdir($baseDirectory . '/foo');
2948  chmod($baseDirectory . '/foo', 1751);
2949  GeneralUtilityFilesystemFixture::writeFileToTypo3tempDir($baseDirectory . '/foo/file', '42');
2950  chmod($baseDirectory . '/foo/file', 482);
2951  GeneralUtilityFilesystemFixture::mkdir($baseDirectory . '/.bar');
2952  chmod($baseDirectory . '/.bar', 1751);
2953  // Use this if writeFileToTypo3tempDir is fixed to create hidden files in subdirectories
2954  // \TYPO3\CMS\Core\Utility\GeneralUtility::writeFileToTypo3tempDir($baseDirectory . '/.bar/.file', '42');
2955  // \TYPO3\CMS\Core\Utility\GeneralUtility::writeFileToTypo3tempDir($baseDirectory . '/.bar/..file2', '42');
2956  touch($baseDirectory . '/.bar/.file', '42');
2957  chmod($baseDirectory . '/.bar/.file', 482);
2958  touch($baseDirectory . '/.bar/..file2', '42');
2959  chmod($baseDirectory . '/.bar/..file2', 482);
2960  // Set target permissions and run method
2961  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
2962  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0770';
2963  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($baseDirectory, true);
2964  // Get actual permissions
2965  clearstatcache();
2966  $resultBaseDirectoryPermissions = substr(decoct(fileperms($baseDirectory)), 1);
2967  $resultBaseFilePermissions = substr(decoct(fileperms($baseDirectory . '/file')), 2);
2968  $resultFooDirectoryPermissions = substr(decoct(fileperms($baseDirectory . '/foo')), 1);
2969  $resultFooFilePermissions = substr(decoct(fileperms($baseDirectory . '/foo/file')), 2);
2970  $resultBarDirectoryPermissions = substr(decoct(fileperms($baseDirectory . '/.bar')), 1);
2971  $resultBarFilePermissions = substr(decoct(fileperms($baseDirectory . '/.bar/.file')), 2);
2972  $resultBarFile2Permissions = substr(decoct(fileperms($baseDirectory . '/.bar/..file2')), 2);
2973  // Test if everything was ok
2974  $this->assertTrue($fixPermissionsResult);
2975  $this->assertEquals('0770', $resultBaseDirectoryPermissions);
2976  $this->assertEquals('0660', $resultBaseFilePermissions);
2977  $this->assertEquals('0770', $resultFooDirectoryPermissions);
2978  $this->assertEquals('0660', $resultFooFilePermissions);
2979  $this->assertEquals('0770', $resultBarDirectoryPermissions);
2980  $this->assertEquals('0660', $resultBarFilePermissions);
2981  $this->assertEquals('0660', $resultBarFile2Permissions);
2982  }
2983 
2988  {
2989  if (TYPO3_OS === 'WIN') {
2990  $this->markTestSkipped('fixPermissions() tests not available on Windows');
2991  }
2992  // Create and prepare test file
2993  $filename = PATH_site . 'typo3temp/../typo3temp/' . $this->getUniqueId('test_');
2994  // Set target permissions and run method
2995  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
2996  $fixPermissionsResult = GeneralUtility::fixPermissions($filename);
2997  $this->assertFalse($fixPermissionsResult);
2998  }
2999 
3004  {
3005  if (TYPO3_OS === 'WIN') {
3006  $this->markTestSkipped('fixPermissions() tests not available on Windows');
3007  }
3008  $filename = 'typo3temp/' . $this->getUniqueId('test_');
3009  GeneralUtility::writeFileToTypo3tempDir(PATH_site . $filename, '42');
3010  $this->testFilesToDelete[] = PATH_site . $filename;
3011  chmod(PATH_site . $filename, 482);
3012  // Set target permissions and run method
3013  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0660';
3014  $fixPermissionsResult = GeneralUtility::fixPermissions($filename);
3015  clearstatcache();
3016  $this->assertTrue($fixPermissionsResult);
3017  $this->assertEquals('0660', substr(decoct(fileperms(PATH_site . $filename)), 2));
3018  }
3019 
3024  {
3025  if (TYPO3_OS === 'WIN') {
3026  $this->markTestSkipped('fixPermissions() tests not available on Windows');
3027  }
3028  $filename = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
3030  chmod($filename, 482);
3031  unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask']);
3032  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($filename);
3033  clearstatcache();
3034  $this->assertTrue($fixPermissionsResult);
3035  $this->assertEquals('0644', substr(decoct(fileperms($filename)), 2));
3036  }
3037 
3042  {
3043  if (TYPO3_OS === 'WIN') {
3044  $this->markTestSkipped('fixPermissions() tests not available on Windows');
3045  }
3046  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
3048  chmod($directory, 1551);
3049  unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask']);
3050  $fixPermissionsResult = GeneralUtilityFilesystemFixture::fixPermissions($directory);
3051  clearstatcache();
3052  $this->assertTrue($fixPermissionsResult);
3053  $this->assertEquals('0755', substr(decoct(fileperms($directory)), 1));
3054  }
3055 
3057  // Tests concerning mkdir
3059 
3062  public function mkdirCreatesDirectory()
3063  {
3064  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
3065  $mkdirResult = GeneralUtilityFilesystemFixture::mkdir($directory);
3066  clearstatcache();
3067  $this->assertTrue($mkdirResult);
3068  $this->assertTrue(is_dir($directory));
3069  }
3070 
3075  {
3076  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('.test_');
3077  $mkdirResult = GeneralUtilityFilesystemFixture::mkdir($directory);
3078  clearstatcache();
3079  $this->assertTrue($mkdirResult);
3080  $this->assertTrue(is_dir($directory));
3081  }
3082 
3087  {
3088  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_') . '/';
3089  $mkdirResult = GeneralUtilityFilesystemFixture::mkdir($directory);
3090  clearstatcache();
3091  $this->assertTrue($mkdirResult);
3092  $this->assertTrue(is_dir($directory));
3093  }
3094 
3099  {
3100  if (TYPO3_OS === 'WIN') {
3101  $this->markTestSkipped('mkdirSetsPermissionsOfCreatedDirectory() test not available on Windows');
3102  }
3103  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
3104  $oldUmask = umask(19);
3105  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0772';
3107  clearstatcache();
3108  $resultDirectoryPermissions = substr(decoct(fileperms($directory)), 1);
3109  umask($oldUmask);
3110  $this->assertEquals($resultDirectoryPermissions, '0772');
3111  }
3112 
3117  {
3118  $swapGroup = $this->checkGroups(__FUNCTION__);
3119  if ($swapGroup !== false) {
3120  $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $swapGroup;
3121  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('mkdirtest_');
3123  clearstatcache();
3124  $resultDirectoryGroup = filegroup($directory);
3125  $this->assertEquals($resultDirectoryGroup, $swapGroup);
3126  }
3127  }
3128 
3130  // Helper function for filesystem ownership tests
3132 
3139  private function checkGroups($methodName)
3140  {
3141  if (TYPO3_OS === 'WIN') {
3142  $this->markTestSkipped($methodName . '() test not available on Windows.');
3143  return false;
3144  }
3145  if (!function_exists('posix_getegid')) {
3146  $this->markTestSkipped('Function posix_getegid() not available, ' . $methodName . '() tests skipped');
3147  return false;
3148  }
3149  if (posix_getegid() === -1) {
3150  $this->markTestSkipped('Function posix_getegid() returns -1, ' . $methodName . '() tests skipped');
3151  return false;
3152  }
3153  if (!function_exists('posix_getgroups')) {
3154  $this->markTestSkipped('Function posix_getgroups() not available, ' . $methodName . '() tests skipped');
3155  return false;
3156  }
3157  $groups = posix_getgroups();
3158  if (count($groups) <= 1) {
3159  $this->markTestSkipped($methodName . '() test cannot be done when the web server user is only member of 1 group.');
3160  return false;
3161  }
3162  $secondaryGroups = array_diff($groups, [posix_getegid()]);
3163  return array_shift($secondaryGroups);
3164  }
3165 
3167  // Tests concerning mkdir_deep
3169 
3172  public function mkdirDeepCreatesDirectory()
3173  {
3174  $directory = $this->getVirtualTestDir() . '/' . $this->getUniqueId('test_');
3175  GeneralUtility::mkdir_deep($directory);
3176  $this->assertTrue(is_dir($directory));
3177  }
3178 
3183  {
3184  $directory = $this->getVirtualTestDir() . '/typo3temp/' . $this->getUniqueId('test_');
3185  $subDirectory = $directory . '/foo';
3186  GeneralUtility::mkdir_deep($subDirectory);
3187  $this->assertTrue(is_dir($subDirectory));
3188  }
3189 
3195  {
3196  return [
3197  'no double slash if concatenated with PATH_site' => ['fileadmin/testDir1'],
3198  'double slash if concatenated with PATH_site' => ['/fileadmin/testDir2'],
3199  ];
3200  }
3201 
3206  public function mkdirDeepCreatesDirectoryWithDoubleSlashes($directoryToCreate)
3207  {
3208  vfsStream::setup();
3209  // Load fixture files and folders from disk
3210  FileStreamWrapper::init(PATH_site);
3211  FileStreamWrapper::registerOverlayPath('fileadmin', 'vfs://root/fileadmin', true);
3212  GeneralUtility::mkdir_deep(PATH_site, $directoryToCreate);
3213  $this->assertTrue(is_dir(PATH_site . $directoryToCreate));
3215  }
3216 
3221  {
3222  if (TYPO3_OS === 'WIN') {
3223  $this->markTestSkipped('mkdirDeepFixesPermissionsOfCreatedDirectory() test not available on Windows.');
3224  }
3225  $directory = $this->getUniqueId('mkdirdeeptest_');
3226  $oldUmask = umask(19);
3227  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0777';
3228  GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $directory);
3229  $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
3230  clearstatcache();
3231  umask($oldUmask);
3232  $this->assertEquals('777', substr(decoct(fileperms(PATH_site . 'typo3temp/' . $directory)), -3, 3));
3233  }
3234 
3239  {
3240  if (TYPO3_OS === 'WIN') {
3241  $this->markTestSkipped('mkdirDeepFixesPermissionsOnNewParentDirectory() test not available on Windows.');
3242  }
3243  $directory = $this->getUniqueId('mkdirdeeptest_');
3244  $subDirectory = $directory . '/bar';
3245  $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] = '0777';
3246  $oldUmask = umask(19);
3247  GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $subDirectory);
3248  $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
3249  clearstatcache();
3250  umask($oldUmask);
3251  $this->assertEquals('777', substr(decoct(fileperms(PATH_site . 'typo3temp/' . $directory)), -3, 3));
3252  }
3253 
3258  {
3259  if (TYPO3_OS === 'WIN') {
3260  $this->markTestSkipped('mkdirDeepDoesNotChangePermissionsOfExistingSubDirectories() test not available on Windows.');
3261  }
3262  $baseDirectory = PATH_site . 'typo3temp/';
3263  $existingDirectory = $this->getUniqueId('test_existing_') . '/';
3264  $newSubDirectory = $this->getUniqueId('test_new_');
3265  @mkdir(($baseDirectory . $existingDirectory));
3266  $this->testFilesToDelete[] = $baseDirectory . $existingDirectory;
3267  chmod($baseDirectory . $existingDirectory, 482);
3268  GeneralUtility::mkdir_deep($baseDirectory, $existingDirectory . $newSubDirectory);
3269  $this->assertEquals('0742', substr(decoct(fileperms($baseDirectory . $existingDirectory)), 2));
3270  }
3271 
3276  {
3277  $swapGroup = $this->checkGroups(__FUNCTION__);
3278  if ($swapGroup !== false) {
3279  $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $swapGroup;
3280  $directory = $this->getUniqueId('mkdirdeeptest_');
3281  GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $directory);
3282  $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
3283  clearstatcache();
3284  $resultDirectoryGroup = filegroup(PATH_site . 'typo3temp/' . $directory);
3285  $this->assertEquals($resultDirectoryGroup, $swapGroup);
3286  }
3287  }
3288 
3293  {
3294  $swapGroup = $this->checkGroups(__FUNCTION__);
3295  if ($swapGroup !== false) {
3296  $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $swapGroup;
3297  $directory = $this->getUniqueId('mkdirdeeptest_');
3298  $subDirectory = $directory . '/bar';
3299  GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $subDirectory);
3300  $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
3301  clearstatcache();
3302  $resultDirectoryGroup = filegroup(PATH_site . 'typo3temp/' . $directory);
3303  $this->assertEquals($resultDirectoryGroup, $swapGroup);
3304  }
3305  }
3306 
3311  {
3312  $swapGroup = $this->checkGroups(__FUNCTION__);
3313  if ($swapGroup !== false) {
3314  $GLOBALS['TYPO3_CONF_VARS']['SYS']['createGroup'] = $swapGroup;
3315  $directory = $this->getUniqueId('mkdirdeeptest_');
3316  $subDirectory = $directory . '/bar';
3317  GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/', $subDirectory);
3318  $this->testFilesToDelete[] = PATH_site . 'typo3temp/' . $directory;
3319  clearstatcache();
3320  $resultDirectoryGroup = filegroup(PATH_site . 'typo3temp/' . $directory);
3321  $this->assertEquals($resultDirectoryGroup, $swapGroup);
3322  }
3323  }
3324 
3329  {
3330  if (!class_exists('org\\bovigo\\vfs\\vfsStreamWrapper')) {
3331  $this->markTestSkipped('mkdirDeepCreatesDirectoryInVfsStream() test not available with this phpunit version.');
3332  }
3333  vfsStreamWrapper::register();
3334  $baseDirectory = $this->getUniqueId('test_');
3335  vfsStreamWrapper::setRoot(new vfsStreamDirectory($baseDirectory));
3336  GeneralUtility::mkdir_deep('vfs://' . $baseDirectory . '/', 'sub');
3337  $this->assertTrue(is_dir('vfs://' . $baseDirectory . '/sub'));
3338  }
3339 
3345  {
3346  GeneralUtility::mkdir_deep('http://localhost');
3347  }
3348 
3354  {
3356  }
3357 
3363  {
3364  GeneralUtility::mkdir_deep(PATH_site . 'typo3temp/foo', []);
3365  }
3366 
3368  // Tests concerning rmdir
3370 
3374  public function rmdirRemovesFile()
3375  {
3376  $file = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
3377  touch($file);
3378  GeneralUtility::rmdir($file);
3379  $this->assertFalse(file_exists($file));
3380  }
3381 
3386  {
3387  $file = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
3388  touch($file);
3389  $this->assertTrue(GeneralUtility::rmdir($file));
3390  }
3391 
3396  {
3397  $file = PATH_site . 'typo3temp/' . $this->getUniqueId('file_');
3398  $this->assertFalse(GeneralUtility::rmdir($file));
3399  }
3400 
3404  public function rmdirRemovesDirectory()
3405  {
3406  $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('directory_');
3407  mkdir($directory);
3408  GeneralUtility::rmdir($directory);
3409  $this->assertFalse(file_exists($directory));
3410  }
3411 
3416  {
3417  $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('directory_') . '/';
3418  mkdir($directory);
3419  GeneralUtility::rmdir($directory);
3420  $this->assertFalse(file_exists($directory));
3421  }
3422 
3427  {
3428  $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('directory_') . '/';
3429  mkdir($directory);
3430  $file = $this->getUniqueId('file_');
3431  touch($directory . $file);
3432  $this->testFilesToDelete[] = $directory;
3433  $return = GeneralUtility::rmdir($directory);
3434  $this->assertTrue(file_exists($directory));
3435  $this->assertTrue(file_exists($directory . $file));
3436  $this->assertFalse($return);
3437  }
3438 
3443  {
3444  $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('directory_') . '/';
3445  mkdir($directory);
3446  mkdir($directory . 'sub/');
3447  touch($directory . 'sub/file');
3448  $return = GeneralUtility::rmdir($directory, true);
3449  $this->assertFalse(file_exists($directory));
3450  $this->assertTrue($return);
3451  }
3452 
3457  {
3458  if (TYPO3_OS === 'WIN') {
3459  $this->markTestSkipped('Test not available on Windows OS.');
3460  }
3461  $existingDirectory = PATH_site . 'typo3temp/' . $this->getUniqueId('notExists_') . '/';
3462  mkdir($existingDirectory);
3463  $this->testFilesToDelete[] = $existingDirectory;
3464  $symlinkName = PATH_site . 'typo3temp/' . $this->getUniqueId('link_');
3465  symlink($existingDirectory, $symlinkName);
3466  GeneralUtility::rmdir($symlinkName, true);
3467  $this->assertFalse(is_link($symlinkName));
3468  }
3469 
3474  {
3475  if (TYPO3_OS === 'WIN') {
3476  $this->markTestSkipped('Test not available on Windows OS.');
3477  }
3478  $notExistingDirectory = PATH_site . 'typo3temp/' . $this->getUniqueId('notExists_') . '/';
3479  $symlinkName = PATH_site . 'typo3temp/' . $this->getUniqueId('link_');
3480  symlink($notExistingDirectory, $symlinkName);
3481  GeneralUtility::rmdir($symlinkName, true);
3482  $this->assertFalse(is_link($symlinkName));
3483  }
3484 
3488  public function rmdirRemovesDeadLinkToFile()
3489  {
3490  if (TYPO3_OS === 'WIN') {
3491  $this->markTestSkipped('Test not available on Windows OS.');
3492  }
3493  $notExistingFile = PATH_site . 'typo3temp/' . $this->getUniqueId('notExists_');
3494  $symlinkName = PATH_site . 'typo3temp/' . $this->getUniqueId('link_');
3495  symlink($notExistingFile, $symlinkName);
3496  GeneralUtility::rmdir($symlinkName, true);
3497  $this->assertFalse(is_link($symlinkName));
3498  }
3499 
3501  // Tests concerning getFilesInDir
3503 
3510  {
3511  if (!class_exists('org\\bovigo\\vfs\\vfsStreamWrapper')) {
3512  $this->markTestSkipped('getFilesInDirCreateTestDirectory() helper method not available without vfsStream.');
3513  }
3514  $structure = [
3515  'subDirectory' => [
3516  'test.php' => 'butter',
3517  'other.php' => 'milk',
3518  'stuff.csv' => 'honey',
3519  ],
3520  'excludeMe.txt' => 'cocoa nibs',
3521  'testB.txt' => 'olive oil',
3522  'testA.txt' => 'eggs',
3523  'testC.txt' => 'carrots',
3524  'test.js' => 'oranges',
3525  'test.css' => 'apples',
3526  '.secret.txt' => 'sammon',
3527  ];
3528  vfsStream::setup('test', null, $structure);
3529  $vfsUrl = vfsStream::url('test');
3530 
3531  // set random values for mtime
3532  foreach ($structure as $structureLevel1Key => $structureLevel1Content) {
3533  $newMtime = rand();
3534  if (is_array($structureLevel1Content)) {
3535  foreach ($structureLevel1Content as $structureLevel2Key => $structureLevel2Content) {
3536  touch($vfsUrl . '/' . $structureLevel1Key . '/' . $structureLevel2Key, $newMtime);
3537  }
3538  } else {
3539  touch($vfsUrl . '/' . $structureLevel1Key, $newMtime);
3540  }
3541  }
3542 
3543  return $vfsUrl;
3544  }
3545 
3550  {
3551  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3552  $files = GeneralUtility::getFilesInDir($vfsStreamUrl);
3553  $this->assertContains('testA.txt', $files);
3554  }
3555 
3560  {
3561  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3562  $files = GeneralUtility::getFilesInDir($vfsStreamUrl);
3563  $this->assertContains('.secret.txt', $files);
3564  }
3565 
3570  {
3571  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3572  $files = GeneralUtility::getFilesInDir($vfsStreamUrl, 'txt,js');
3573  $this->assertContains('testA.txt', $files);
3574  $this->assertContains('test.js', $files);
3575  }
3576 
3581  {
3582  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3583  $files = GeneralUtility::getFilesInDir($vfsStreamUrl, 'txt,js');
3584  $this->assertContains('testA.txt', $files);
3585  $this->assertContains('test.js', $files);
3586  $this->assertNotContains('test.css', $files);
3587  }
3588 
3593  {
3594  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3595  $files = GeneralUtility::getFilesInDir($vfsStreamUrl, '', false, '', 'excludeMe.*');
3596  $this->assertContains('test.js', $files);
3597  $this->assertNotContains('excludeMe.txt', $files);
3598  }
3599 
3604  {
3605  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3606  $this->assertContains(
3607  $vfsStreamUrl . '/testA.txt',
3608  GeneralUtility::getFilesInDir($vfsStreamUrl, '', true)
3609  );
3610  }
3611 
3616  {
3617  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3618  $this->assertSame(
3619  array_values(GeneralUtility::getFilesInDir($vfsStreamUrl, '', false)),
3620  ['.secret.txt', 'excludeMe.txt', 'test.css', 'test.js', 'testA.txt', 'testB.txt', 'testC.txt']
3621  );
3622  }
3623 
3628  {
3629  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3630  $files = [];
3631  $iterator = new \DirectoryIterator($vfsStreamUrl);
3632  foreach ($iterator as $fileinfo) {
3633  if ($fileinfo->isFile()) {
3634  $files[$fileinfo->getFilename()] = $fileinfo->getMTime();
3635  }
3636  }
3637  asort($files);
3638  $this->assertSame(
3639  array_values(GeneralUtility::getFilesInDir($vfsStreamUrl, '', false, 'mtime')),
3640  array_keys($files)
3641  );
3642  }
3643 
3648  {
3649  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3650  $this->assertArrayHasKey(
3651  md5($vfsStreamUrl . '/testA.txt'),
3652  GeneralUtility::getFilesInDir($vfsStreamUrl)
3653  );
3654  }
3655 
3660  {
3661  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3662  $this->assertNotContains(
3663  'subDirectory',
3664  GeneralUtility::getFilesInDir($vfsStreamUrl)
3665  );
3666  }
3667 
3675  {
3676  $vfsStreamUrl = $this->getFilesInDirCreateTestDirectory();
3677  $files = GeneralUtility::getFilesInDir($vfsStreamUrl);
3678  $this->assertNotContains('..', $files);
3679  $this->assertNotContains('.', $files);
3680  }
3681 
3683  // Tests concerning unQuoteFilenames
3685 
3691  {
3692  return [
3693  // Some theoretical tests first
3694  [
3695  '',
3696  [],
3697  []
3698  ],
3699  [
3700  'aa bb "cc" "dd"',
3701  ['aa', 'bb', '"cc"', '"dd"'],
3702  ['aa', 'bb', 'cc', 'dd']
3703  ],
3704  [
3705  'aa bb "cc dd"',
3706  ['aa', 'bb', '"cc dd"'],
3707  ['aa', 'bb', 'cc dd']
3708  ],
3709  [
3710  '\'aa bb\' "cc dd"',
3711  ['\'aa bb\'', '"cc dd"'],
3712  ['aa bb', 'cc dd']
3713  ],
3714  [
3715  '\'aa bb\' cc "dd"',
3716  ['\'aa bb\'', 'cc', '"dd"'],
3717  ['aa bb', 'cc', 'dd']
3718  ],
3719  // Now test against some real world examples
3720  [
3721  '/opt/local/bin/gm.exe convert +profile \'*\' -geometry 170x136! -negate "C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
3722  [
3723  '/opt/local/bin/gm.exe',
3724  'convert',
3725  '+profile',
3726  '\'*\'',
3727  '-geometry',
3728  '170x136!',
3729  '-negate',
3730  '"C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
3731  '"C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
3732  ],
3733  [
3734  '/opt/local/bin/gm.exe',
3735  'convert',
3736  '+profile',
3737  '*',
3738  '-geometry',
3739  '170x136!',
3740  '-negate',
3741  'C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
3742  'C:/Users/Someuser.Domain/Documents/Htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
3743  ]
3744  ],
3745  [
3746  'C:/opt/local/bin/gm.exe convert +profile \'*\' -geometry 170x136! -negate "C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
3747  [
3748  'C:/opt/local/bin/gm.exe',
3749  'convert',
3750  '+profile',
3751  '\'*\'',
3752  '-geometry',
3753  '170x136!',
3754  '-negate',
3755  '"C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
3756  '"C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
3757  ],
3758  [
3759  'C:/opt/local/bin/gm.exe',
3760  'convert',
3761  '+profile',
3762  '*',
3763  '-geometry',
3764  '170x136!',
3765  '-negate',
3766  'C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
3767  'C:/Program Files/Apache2/htdocs/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
3768  ]
3769  ],
3770  [
3771  '/usr/bin/gm convert +profile \'*\' -geometry 170x136! -negate "/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
3772  [
3773  '/usr/bin/gm',
3774  'convert',
3775  '+profile',
3776  '\'*\'',
3777  '-geometry',
3778  '170x136!',
3779  '-negate',
3780  '"/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
3781  '"/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
3782  ],
3783  [
3784  '/usr/bin/gm',
3785  'convert',
3786  '+profile',
3787  '*',
3788  '-geometry',
3789  '170x136!',
3790  '-negate',
3791  '/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
3792  '/Shared Items/Data/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
3793  ]
3794  ],
3795  [
3796  '/usr/bin/gm convert +profile \'*\' -geometry 170x136! -negate "/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]" "/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"',
3797  [
3798  '/usr/bin/gm',
3799  'convert',
3800  '+profile',
3801  '\'*\'',
3802  '-geometry',
3803  '170x136!',
3804  '-negate',
3805  '"/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]"',
3806  '"/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif"'
3807  ],
3808  [
3809  '/usr/bin/gm',
3810  'convert',
3811  '+profile',
3812  '*',
3813  '-geometry',
3814  '170x136!',
3815  '-negate',
3816  '/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
3817  '/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
3818  ]
3819  ],
3820  [
3821  '/usr/bin/gm convert +profile \'*\' -geometry 170x136! -negate \'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]\' \'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif\'',
3822  [
3823  '/usr/bin/gm',
3824  'convert',
3825  '+profile',
3826  '\'*\'',
3827  '-geometry',
3828  '170x136!',
3829  '-negate',
3830  '\'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]\'',
3831  '\'/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif\''
3832  ],
3833  [
3834  '/usr/bin/gm',
3835  'convert',
3836  '+profile',
3837  '*',
3838  '-geometry',
3839  '170x136!',
3840  '-negate',
3841  '/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif[0]',
3842  '/Network/Servers/server01.internal/Projects/typo3temp/temp/61401f5c16c63d58e1d92e8a2449f2fe_maskNT.gif'
3843  ]
3844  ]
3845  ];
3846  }
3847 
3854  public function explodeAndUnquoteImageMagickCommands($source, $expectedQuoted, $expectedUnquoted)
3855  {
3856  $actualQuoted = GeneralUtility::unQuoteFilenames($source);
3857  $actualUnquoted = GeneralUtility::unQuoteFilenames($source, true);
3858  $this->assertEquals($expectedQuoted, $actualQuoted, 'The exploded command does not match the expected');
3859  $this->assertEquals($expectedUnquoted, $actualUnquoted, 'The exploded and unquoted command does not match the expected');
3860  }
3861 
3863  // Tests concerning split_fileref
3865 
3869  {
3870  $directoryName = $this->getUniqueId('test_') . '.com';
3871  $directoryPath = PATH_site . 'typo3temp/';
3872  $directory = $directoryPath . $directoryName;
3873  mkdir($directory, octdec($GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask']));
3874  $fileInfo = GeneralUtility::split_fileref($directory);
3875  $directoryCreated = is_dir($directory);
3876  rmdir($directory);
3877  $this->assertTrue($directoryCreated);
3878  $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $fileInfo);
3879  $this->assertEquals($directoryPath, $fileInfo['path']);
3880  $this->assertEquals($directoryName, $fileInfo['file']);
3881  $this->assertEquals($directoryName, $fileInfo['filebody']);
3882  $this->assertEquals('', $fileInfo['fileext']);
3883  $this->assertArrayNotHasKey('realFileext', $fileInfo);
3884  }
3885 
3890  {
3891  $testFile = 'fileadmin/media/someFile.png';
3892  $fileInfo = GeneralUtility::split_fileref($testFile);
3893  $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $fileInfo);
3894  $this->assertEquals('fileadmin/media/', $fileInfo['path']);
3895  $this->assertEquals('someFile.png', $fileInfo['file']);
3896  $this->assertEquals('someFile', $fileInfo['filebody']);
3897  $this->assertEquals('png', $fileInfo['fileext']);
3898  }
3899 
3901  // Tests concerning dirname
3903 
3907  public function dirnameDataProvider()
3908  {
3909  return [
3910  'absolute path with multiple part and file' => ['/dir1/dir2/script.php', '/dir1/dir2'],
3911  'absolute path with one part' => ['/dir1/', '/dir1'],
3912  'absolute path to file without extension' => ['/dir1/something', '/dir1'],
3913  'relative path with one part and file' => ['dir1/script.php', 'dir1'],
3914  'relative one-character path with one part and file' => ['d/script.php', 'd'],
3915  'absolute zero-part path with file' => ['/script.php', ''],
3916  'empty string' => ['', '']
3917  ];
3918  }
3919 
3926  public function dirnameWithDataProvider($input, $expectedValue)
3927  {
3928  $this->assertEquals($expectedValue, GeneralUtility::dirname($input));
3929  }
3930 
3932  // Tests concerning resolveBackPath
3934 
3939  {
3940  return [
3941  'empty path' => ['', ''],
3942  'this directory' => ['./', './'],
3943  'relative directory without ..' => ['dir1/dir2/dir3/', 'dir1/dir2/dir3/'],
3944  'relative path without ..' => ['dir1/dir2/script.php', 'dir1/dir2/script.php'],
3945  'absolute directory without ..' => ['/dir1/dir2/dir3/', '/dir1/dir2/dir3/'],
3946  'absolute path without ..' => ['/dir1/dir2/script.php', '/dir1/dir2/script.php'],
3947  'only one directory upwards without trailing slash' => ['..', '..'],
3948  'only one directory upwards with trailing slash' => ['../', '../'],
3949  'one level with trailing ..' => ['dir1/..', ''],
3950  'one level with trailing ../' => ['dir1/../', ''],
3951  'two levels with trailing ..' => ['dir1/dir2/..', 'dir1'],
3952  'two levels with trailing ../' => ['dir1/dir2/../', 'dir1/'],
3953  'leading ../ without trailing /' => ['../dir1', '../dir1'],
3954  'leading ../ with trailing /' => ['../dir1/', '../dir1/'],
3955  'leading ../ and inside path' => ['../dir1/dir2/../dir3/', '../dir1/dir3/'],
3956  'one times ../ in relative directory' => ['dir1/../dir2/', 'dir2/'],
3957  'one times ../ in absolute directory' => ['/dir1/../dir2/', '/dir2/'],
3958  'one times ../ in relative path' => ['dir1/../dir2/script.php', 'dir2/script.php'],
3959  'one times ../ in absolute path' => ['/dir1/../dir2/script.php', '/dir2/script.php'],
3960  'consecutive ../' => ['dir1/dir2/dir3/../../../dir4', 'dir4'],
3961  'distrubuted ../ with trailing /' => ['dir1/../dir2/dir3/../', 'dir2/'],
3962  'distributed ../ without trailing /' => ['dir1/../dir2/dir3/..', 'dir2'],
3963  'multiple distributed and consecutive ../ together' => ['dir1/dir2/dir3/dir4/../../dir5/dir6/dir7/../dir8/', 'dir1/dir2/dir5/dir6/dir8/'],
3964  'dirname with leading ..' => ['dir1/..dir2/dir3/', 'dir1/..dir2/dir3/'],
3965  'dirname with trailing ..' => ['dir1/dir2../dir3/', 'dir1/dir2../dir3/'],
3966  'more times upwards than downwards in directory' => ['dir1/../../', '../'],
3967  'more times upwards than downwards in path' => ['dir1/../../script.php', '../script.php']
3968  ];
3969  }
3970 
3977  public function resolveBackPathWithDataProvider($input, $expectedValue)
3978  {
3979  $this->assertEquals($expectedValue, GeneralUtility::resolveBackPath($input));
3980  }
3981 
3983  // Tests concerning makeInstance, setSingletonInstance, addInstance, purgeInstances
3985 
3990  {
3992  }
3993 
3999  {
4001  }
4002 
4008  {
4010  }
4011 
4017  {
4019  }
4020 
4026  {
4028  }
4029 
4035  {
4036  GeneralUtility::makeInstance('\\TYPO3\\CMS\\Backend\\Controller\\BackendController');
4037  }
4038 
4043  {
4044  $className = get_class($this->getMock('foo'));
4045  $this->assertTrue(GeneralUtility::makeInstance($className) instanceof $className);
4046  }
4047 
4052  {
4053  $instance = GeneralUtility::makeInstance(TwoParametersConstructorFixture::class, 'one parameter', 'another parameter');
4054  $this->assertEquals('one parameter', $instance->constructorParameter1, 'The first constructor parameter has not been set.');
4055  $this->assertEquals('another parameter', $instance->constructorParameter2, 'The second constructor parameter has not been set.');
4056  }
4057 
4062  {
4064  $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][OriginalClassFixture::class] = ['className' => ReplacementClassFixture::class];
4065  $this->assertInstanceOf(ReplacementClassFixture::class, GeneralUtility::makeInstance(OriginalClassFixture::class));
4066  }
4067 
4072  {
4074  $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][OriginalClassFixture::class] = ['className' => ReplacementClassFixture::class];
4075  $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][ReplacementClassFixture::class] = ['className' => OtherReplacementClassFixture::class];
4076  $this->assertInstanceOf(OtherReplacementClassFixture::class, GeneralUtility::makeInstance(OriginalClassFixture::class));
4077  }
4078 
4083  {
4084  $className = get_class($this->getMock('foo'));
4085  $this->assertNotSame(GeneralUtility::makeInstance($className), GeneralUtility::makeInstance($className));
4086  }
4087 
4092  {
4093  $className = get_class($this->getMock(\TYPO3\CMS\Core\SingletonInterface::class));
4094  $this->assertSame(GeneralUtility::makeInstance($className), GeneralUtility::makeInstance($className));
4095  }
4096 
4101  {
4102  $className = get_class($this->getMock(\TYPO3\CMS\Core\SingletonInterface::class));
4103  $instance = GeneralUtility::makeInstance($className);
4105  $this->assertNotSame($instance, GeneralUtility::makeInstance($className));
4106  }
4107 
4113  {
4114  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4115  GeneralUtility::setSingletonInstance('', $instance);
4116  }
4117 
4123  {
4124  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class, ['foo']);
4125  $singletonClassName = get_class($this->getMock(\TYPO3\CMS\Core\SingletonInterface::class));
4126  GeneralUtility::setSingletonInstance($singletonClassName, $instance);
4127  }
4128 
4133  {
4134  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4135  $singletonClassName = get_class($instance);
4136  GeneralUtility::setSingletonInstance($singletonClassName, $instance);
4137  $this->assertSame($instance, GeneralUtility::makeInstance($singletonClassName));
4138  }
4139 
4144  {
4145  $instance1 = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4146  $singletonClassName = get_class($instance1);
4147  $instance2 = new $singletonClassName();
4148  GeneralUtility::setSingletonInstance($singletonClassName, $instance1);
4149  GeneralUtility::setSingletonInstance($singletonClassName, $instance2);
4150  $this->assertSame($instance2, GeneralUtility::makeInstance($singletonClassName));
4151  }
4152 
4157  {
4158  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4159  $instanceClassName = get_class($instance);
4160  GeneralUtility::setSingletonInstance($instanceClassName, $instance);
4161  $registeredSingletonInstances = GeneralUtility::getSingletonInstances();
4162  $this->assertArrayHasKey($instanceClassName, $registeredSingletonInstances);
4163  $this->assertSame($registeredSingletonInstances[$instanceClassName], $instance);
4164  }
4165 
4170  {
4171  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4172  $instanceClassName = get_class($instance);
4173  GeneralUtility::setSingletonInstance($instanceClassName, $instance);
4175  $registeredSingletonInstances = GeneralUtility::getSingletonInstances();
4176  $this->assertArrayNotHasKey($instanceClassName, $registeredSingletonInstances);
4177  }
4178 
4183  {
4184  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4185  $instanceClassName = get_class($instance);
4187  [$instanceClassName => $instance]
4188  );
4189  $registeredSingletonInstances = GeneralUtility::getSingletonInstances();
4190  $this->assertArrayHasKey($instanceClassName, $registeredSingletonInstances);
4191  $this->assertSame($registeredSingletonInstances[$instanceClassName], $instance);
4192  }
4193 
4199  {
4200  $instance = $this->getMock('foo');
4201  GeneralUtility::addInstance('', $instance);
4202  }
4203 
4209  {
4210  $instance = $this->getMock('foo', ['bar']);
4211  $singletonClassName = get_class($this->getMock('foo'));
4212  GeneralUtility::addInstance($singletonClassName, $instance);
4213  }
4214 
4220  {
4221  $instance = $this->getMock(\TYPO3\CMS\Core\SingletonInterface::class);
4222  GeneralUtility::addInstance(get_class($instance), $instance);
4223  }
4224 
4229  {
4230  $instance = $this->getMock('foo');
4231  $className = get_class($instance);
4232  GeneralUtility::addInstance($className, $instance);
4233  $this->assertSame($instance, GeneralUtility::makeInstance($className));
4234  }
4235 
4240  {
4241  $instance = $this->getMock('foo');
4242  $className = get_class($instance);
4243  GeneralUtility::addInstance($className, $instance);
4244  $this->assertNotSame(GeneralUtility::makeInstance($className), GeneralUtility::makeInstance($className));
4245  }
4246 
4251  {
4252  $instance1 = $this->getMock('foo');
4253  $className = get_class($instance1);
4254  GeneralUtility::addInstance($className, $instance1);
4255  $instance2 = new $className();
4256  GeneralUtility::addInstance($className, $instance2);
4257  $this->assertSame($instance1, GeneralUtility::makeInstance($className), 'The first returned instance does not match the first added instance.');
4258  $this->assertSame($instance2, GeneralUtility::makeInstance($className), 'The second returned instance does not match the second added instance.');
4259  }
4260 
4265  {
4266  $instance = $this->getMock('foo');
4267  $className = get_class($instance);
4268  GeneralUtility::addInstance($className, $instance);
4270  $this->assertNotSame($instance, GeneralUtility::makeInstance($className));
4271  }
4272 
4279  {
4280  $data = [
4281  'double slash in path' => ['path//path'],
4282  'backslash in path' => ['path\\path'],
4283  'directory up in path' => ['path/../path'],
4284  'directory up at the beginning' => ['../path'],
4285  'NUL character in path' => ['path' . chr(0) . 'path'],
4286  'BS character in path' => ['path' . chr(8) . 'path'],
4287  'invalid UTF-8-sequence' => ["\xc0" . 'path/path'],
4288  'Could be overlong NUL in some UTF-8 implementations, invalid in RFC3629' => ["\xc0\x80" . 'path/path'],
4289  ];
4290 
4291  // Mixing with regular utf-8
4292  $utf8Characters = 'Ссылка/';
4293  foreach ($data as $key => $value) {
4294  $data[$key . ' with UTF-8 characters prepended'] = [$utf8Characters . $value[0]];
4295  $data[$key . ' with UTF-8 characters appended'] = [$value[0] . $utf8Characters];
4296  }
4297 
4298  // Encoding with UTF-16
4299  foreach ($data as $key => $value) {
4300  $data[$key . ' encoded with UTF-16'] = [mb_convert_encoding($value[0], 'UTF-16')];
4301  }
4302 
4303  // Valid paths encoded with UTF-16
4304  $data['Valid path but UTF-16 encoded'] = [mb_convert_encoding('fileadmin/foo.txt', 'UTF-16')];
4305  $data['UTF-8 characters with UTF-16 encoded'] = [mb_convert_encoding('fileadmin/templates/Ссылка (fce).xml', 'UTF-16')];
4306 
4307  return $data;
4308  }
4309 
4318  {
4319  $this->assertFalse(GeneralUtility::validPathStr($path));
4320  }
4321 
4325  public function validPathStrDataProvider()
4326  {
4327  $data = [
4328  'normal ascii path' => ['fileadmin/templates/myfile..xml'],
4329  'special character' => ['fileadmin/templates/Ссылка (fce).xml']
4330  ];
4331 
4332  return $data;
4333  }
4334 
4342  {
4343  $this->assertTrue(GeneralUtility::validPathStr($path));
4344  }
4345 
4349  public function deniedFilesDataProvider()
4350  {
4351  return [
4352  'Nul character in file' => ['image' . chr(0) . '.gif'],
4353  'Nul character in file with .php' => ['image.php' . chr(0) . '.gif'],
4354  'Regular .php file' => ['file.php'],
4355  'Regular .php5 file' => ['file.php5'],
4356  'Regular .php3 file' => ['file.php3'],
4357  'Regular .phpsh file' => ['file.phpsh'],
4358  'Regular .phtml file' => ['file.phtml'],
4359  'Regular .pht file' => ['file.pht'],
4360  'PHP file in the middle' => ['file.php.txt'],
4361  '.htaccess file' => ['.htaccess'],
4362  ];
4363  }
4364 
4373  {
4374  $this->assertFalse(GeneralUtility::verifyFilenameAgainstDenyPattern($deniedFile));
4375  }
4376 
4378  // Tests concerning copyDirectory
4380 
4385  {
4386  $sourceDirectory = 'typo3temp/' . $this->getUniqueId('test_') . '/';
4387  $absoluteSourceDirectory = PATH_site . $sourceDirectory;
4388  $this->testFilesToDelete[] = $absoluteSourceDirectory;
4389  GeneralUtility::mkdir($absoluteSourceDirectory);
4390 
4391  $targetDirectory = 'typo3temp/' . $this->getUniqueId('test_') . '/';
4392  $absoluteTargetDirectory = PATH_site . $targetDirectory;
4393  $this->testFilesToDelete[] = $absoluteTargetDirectory;
4394  GeneralUtility::mkdir($absoluteTargetDirectory);
4395 
4396  GeneralUtility::writeFileToTypo3tempDir($absoluteSourceDirectory . 'file', '42');
4397  GeneralUtility::mkdir($absoluteSourceDirectory . 'foo');
4398  GeneralUtility::writeFileToTypo3tempDir($absoluteSourceDirectory . 'foo/file', '42');
4399 
4400  GeneralUtility::copyDirectory($sourceDirectory, $targetDirectory);
4401 
4402  $this->assertFileExists($absoluteTargetDirectory . 'file');
4403  $this->assertFileExists($absoluteTargetDirectory . 'foo/file');
4404  }
4405 
4410  {
4411  $sourceDirectory = 'typo3temp/' . $this->getUniqueId('test_') . '/';
4412  $absoluteSourceDirectory = PATH_site . $sourceDirectory;
4413  $this->testFilesToDelete[] = $absoluteSourceDirectory;
4414  GeneralUtility::mkdir($absoluteSourceDirectory);
4415 
4416  $targetDirectory = 'typo3temp/' . $this->getUniqueId('test_') . '/';
4417  $absoluteTargetDirectory = PATH_site . $targetDirectory;
4418  $this->testFilesToDelete[] = $absoluteTargetDirectory;
4419  GeneralUtility::mkdir($absoluteTargetDirectory);
4420 
4421  GeneralUtility::writeFileToTypo3tempDir($absoluteSourceDirectory . 'file', '42');
4422  GeneralUtility::mkdir($absoluteSourceDirectory . 'foo');
4423  GeneralUtility::writeFileToTypo3tempDir($absoluteSourceDirectory . 'foo/file', '42');
4424 
4425  GeneralUtility::copyDirectory($absoluteSourceDirectory, $absoluteTargetDirectory);
4426 
4427  $this->assertFileExists($absoluteTargetDirectory . 'file');
4428  $this->assertFileExists($absoluteTargetDirectory . 'foo/file');
4429  }
4430 
4432  // Tests concerning sysLog
4434 
4438  {
4439  if (TYPO3_OS === 'WIN') {
4440  $this->markTestSkipped('syslogFixesPermissionsOnFileIfUsingFileLogging() test not available on Windows.');
4441  }
4442  // Fake all required settings
4443  $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] = 0;
4444  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit'] = true;
4445  unset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog']);
4446  $testLogFilename = PATH_site . 'typo3temp/' . $this->getUniqueId('test_') . '.txt';
4447  $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog'] = 'file,' . $testLogFilename . ',0';
4448  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0777';
4449  // Call method, get actual permissions and clean up
4450  GeneralUtility::syslog('testLog', 'test', GeneralUtility::SYSLOG_SEVERITY_NOTICE);
4451  $this->testFilesToDelete[] = $testLogFilename;
4452  clearstatcache();
4453  $this->assertEquals('0777', substr(decoct(fileperms($testLogFilename)), 2));
4454  }
4455 
4460  {
4461  if (TYPO3_OS === 'WIN') {
4462  $this->markTestSkipped('deprecationLogFixesPermissionsOnLogFile() test not available on Windows.');
4463  }
4464  $filePath = PATH_site . GeneralUtilityFixture::DEPRECATION_LOG_PATH;
4465  @mkdir(dirname($filePath));
4466  $this->testFilesToDelete[] = $filePath;
4467  $GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog'] = true;
4468  $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] = '0777';
4470  clearstatcache();
4471  $resultFilePermissions = substr(decoct(fileperms($filePath)), 2);
4472  $this->assertEquals('0777', $resultFilePermissions);
4473  }
4474 
4476  // Tests concerning callUserFunction
4478 
4484  {
4485  $inputData = ['foo' => 'bar'];
4486  // omit the debug() output
4487  ob_start();
4488  $result = GeneralUtility::callUserFunction($functionName, $inputData, $this, 'user_', 1);
4489  ob_end_clean();
4490  $this->assertFalse($result);
4491  }
4492 
4499  {
4500  $inputData = ['foo' => 'bar'];
4501  GeneralUtility::callUserFunction($functionName, $inputData, $this, 'user_', 2);
4502  }
4503 
4511  {
4512  return [
4513  'Function is not prefixed' => ['t3lib_divTest->calledUserFunction'],
4514  'Class doesn\'t exists' => ['t3lib_divTest21345->user_calledUserFunction'],
4515  'No method name' => ['t3lib_divTest'],
4516  'No class name' => ['->user_calledUserFunction'],
4517  'No function name' => ['']
4518  ];
4519  }
4520 
4529  {
4530  $inputData = ['foo' => 'bar'];
4531  $result = GeneralUtility::callUserFunction(function () {
4532  return 'Worked fine';
4533  }, $inputData, $this, '');
4534  $this->assertEquals('Worked fine', $result);
4535  }
4536 
4541  {
4542  $inputData = ['foo' => 'bar'];
4543  $result = GeneralUtility::callUserFunction(self::class . '->user_calledUserFunction', $inputData, $this);
4544  $this->assertEquals('Worked fine', $result);
4545  }
4546 
4550  public function user_calledUserFunction()
4551  {
4552  return 'Worked fine';
4553  }
4554 
4559  {
4560  $inputData = ['foo' => 'bar'];
4561  $result = GeneralUtility::callUserFunction('typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php:TYPO3\\CMS\\Core\\Tests\\Unit\\Utility\GeneralUtilityTest->user_calledUserFunction', $inputData, $this);
4562  $this->assertEquals('Worked fine', $result);
4563  }
4564 
4569  {
4570  $inputData = ['called' => []];
4571  GeneralUtility::callUserFunction('&TYPO3\\CMS\\Core\\Tests\\Unit\\Utility\\GeneralUtilityTest->user_calledUserFunctionCountCallers', $inputData, $this);
4572  GeneralUtility::callUserFunction('&TYPO3\\CMS\\Core\\Tests\\Unit\\Utility\\GeneralUtilityTest->user_calledUserFunctionCountCallers', $inputData, $this);
4573  $this->assertEquals(1, count($inputData['called']));
4574  }
4575 
4584  {
4585  $params['called'][spl_object_hash($this)]++;
4586  }
4587 
4592  {
4593  $inputData = ['foo' => 'bar'];
4594  $closure = function ($parameters, $reference) use ($inputData) {
4595  $reference->assertEquals($inputData, $parameters, 'Passed data doesn\'t match expected output');
4596  return 'Worked fine';
4597  };
4598  $this->assertEquals('Worked fine', GeneralUtility::callUserFunction($closure, $inputData, $this));
4599  }
4600 
4602  // Tests concerning generateRandomBytes
4604 
4609  public function generateRandomBytesReturnsExpectedAmountOfBytes($numberOfBytes)
4610  {
4611  $this->assertEquals(strlen(GeneralUtility::generateRandomBytes($numberOfBytes)), $numberOfBytes);
4612  }
4613 
4615  {
4616  return [
4617  [1],
4618  [2],
4619  [3],
4620  [4],
4621  [7],
4622  [8],
4623  [31],
4624  [32],
4625  [100],
4626  [102],
4627  [4000],
4628  [4095],
4629  [4096],
4630  [4097],
4631  [8000]
4632  ];
4633  }
4634 
4641  {
4642  $results = [];
4643  $numberOfTests = 5;
4644  // generate a few random numbers
4645  for ($i = 0; $i < $numberOfTests; $i++) {
4646  $results[$i] = GeneralUtility::generateRandomBytes($numberOfBytes);
4647  }
4648  // array_unique would filter out duplicates
4649  $this->assertEquals($results, array_unique($results));
4650  }
4651 
4653  {
4654  return [
4655  [32],
4656  [128],
4657  [4096]
4658  ];
4659  }
4660 
4662  // Tests concerning substUrlsInPlainText
4664 
4668  {
4669  $urlMatch = 'http://example.com/index.php\\?RDCT=[0-9a-z]{20}';
4670  return [
4671  ['http://only-url.com', '|^' . $urlMatch . '$|'],
4672  ['https://only-secure-url.com', '|^' . $urlMatch . '$|'],
4673  ['A http://url in the sentence.', '|^A ' . $urlMatch . ' in the sentence\\.$|'],
4674  ['URL in round brackets (http://www.example.com) in the sentence.', '|^URL in round brackets \\(' . $urlMatch . '\\) in the sentence.$|'],
4675  ['URL in square brackets [http://www.example.com/a/b.php?c[d]=e] in the sentence.', '|^URL in square brackets \\[' . $urlMatch . '\\] in the sentence.$|'],
4676  ['URL in square brackets at the end of the sentence [http://www.example.com/a/b.php?c[d]=e].', '|^URL in square brackets at the end of the sentence \\[' . $urlMatch . '].$|'],
4677  ['Square brackets in the http://www.url.com?tt_news[uid]=1', '|^Square brackets in the ' . $urlMatch . '$|'],
4678  ['URL with http://dot.com.', '|^URL with ' . $urlMatch . '.$|'],
4679  ['URL in <a href="http://www.example.com/">a tag</a>', '|^URL in <a href="' . $urlMatch . '">a tag</a\\>$|'],
4680  ['URL in HTML <b>http://www.example.com</b><br />', '|^URL in HTML <b>' . $urlMatch . '</b><br />$|'],
4681  ['URL with http://username@example.com/', '|^URL with ' . $urlMatch . '$|'],
4682  ['Secret in URL http://username:secret@example.com', '|^Secret in URL ' . $urlMatch . '$|'],
4683  ['URL in quotation marks "http://example.com"', '|^URL in quotation marks "' . $urlMatch . '"$|'],
4684  ['URL with umlauts http://müller.de', '|^URL with umlauts ' . $urlMatch . '$|'],
4685  ['Multiline
4686 text with a http://url.com', '|^Multiline
4687 text with a ' . $urlMatch . '$|s'],
4688  ['http://www.shout.com!', '|^' . $urlMatch . '!$|'],
4689  ['And with two URLs http://www.two.com/abc http://urls.com/abc?x=1&y=2', '|^And with two URLs ' . $urlMatch . ' ' . $urlMatch . '$|']
4690  ];
4691  }
4692 
4699  public function substUrlsInPlainText($input, $expected)
4700  {
4701  $GLOBALS['TYPO3_DB'] = $this->getMock(\TYPO3\CMS\Core\Database\DatabaseConnection::class, [], [], '', false);
4702  $this->assertTrue(preg_match($expected, GeneralUtility::substUrlsInPlainText($input, 1, 'http://example.com/index.php')) == 1);
4703  }
4704 
4709  {
4710  return [
4711  'Extracts redirect URL from Location header' => ["HTTP/1.0 302 Redirect\r\nServer: Apache\r\nLocation: http://example.com/\r\nX-pad: avoid browser bug\r\n\r\nLocation: test\r\n", 'http://example.com/'],
4712  'Returns empty string if no Location is found in header' => ["HTTP/1.0 302 Redirect\r\nServer: Apache\r\nX-pad: avoid browser bug\r\n\r\nLocation: test\r\n", ''],
4713  ];
4714  }
4715 
4722  public function getRedirectUrlReturnsRedirectUrlFromHttpResponse($httpResponse, $expected)
4723  {
4724  $this->assertEquals($expected, GeneralUtilityFixture::getRedirectUrlFromHttpHeaders($httpResponse));
4725  }
4726 
4731  {
4732  return [
4733  'Simple content' => ["HTTP/1.0 302 Redirect\r\nServer: Apache\r\nX-pad: avoid browser bug\r\n\r\nHello, world!", 'Hello, world!'],
4734  'Content with multiple returns' => ["HTTP/1.0 302 Redirect\r\nServer: Apache\r\nX-pad: avoid browser bug\r\n\r\nHello, world!\r\n\r\nAnother hello here!", "Hello, world!\r\n\r\nAnother hello here!"],
4735  ];
4736  }
4737 
4744  public function stripHttpHeadersStripsHeadersFromHttpResponse($httpResponse, $expected)
4745  {
4746  $this->assertEquals($expected, GeneralUtilityFixture::stripHttpHeaders($httpResponse));
4747  }
4748 
4753  {
4754  $inputData = ['foo' => 'bar'];
4755  $result = GeneralUtility::callUserFunction("\t" . self::class . '->user_calledUserFunction ', $inputData, $this);
4756  $this->assertEquals('Worked fine', $result);
4757  }
4758 
4763  {
4764  $directory = PATH_site . 'typo3temp/' . $this->getUniqueId('directory_');
4765  mkdir($directory);
4766  $filesAndDirectories = GeneralUtility::getAllFilesAndFoldersInPath([], $directory, '', true);
4767  $check = true;
4768  foreach ($filesAndDirectories as $md5 => $path) {
4769  if (!preg_match('/^[a-f0-9]{32}$/', $md5)) {
4770  $check = false;
4771  }
4772  }
4773  GeneralUtility::rmdir($directory);
4774  $this->assertTrue($check);
4775  }
4776 
4784  {
4785  $input = [
4786  'el' => []
4787  ];
4788 
4789  $output = GeneralUtility::array2xml($input);
4790 
4791  $this->assertEquals('<phparray>
4792  <el type="array"></el>
4793 </phparray>', $output);
4794  }
4795 }
canSetNewGetInputValues($input, $key, $expected, $getPreset=[])
static compileSelectedGetVarsFromArray($varList, array $getArray, $GPvarAlt=true)
static stripSlashesOnArray(array &$theArray)
getRedirectUrlReturnsRedirectUrlFromHttpResponse($httpResponse, $expected)
static minifyJavaScript($script, &$error='')
static unlink_tempfile($uploadedTempFileName)
static substUrlsInPlainText($message, $urlmode='76', $index_script_url='')
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static mkdir_deep($directory, $deepDirectory='')
static addInstance($className, $instance)
static array2xml(array $array, $NSprefix='', $level=0, $docTag='phparray', $spaceInd=0, array $options=[], array $stackData=[])
static getFilesInDir($path, $extensionList='', $prependPath=false, $order='', $excludePattern='')
static registerOverlayPath($overlay, $replace, $createFolder=true)
static isFirstPartOfStr($str, $partStr)
trimExplodeReturnsCorrectResult($delimiter, $testString, $removeEmpty, $limit, $expectedResult)
revExplodeCorrectlyExplodesStringForGivenPartsCount($delimiter, $testString, $count, $expectedArray)
static setSingletonInstance($className, SingletonInterface $instance)
static writeFileToTypo3tempDir($filepath, $content)
rmFromListRemovesElementsFromCommaSeparatedList($initialList, $listWithElementRemoved)
static hmac($input, $additionalSecret='')
getIndpEnvForHostThrowsExceptionForNotAllowedHostnameValues($httpHost, $hostNamePattern)
static generateRandomBytes($bytesToReturn)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static verifyFilenameAgainstDenyPattern($filename)
static copyDirectory($source, $destination)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static _GETset($inputGet, $key='')
formatSizeTranslatesBytesToHigherOrderRepresentation($size, $labels, $base, $expected)
static resetSingletonInstances(array $newSingletonInstances)
static split_fileref($fileNameWithPath)
static addSlashesOnArray(array &$theArray)
static unQuoteFilenames($parameters, $unQuote=false)
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=false, $rawurlencodeParamName=false)
static fixPermissions($path, $recursive=false)
getIndpEnvTypo3PortParsesHostnamesAndIpAdresses($httpHost, $dummy, $expectedPort)
static getAllFilesAndFoldersInPath(array $fileArr, $path, $extList='', $regDirs=false, $recursivityLevels=99, $excludePattern='')
static getBytesFromSizeMeasurement($measurement)
static tempnam($filePrefix, $fileSuffix='')
static rmdir($path, $removeNonEmpty=false)
getBytesFromSizeMeasurementCalculatesCorrectByteValue($expected, $byteString)
static explodeUrl2Array($string, $multidim=false)
static splitCalc($string, $operators)
slashJsEscapesSingleQuotesAndSlashes($input, $extended, $expected)
static array_merge(array $arr1, array $arr2)
getIndpEnvForHostAllowsAllHostnameValuesIfHostPatternIsSetToAllowAll($httpHost, $hostNamePattern)
sanitizeLocalUrlAcceptsNotEncodedValidUrls($url, $host, $subDirectory)
explodeAndUnquoteImageMagickCommands($source, $expectedQuoted, $expectedUnquoted)
static formatSize($sizeInBytes, $labels='', $base=0)
isAllowedHostHeaderValueWorksCorrectlyWithWithServerNamePattern($httpHost, $serverName, $isAllowed, $serverPort='80', $ssl='Off')
$host
Definition: server.php:37
static revExplode($delimiter, $string, $count=0)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static slashJS($string, $extended=false, $char='\'')
isAllowedHostHeaderValueReturnsTrueIfHostValueMatches($httpHost, $hostNamePattern)
isAllowedHostHeaderValueReturnsFalseIfHostValueMatches($httpHost, $hostNamePattern)
static encodeHeader($line, $enc='quoted-printable', $charset='utf-8')
static uniqueList($in_list, $secondParameter=null)