TYPO3 CMS  TYPO3_6-2
GeneralUtility.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Utility;
3 
32 
33  // Severity constants used by \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog()
39 
42 
49  static protected $allowHostHeaderValue = FALSE;
50 
57  static protected $singletonInstances = array();
58 
64  static protected $nonSingletonInstances = array();
65 
71  static protected $finalClassNameCache = array();
72 
78  static protected $applicationContext = NULL;
79 
85  static protected $idnaStringCache = array();
86 
92  static protected $idnaConverter = NULL;
93 
99  static protected $supportedCgiServerApis = array(
100  'fpm-fcgi',
101  'cgi',
102  'isapi',
103  'cgi-fcgi',
104  'srv', // HHVM with fastcgi
105  );
106 
107  /*************************
108  *
109  * GET/POST Variables
110  *
111  * Background:
112  * Input GET/POST variables in PHP may have their quotes escaped with "\" or not depending on configuration.
113  * TYPO3 has always converted quotes to BE escaped if the configuration told that they would not be so.
114  * But the clean solution is that quotes are never escaped and that is what the functions below offers.
115  * Eventually TYPO3 should provide this in the global space as well.
116  * In the transitional phase (or forever..?) we need to encourage EVERY to read and write GET/POST vars through the API functions below.
117  *
118  *************************/
128  static public function _GP($var) {
129  if (empty($var)) {
130  return;
131  }
132  $value = isset($_POST[$var]) ? $_POST[$var] : $_GET[$var];
133  if (isset($value)) {
134  if (is_array($value)) {
135  self::stripSlashesOnArray($value);
136  } else {
137  $value = stripslashes($value);
138  }
139  }
140  return $value;
141  }
142 
149  static public function _GPmerged($parameter) {
150  $postParameter = isset($_POST[$parameter]) && is_array($_POST[$parameter]) ? $_POST[$parameter] : array();
151  $getParameter = isset($_GET[$parameter]) && is_array($_GET[$parameter]) ? $_GET[$parameter] : array();
152  $mergedParameters = $getParameter;
153  ArrayUtility::mergeRecursiveWithOverrule($mergedParameters, $postParameter);
154  self::stripSlashesOnArray($mergedParameters);
155  return $mergedParameters;
156  }
157 
166  static public function _GET($var = NULL) {
167  $value = $var === NULL ? $_GET : (empty($var) ? NULL : $_GET[$var]);
168  // Removes slashes since TYPO3 has added them regardless of magic_quotes setting.
169  if (isset($value)) {
170  if (is_array($value)) {
171  self::stripSlashesOnArray($value);
172  } else {
173  $value = stripslashes($value);
174  }
175  }
176  return $value;
177  }
178 
187  static public function _POST($var = NULL) {
188  $value = $var === NULL ? $_POST : (empty($var) ? NULL : $_POST[$var]);
189  // Removes slashes since TYPO3 has added them regardless of magic_quotes setting.
190  if (isset($value)) {
191  if (is_array($value)) {
192  self::stripSlashesOnArray($value);
193  } else {
194  $value = stripslashes($value);
195  }
196  }
197  return $value;
198  }
199 
207  static public function _GETset($inputGet, $key = '') {
208  // Adds slashes since TYPO3 standard currently is that slashes
209  // must be applied (regardless of magic_quotes setting)
210  if (is_array($inputGet)) {
211  self::addSlashesOnArray($inputGet);
212  } else {
213  $inputGet = addslashes($inputGet);
214  }
215  if ($key != '') {
216  if (strpos($key, '|') !== FALSE) {
217  $pieces = explode('|', $key);
218  $newGet = array();
219  $pointer = &$newGet;
220  foreach ($pieces as $piece) {
221  $pointer = &$pointer[$piece];
222  }
223  $pointer = $inputGet;
224  $mergedGet = $_GET;
225  ArrayUtility::mergeRecursiveWithOverrule($mergedGet, $newGet);
226  $_GET = $mergedGet;
227  $GLOBALS['HTTP_GET_VARS'] = $mergedGet;
228  } else {
229  $_GET[$key] = $inputGet;
230  $GLOBALS['HTTP_GET_VARS'][$key] = $inputGet;
231  }
232  } elseif (is_array($inputGet)) {
233  $_GET = $inputGet;
234  $GLOBALS['HTTP_GET_VARS'] = $inputGet;
235  }
236  }
237 
247  static public function removeXSS($string) {
248  require_once PATH_typo3 . 'contrib/RemoveXSS/RemoveXSS.php';
249  $string = \RemoveXSS::process($string);
250  return $string;
251  }
252 
253  /*************************
254  *
255  * IMAGE FUNCTIONS
256  *
257  *************************/
276  static public function gif_compress($theFile, $type) {
277  $gfxConf = $GLOBALS['TYPO3_CONF_VARS']['GFX'];
278  $returnCode = '';
279  // GIF...
280  if ($gfxConf['gif_compress'] && strtolower(substr($theFile, -4, 4)) == '.gif') {
281  // IM
282  if (($type == 'IM' || !$type) && $gfxConf['im'] && $gfxConf['im_path_lzw']) {
283  // Use temporary file to prevent problems with read and write lock on same file on network file systems
284  $temporaryName = dirname($theFile) . '/' . md5(uniqid('', TRUE)) . '.gif';
285  // Rename could fail, if a simultaneous thread is currently working on the same thing
286  if (@rename($theFile, $temporaryName)) {
287  $cmd = self::imageMagickCommand('convert', '"' . $temporaryName . '" "' . $theFile . '"', $gfxConf['im_path_lzw']);
289  unlink($temporaryName);
290  }
291  $returnCode = 'IM';
292  if (@is_file($theFile)) {
293  self::fixPermissions($theFile);
294  }
295  } elseif (($type == 'GD' || !$type) && $gfxConf['gdlib'] && !$gfxConf['gdlib_png']) {
296  // GD
297  $tempImage = imageCreateFromGif($theFile);
298  imageGif($tempImage, $theFile);
299  imageDestroy($tempImage);
300  $returnCode = 'GD';
301  if (@is_file($theFile)) {
302  self::fixPermissions($theFile);
303  }
304  }
305  }
306  return $returnCode;
307  }
308 
316  static public function png_to_gif_by_imagemagick($theFile) {
317  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['png_to_gif'] && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] && $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw'] && strtolower(substr($theFile, -4, 4)) == '.png' && @is_file($theFile)) {
318  // IM
319  $newFile = substr($theFile, 0, -4) . '.gif';
320  $cmd = self::imageMagickCommand('convert', '"' . $theFile . '" "' . $newFile . '"', $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path_lzw']);
322  $theFile = $newFile;
323  if (@is_file($newFile)) {
324  self::fixPermissions($newFile);
325  }
326  }
327  return $theFile;
328  }
329 
338  static public function read_png_gif($theFile, $output_png = FALSE) {
339  if ($GLOBALS['TYPO3_CONF_VARS']['GFX']['im'] && @is_file($theFile)) {
340  $ext = strtolower(substr($theFile, -4, 4));
341  if ((string) $ext == '.png' && $output_png || (string) $ext == '.gif' && !$output_png) {
342  return $theFile;
343  } else {
344  $newFile = PATH_site . 'typo3temp/readPG_' . md5(($theFile . '|' . filemtime($theFile))) . ($output_png ? '.png' : '.gif');
345  $cmd = self::imageMagickCommand('convert', '"' . $theFile . '" "' . $newFile . '"', $GLOBALS['TYPO3_CONF_VARS']['GFX']['im_path']);
347  if (@is_file($newFile)) {
348  self::fixPermissions($newFile);
349  return $newFile;
350  }
351  }
352  }
353  }
354 
355  /*************************
356  *
357  * STRING FUNCTIONS
358  *
359  *************************/
368  static public function fixed_lgd_cs($string, $chars, $appendString = '...') {
369  if (is_object($GLOBALS['LANG'])) {
370  return $GLOBALS['LANG']->csConvObj->crop($GLOBALS['LANG']->charSet, $string, $chars, $appendString);
371  } elseif (is_object($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE']->csConvObj)) {
372  $charSet = $GLOBALS['TSFE']->renderCharset != '' ? $GLOBALS['TSFE']->renderCharset : $GLOBALS['TSFE']->defaultCharSet;
373  return $GLOBALS['TSFE']->csConvObj->crop($charSet, $string, $chars, $appendString);
374  } else {
375  // This case should not happen
376  $csConvObj = self::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter');
377  return $csConvObj->crop('utf-8', $string, $chars, $appendString);
378  }
379  }
380 
389  static public function cmpIP($baseIP, $list) {
390  $list = trim($list);
391  if ($list === '') {
392  return FALSE;
393  } elseif ($list === '*') {
394  return TRUE;
395  }
396  if (strpos($baseIP, ':') !== FALSE && self::validIPv6($baseIP)) {
397  return self::cmpIPv6($baseIP, $list);
398  } else {
399  return self::cmpIPv4($baseIP, $list);
400  }
401  }
402 
410  static public function cmpIPv4($baseIP, $list) {
411  $IPpartsReq = explode('.', $baseIP);
412  if (count($IPpartsReq) == 4) {
413  $values = self::trimExplode(',', $list, TRUE);
414  foreach ($values as $test) {
415  $testList = explode('/', $test);
416  if (count($testList) == 2) {
417  list($test, $mask) = $testList;
418  } else {
419  $mask = FALSE;
420  }
421  if ((int)$mask) {
422  // "192.168.3.0/24"
423  $lnet = ip2long($test);
424  $lip = ip2long($baseIP);
425  $binnet = str_pad(decbin($lnet), 32, '0', STR_PAD_LEFT);
426  $firstpart = substr($binnet, 0, $mask);
427  $binip = str_pad(decbin($lip), 32, '0', STR_PAD_LEFT);
428  $firstip = substr($binip, 0, $mask);
429  $yes = $firstpart === $firstip;
430  } else {
431  // "192.168.*.*"
432  $IPparts = explode('.', $test);
433  $yes = 1;
434  foreach ($IPparts as $index => $val) {
435  $val = trim($val);
436  if ($val !== '*' && $IPpartsReq[$index] !== $val) {
437  $yes = 0;
438  }
439  }
440  }
441  if ($yes) {
442  return TRUE;
443  }
444  }
445  }
446  return FALSE;
447  }
448 
456  static public function cmpIPv6($baseIP, $list) {
457  // Policy default: Deny connection
458  $success = FALSE;
459  $baseIP = self::normalizeIPv6($baseIP);
460  $values = self::trimExplode(',', $list, TRUE);
461  foreach ($values as $test) {
462  $testList = explode('/', $test);
463  if (count($testList) == 2) {
464  list($test, $mask) = $testList;
465  } else {
466  $mask = FALSE;
467  }
468  if (self::validIPv6($test)) {
469  $test = self::normalizeIPv6($test);
470  $maskInt = (int)$mask ?: 128;
471  // Special case; /0 is an allowed mask - equals a wildcard
472  if ($mask === '0') {
473  $success = TRUE;
474  } elseif ($maskInt == 128) {
475  $success = $test === $baseIP;
476  } else {
477  $testBin = self::IPv6Hex2Bin($test);
478  $baseIPBin = self::IPv6Hex2Bin($baseIP);
479  $success = TRUE;
480  // Modulo is 0 if this is a 8-bit-boundary
481  $maskIntModulo = $maskInt % 8;
482  $numFullCharactersUntilBoundary = (int)($maskInt / 8);
483  if (substr($testBin, 0, $numFullCharactersUntilBoundary) !== substr($baseIPBin, 0, $numFullCharactersUntilBoundary)) {
484  $success = FALSE;
485  } elseif ($maskIntModulo > 0) {
486  // If not an 8-bit-boundary, check bits of last character
487  $testLastBits = str_pad(decbin(ord(substr($testBin, $numFullCharactersUntilBoundary, 1))), 8, '0', STR_PAD_LEFT);
488  $baseIPLastBits = str_pad(decbin(ord(substr($baseIPBin, $numFullCharactersUntilBoundary, 1))), 8, '0', STR_PAD_LEFT);
489  if (strncmp($testLastBits, $baseIPLastBits, $maskIntModulo) != 0) {
490  $success = FALSE;
491  }
492  }
493  }
494  }
495  if ($success) {
496  return TRUE;
497  }
498  }
499  return FALSE;
500  }
501 
509  static public function IPv6Hex2Bin($hex) {
510  return inet_pton($hex);
511  }
512 
520  static public function IPv6Bin2Hex($bin) {
521  return inet_ntop($bin);
522  }
523 
531  static public function normalizeIPv6($address) {
532  $normalizedAddress = '';
533  $stageOneAddress = '';
534  // According to RFC lowercase-representation is recommended
535  $address = strtolower($address);
536  // Normalized representation has 39 characters (0000:0000:0000:0000:0000:0000:0000:0000)
537  if (strlen($address) == 39) {
538  // Already in full expanded form
539  return $address;
540  }
541  // Count 2 if if address has hidden zero blocks
542  $chunks = explode('::', $address);
543  if (count($chunks) == 2) {
544  $chunksLeft = explode(':', $chunks[0]);
545  $chunksRight = explode(':', $chunks[1]);
546  $left = count($chunksLeft);
547  $right = count($chunksRight);
548  // Special case: leading zero-only blocks count to 1, should be 0
549  if ($left == 1 && strlen($chunksLeft[0]) == 0) {
550  $left = 0;
551  }
552  $hiddenBlocks = 8 - ($left + $right);
553  $hiddenPart = '';
554  $h = 0;
555  while ($h < $hiddenBlocks) {
556  $hiddenPart .= '0000:';
557  $h++;
558  }
559  if ($left == 0) {
560  $stageOneAddress = $hiddenPart . $chunks[1];
561  } else {
562  $stageOneAddress = $chunks[0] . ':' . $hiddenPart . $chunks[1];
563  }
564  } else {
565  $stageOneAddress = $address;
566  }
567  // Normalize the blocks:
568  $blocks = explode(':', $stageOneAddress);
569  $divCounter = 0;
570  foreach ($blocks as $block) {
571  $tmpBlock = '';
572  $i = 0;
573  $hiddenZeros = 4 - strlen($block);
574  while ($i < $hiddenZeros) {
575  $tmpBlock .= '0';
576  $i++;
577  }
578  $normalizedAddress .= $tmpBlock . $block;
579  if ($divCounter < 7) {
580  $normalizedAddress .= ':';
581  $divCounter++;
582  }
583  }
584  return $normalizedAddress;
585  }
586 
594  static public function compressIPv6($address) {
595  return inet_ntop(inet_pton($address));
596  }
597 
606  static public function validIP($ip) {
607  return filter_var($ip, FILTER_VALIDATE_IP) !== FALSE;
608  }
609 
618  static public function validIPv4($ip) {
619  return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== FALSE;
620  }
621 
630  static public function validIPv6($ip) {
631  return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== FALSE;
632  }
633 
641  static public function cmpFQDN($baseHost, $list) {
642  $baseHost = trim($baseHost);
643  if (empty($baseHost)) {
644  return FALSE;
645  }
646  if (self::validIPv4($baseHost) || self::validIPv6($baseHost)) {
647  // Resolve hostname
648  // Note: this is reverse-lookup and can be randomly set as soon as somebody is able to set
649  // the reverse-DNS for his IP (security when for example used with REMOTE_ADDR)
650  $baseHostName = gethostbyaddr($baseHost);
651  if ($baseHostName === $baseHost) {
652  // Unable to resolve hostname
653  return FALSE;
654  }
655  } else {
656  $baseHostName = $baseHost;
657  }
658  $baseHostNameParts = explode('.', $baseHostName);
659  $values = self::trimExplode(',', $list, TRUE);
660  foreach ($values as $test) {
661  $hostNameParts = explode('.', $test);
662  // To match hostNameParts can only be shorter (in case of wildcards) or equal
663  if (count($hostNameParts) > count($baseHostNameParts)) {
664  continue;
665  }
666  $yes = TRUE;
667  foreach ($hostNameParts as $index => $val) {
668  $val = trim($val);
669  if ($val === '*') {
670  // Wildcard valid for one or more hostname-parts
671  $wildcardStart = $index + 1;
672  // Wildcard as last/only part always matches, otherwise perform recursive checks
673  if ($wildcardStart < count($hostNameParts)) {
674  $wildcardMatched = FALSE;
675  $tempHostName = implode('.', array_slice($hostNameParts, $index + 1));
676  while ($wildcardStart < count($baseHostNameParts) && !$wildcardMatched) {
677  $tempBaseHostName = implode('.', array_slice($baseHostNameParts, $wildcardStart));
678  $wildcardMatched = self::cmpFQDN($tempBaseHostName, $tempHostName);
679  $wildcardStart++;
680  }
681  if ($wildcardMatched) {
682  // Match found by recursive compare
683  return TRUE;
684  } else {
685  $yes = FALSE;
686  }
687  }
688  } elseif ($baseHostNameParts[$index] !== $val) {
689  // In case of no match
690  $yes = FALSE;
691  }
692  }
693  if ($yes) {
694  return TRUE;
695  }
696  }
697  return FALSE;
698  }
699 
707  static public function isOnCurrentHost($url) {
708  return stripos($url . '/', self::getIndpEnv('TYPO3_REQUEST_HOST') . '/') === 0;
709  }
710 
719  static public function inList($list, $item) {
720  return strpos(',' . $list . ',', ',' . $item . ',') !== FALSE;
721  }
722 
733  static public function rmFromList($element, $list) {
734  $items = explode(',', $list);
735  foreach ($items as $k => $v) {
736  if ($v == $element) {
737  unset($items[$k]);
738  }
739  }
740  return implode(',', $items);
741  }
742 
750  static public function expandList($list) {
751  $items = explode(',', $list);
752  $list = array();
753  foreach ($items as $item) {
754  $range = explode('-', $item);
755  if (isset($range[1])) {
756  $runAwayBrake = 1000;
757  for ($n = $range[0]; $n <= $range[1]; $n++) {
758  $list[] = $n;
759  $runAwayBrake--;
760  if ($runAwayBrake <= 0) {
761  break;
762  }
763  }
764  } else {
765  $list[] = $item;
766  }
767  }
768  return implode(',', $list);
769  }
770 
778  static public function int_from_ver($verNumberStr) {
779  self::logDeprecatedFunction();
781  }
782 
791  static public function compat_version($verNumberStr) {
792  $currVersionStr = $GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['compat_version'] : TYPO3_branch;
793  if (\TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger($currVersionStr) < \TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger($verNumberStr)) {
794  return FALSE;
795  } else {
796  return TRUE;
797  }
798  }
799 
806  static public function md5int($str) {
807  return hexdec(substr(md5($str), 0, 7));
808  }
809 
817  static public function shortMD5($input, $len = 10) {
818  return substr(md5($input), 0, $len);
819  }
820 
828  static public function hmac($input, $additionalSecret = '') {
829  $hashAlgorithm = 'sha1';
830  $hashBlocksize = 64;
831  $hmac = '';
832  $secret = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . $additionalSecret;
833  if (extension_loaded('hash') && function_exists('hash_hmac') && function_exists('hash_algos') && in_array($hashAlgorithm, hash_algos())) {
834  $hmac = hash_hmac($hashAlgorithm, $input, $secret);
835  } else {
836  // Outer padding
837  $opad = str_repeat(chr(92), $hashBlocksize);
838  // Inner padding
839  $ipad = str_repeat(chr(54), $hashBlocksize);
840  if (strlen($secret) > $hashBlocksize) {
841  // Keys longer than block size are shorten
842  $key = str_pad(pack('H*', call_user_func($hashAlgorithm, $secret)), $hashBlocksize, chr(0));
843  } else {
844  // Keys shorter than block size are zero-padded
845  $key = str_pad($secret, $hashBlocksize, chr(0));
846  }
847  $hmac = call_user_func($hashAlgorithm, ($key ^ $opad) . pack('H*', call_user_func($hashAlgorithm, (($key ^ $ipad) . $input))));
848  }
849  return $hmac;
850  }
851 
860  static public function uniqueList($in_list, $secondParameter = NULL) {
861  if (is_array($in_list)) {
862  throw new \InvalidArgumentException('TYPO3 Fatal Error: TYPO3\\CMS\\Core\\Utility\\GeneralUtility::uniqueList() does NOT support array arguments anymore! Only string comma lists!', 1270853885);
863  }
864  if (isset($secondParameter)) {
865  throw new \InvalidArgumentException('TYPO3 Fatal Error: TYPO3\\CMS\\Core\\Utility\\GeneralUtility::uniqueList() does NOT support more than a single argument value anymore. You have specified more than one!', 1270853886);
866  }
867  return implode(',', array_unique(self::trimExplode(',', $in_list, TRUE)));
868  }
869 
876  static public function split_fileref($fileNameWithPath) {
877  $reg = array();
878  if (preg_match('/(.*\\/)(.*)$/', $fileNameWithPath, $reg)) {
879  $info['path'] = $reg[1];
880  $info['file'] = $reg[2];
881  } else {
882  $info['path'] = '';
883  $info['file'] = $fileNameWithPath;
884  }
885  $reg = '';
886  // If open_basedir is set and the fileName was supplied without a path the is_dir check fails
887  if (!is_dir($fileNameWithPath) && preg_match('/(.*)\\.([^\\.]*$)/', $info['file'], $reg)) {
888  $info['filebody'] = $reg[1];
889  $info['fileext'] = strtolower($reg[2]);
890  $info['realFileext'] = $reg[2];
891  } else {
892  $info['filebody'] = $info['file'];
893  $info['fileext'] = '';
894  }
895  reset($info);
896  return $info;
897  }
898 
914  static public function dirname($path) {
915  $p = self::revExplode('/', $path, 2);
916  return count($p) == 2 ? $p[0] : '';
917  }
918 
929  static public function modifyHTMLColor($color, $R, $G, $B) {
930  // This takes a hex-color (# included!) and adds $R, $G and $B to the HTML-color (format: #xxxxxx) and returns the new color
931  $nR = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(hexdec(substr($color, 1, 2)) + $R, 0, 255);
932  $nG = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(hexdec(substr($color, 3, 2)) + $G, 0, 255);
933  $nB = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange(hexdec(substr($color, 5, 2)) + $B, 0, 255);
934  return '#' . substr(('0' . dechex($nR)), -2) . substr(('0' . dechex($nG)), -2) . substr(('0' . dechex($nB)), -2);
935  }
936 
945  static public function modifyHTMLColorAll($color, $all) {
946  return self::modifyHTMLColor($color, $all, $all, $all);
947  }
948 
956  static public function isFirstPartOfStr($str, $partStr) {
957  return $partStr != '' && strpos((string) $str, (string) $partStr, 0) === 0;
958  }
959 
967  static public function formatSize($sizeInBytes, $labels = '') {
968  // Set labels:
969  if (strlen($labels) == 0) {
970  $labels = ' | K| M| G';
971  } else {
972  $labels = str_replace('"', '', $labels);
973  }
974  $labelArr = explode('|', $labels);
975  // Find size:
976  if ($sizeInBytes > 900) {
977  // GB
978  if ($sizeInBytes > 900000000) {
979  $val = $sizeInBytes / (1024 * 1024 * 1024);
980  return number_format($val, ($val < 20 ? 1 : 0), '.', '') . $labelArr[3];
981  } elseif ($sizeInBytes > 900000) {
982  // MB
983  $val = $sizeInBytes / (1024 * 1024);
984  return number_format($val, ($val < 20 ? 1 : 0), '.', '') . $labelArr[2];
985  } else {
986  // KB
987  $val = $sizeInBytes / 1024;
988  return number_format($val, ($val < 20 ? 1 : 0), '.', '') . $labelArr[1];
989  }
990  } else {
991  // Bytes
992  return $sizeInBytes . $labelArr[0];
993  }
994  }
995 
1002  static public function convertMicrotime($microtime) {
1003  $parts = explode(' ', $microtime);
1004  return round(($parts[0] + $parts[1]) * 1000);
1005  }
1006 
1015  static public function splitCalc($string, $operators) {
1016  $res = array();
1017  $sign = '+';
1018  while ($string) {
1019  $valueLen = strcspn($string, $operators);
1020  $value = substr($string, 0, $valueLen);
1021  $res[] = array($sign, trim($value));
1022  $sign = substr($string, $valueLen, 1);
1023  $string = substr($string, $valueLen + 1);
1024  }
1025  reset($res);
1026  return $res;
1027  }
1028 
1037  static public function htmlspecialchars_decode($value) {
1038  self::logDeprecatedFunction();
1039  return htmlspecialchars_decode($value);
1040  }
1041 
1051  static public function deHSCentities($str) {
1052  return preg_replace('/&amp;([#[:alnum:]]*;)/', '&\\1', $str);
1053  }
1054 
1063  static public function slashJS($string, $extended = FALSE, $char = '\'') {
1064  if ($extended) {
1065  $string = str_replace('\\', '\\\\', $string);
1066  }
1067  return str_replace($char, '\\' . $char, $string);
1068  }
1069 
1077  static public function rawUrlEncodeJS($str) {
1078  return str_replace('%20', ' ', rawurlencode($str));
1079  }
1080 
1088  static public function rawUrlEncodeFP($str) {
1089  return str_replace('%2F', '/', rawurlencode($str));
1090  }
1091 
1110  static public function validEmail($email) {
1111  // Early return in case input is not a string
1112  if (!is_string($email)) {
1113  return FALSE;
1114  }
1115  $atPosition = strrpos($email, '@');
1116  if (!$atPosition || $atPosition + 1 === strlen($email)) {
1117  // Return if no @ found or it is placed at the very beginning or end of the email
1118  return FALSE;
1119  }
1120  $domain = substr($email, $atPosition + 1);
1121  $user = substr($email, 0, $atPosition);
1122  if (!preg_match('/^[a-z0-9.\\-]*$/i', $domain)) {
1123  $domain = self::idnaEncode($domain);
1124  }
1125  return filter_var($user . '@' . $domain, FILTER_VALIDATE_EMAIL) !== FALSE;
1126  }
1127 
1140  static public function isBrokenEmailEnvironment() {
1141  return TYPO3_OS == 'WIN' || FALSE !== strpos(ini_get('sendmail_path'), 'mini_sendmail');
1142  }
1143 
1150  static public function normalizeMailAddress($address) {
1151  if (self::isBrokenEmailEnvironment() && FALSE !== ($pos1 = strrpos($address, '<'))) {
1152  $pos2 = strpos($address, '>', $pos1);
1153  $address = substr($address, $pos1 + 1, ($pos2 ? $pos2 : strlen($address)) - $pos1 - 1);
1154  }
1155  return $address;
1156  }
1157 
1166  static public function formatForTextarea($content) {
1167  return LF . htmlspecialchars($content);
1168  }
1169 
1179  static public function strtoupper($str) {
1180  return strtr((string) $str, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
1181  }
1182 
1192  static public function strtolower($str) {
1193  return strtr((string) $str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
1194  }
1195 
1207  static public function generateRandomBytes($bytesToReturn) {
1208  // Cache 4k of the generated bytestream.
1209  static $bytes = '';
1210  $bytesToGenerate = max(4096, $bytesToReturn);
1211  // if we have not enough random bytes cached, we generate new ones
1212  if (!isset($bytes[($bytesToReturn - 1)])) {
1213  if (TYPO3_OS === 'WIN') {
1214  // Openssl seems to be deadly slow on Windows, so try to use mcrypt
1215  $bytes .= self::generateRandomBytesMcrypt($bytesToGenerate);
1216  } else {
1217  // Try to use native PHP functions first, precedence has openssl
1218  $bytes .= self::generateRandomBytesOpenSsl($bytesToGenerate);
1219  if (!isset($bytes[($bytesToReturn - 1)])) {
1220  $bytes .= self::generateRandomBytesMcrypt($bytesToGenerate);
1221  }
1222  // If openssl and mcrypt failed, try /dev/urandom
1223  if (!isset($bytes[($bytesToReturn - 1)])) {
1224  $bytes .= self::generateRandomBytesUrandom($bytesToGenerate);
1225  }
1226  }
1227  // Fall back if other random byte generation failed until now
1228  if (!isset($bytes[($bytesToReturn - 1)])) {
1229  $bytes .= self::generateRandomBytesFallback($bytesToReturn);
1230  }
1231  }
1232  // get first $bytesToReturn and remove it from the byte cache
1233  $output = substr($bytes, 0, $bytesToReturn);
1234  $bytes = substr($bytes, $bytesToReturn);
1235  return $output;
1236  }
1237 
1244  static protected function generateRandomBytesOpenSsl($bytesToGenerate) {
1245  if (!function_exists('openssl_random_pseudo_bytes')) {
1246  return '';
1247  }
1248  $isStrong = NULL;
1249  return (string) openssl_random_pseudo_bytes($bytesToGenerate, $isStrong);
1250  }
1251 
1258  static protected function generateRandomBytesMcrypt($bytesToGenerate) {
1259  if (!function_exists('mcrypt_create_iv')) {
1260  return '';
1261  }
1262  return (string)(@mcrypt_create_iv($bytesToGenerate, MCRYPT_DEV_URANDOM));
1263  }
1264 
1271  static protected function generateRandomBytesUrandom($bytesToGenerate) {
1272  $bytes = '';
1273  $fh = @fopen('/dev/urandom', 'rb');
1274  if ($fh) {
1275  // PHP only performs buffered reads, so in reality it will always read
1276  // at least 4096 bytes. Thus, it costs nothing extra to read and store
1277  // that much so as to speed any additional invocations.
1278  $bytes = fread($fh, $bytesToGenerate);
1279  fclose($fh);
1280  }
1281  return $bytes;
1282  }
1283 
1290  static protected function generateRandomBytesFallback($bytesToReturn) {
1291  $bytes = '';
1292  // We initialize with somewhat random.
1293  $randomState = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . base_convert(memory_get_usage() % pow(10, 6), 10, 2) . microtime() . uniqid('', TRUE) . getmypid();
1294  while (!isset($bytes[($bytesToReturn - 1)])) {
1295  $randomState = sha1(microtime() . mt_rand() . $randomState);
1296  $bytes .= sha1(mt_rand() . $randomState, TRUE);
1297  }
1298  return $bytes;
1299  }
1300 
1307  static public function idnaEncode($value) {
1308  if (isset(self::$idnaStringCache[$value])) {
1309  return self::$idnaStringCache[$value];
1310  } else {
1311  if (!self::$idnaConverter) {
1312  require_once PATH_typo3 . 'contrib/idna/idna_convert.class.php';
1313  self::$idnaConverter = new \idna_convert(array('idn_version' => 2008));
1314  }
1315  self::$idnaStringCache[$value] = self::$idnaConverter->encode($value);
1316  return self::$idnaStringCache[$value];
1317  }
1318  }
1319 
1326  static public function getRandomHexString($count) {
1327  return substr(bin2hex(self::generateRandomBytes((int)(($count + 1) / 2))), 0, $count);
1328  }
1329 
1337  static public function underscoredToUpperCamelCase($string) {
1338  $upperCamelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', self::strtolower($string))));
1339  return $upperCamelCase;
1340  }
1341 
1349  static public function underscoredToLowerCamelCase($string) {
1350  $upperCamelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', self::strtolower($string))));
1351  $lowerCamelCase = self::lcfirst($upperCamelCase);
1352  return $lowerCamelCase;
1353  }
1354 
1362  static public function camelCaseToLowerCaseUnderscored($string) {
1363  return self::strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $string));
1364  }
1365 
1373  static public function lcfirst($string) {
1374  return self::strtolower($string[0]) . substr($string, 1);
1375  }
1376 
1401  static public function isValidUrl($url) {
1402  $parsedUrl = parse_url($url);
1403  if (!$parsedUrl || !isset($parsedUrl['scheme'])) {
1404  return FALSE;
1405  }
1406  // HttpUtility::buildUrl() will always build urls with <scheme>://
1407  // our original $url might only contain <scheme>: (e.g. mail:)
1408  // so we convert that to the double-slashed version to ensure
1409  // our check against the $recomposedUrl is proper
1410  if (!self::isFirstPartOfStr($url, $parsedUrl['scheme'] . '://')) {
1411  $url = str_replace($parsedUrl['scheme'] . ':', $parsedUrl['scheme'] . '://', $url);
1412  }
1413  $recomposedUrl = HttpUtility::buildUrl($parsedUrl);
1414  if ($recomposedUrl !== $url) {
1415  // The parse_url() had to modify characters, so the URL is invalid
1416  return FALSE;
1417  }
1418  if (isset($parsedUrl['host']) && !preg_match('/^[a-z0-9.\\-]*$/i', $parsedUrl['host'])) {
1419  $parsedUrl['host'] = self::idnaEncode($parsedUrl['host']);
1420  }
1421  return filter_var(HttpUtility::buildUrl($parsedUrl), FILTER_VALIDATE_URL) !== FALSE;
1422  }
1423 
1424  /*************************
1425  *
1426  * ARRAY FUNCTIONS
1427  *
1428  *************************/
1451  static public function inArray(array $in_array, $item) {
1452  foreach ($in_array as $val) {
1453  if (!is_array($val) && (string)$val === (string)$item) {
1454  return TRUE;
1455  }
1456  }
1457  return FALSE;
1458  }
1459 
1470  static public function intExplode($delimiter, $string, $removeEmptyValues = FALSE, $limit = 0) {
1471  $result = explode($delimiter, $string);
1472  foreach ($result as $key => &$value) {
1473  if ($removeEmptyValues && ($value === '' || trim($value) === '')) {
1474  unset($result[$key]);
1475  } else {
1476  $value = (int)$value;
1477  }
1478  }
1479  unset($value);
1480  if ($limit !== 0) {
1481  if ($limit < 0) {
1482  $result = array_slice($result, 0, $limit);
1483  } elseif (count($result) > $limit) {
1484  $lastElements = array_slice($result, $limit - 1);
1485  $result = array_slice($result, 0, $limit - 1);
1486  $result[] = implode($delimiter, $lastElements);
1487  }
1488  }
1489  return $result;
1490  }
1491 
1506  static public function revExplode($delimiter, $string, $count = 0) {
1507  // 2 is the (currently, as of 2014-02) most-used value for $count in the core, therefore we check it first
1508  if ($count === 2) {
1509  $position = strrpos($string, strrev($delimiter));
1510  if ($position !== FALSE) {
1511  return array(substr($string, 0, $position), substr($string, $position + strlen($delimiter)));
1512  } else {
1513  return array($string);
1514  }
1515  } elseif ($count <= 1) {
1516  return array($string);
1517  } else {
1518  $explodedValues = explode($delimiter, strrev($string), $count);
1519  $explodedValues = array_map('strrev', $explodedValues);
1520  return array_reverse($explodedValues);
1521  }
1522  }
1523 
1536  static public function trimExplode($delim, $string, $removeEmptyValues = FALSE, $limit = 0) {
1537  $result = explode($delim, $string);
1538  if ($removeEmptyValues) {
1539  $temp = array();
1540  foreach ($result as $value) {
1541  if (trim($value) !== '') {
1542  $temp[] = $value;
1543  }
1544  }
1545  $result = $temp;
1546  }
1547  if ($limit > 0 && count($result) > $limit) {
1548  $lastElements = array_slice($result, $limit - 1);
1549  $result = array_slice($result, 0, $limit - 1);
1550  $result[] = implode($delim, $lastElements);
1551  } elseif ($limit < 0) {
1552  $result = array_slice($result, 0, $limit);
1553  }
1554  $result = array_map('trim', $result);
1555  return $result;
1556  }
1557 
1565  static public function removeArrayEntryByValue(array $array, $cmpValue) {
1566  foreach ($array as $k => $v) {
1567  if (is_array($v)) {
1568  $array[$k] = self::removeArrayEntryByValue($v, $cmpValue);
1569  } elseif ((string)$v === (string)$cmpValue) {
1570  unset($array[$k]);
1571  }
1572  }
1573  return $array;
1574  }
1575 
1599  static public function keepItemsInArray(array $array, $keepItems, $getValueFunc = NULL) {
1600  if ($array) {
1601  // Convert strings to arrays:
1602  if (is_string($keepItems)) {
1603  $keepItems = self::trimExplode(',', $keepItems);
1604  }
1605  // Check if valueFunc can be executed:
1606  if (!is_callable($getValueFunc)) {
1607  $getValueFunc = NULL;
1608  }
1609  // Do the filtering:
1610  if (is_array($keepItems) && count($keepItems)) {
1611  foreach ($array as $key => $value) {
1612  // Get the value to compare by using the callback function:
1613  $keepValue = isset($getValueFunc) ? call_user_func($getValueFunc, $value) : $value;
1614  if (!in_array($keepValue, $keepItems)) {
1615  unset($array[$key]);
1616  }
1617  }
1618  }
1619  }
1620  return $array;
1621  }
1622 
1634  static public function implodeArrayForUrl($name, array $theArray, $str = '', $skipBlank = FALSE, $rawurlencodeParamName = FALSE) {
1635  foreach ($theArray as $Akey => $AVal) {
1636  $thisKeyName = $name ? $name . '[' . $Akey . ']' : $Akey;
1637  if (is_array($AVal)) {
1638  $str = self::implodeArrayForUrl($thisKeyName, $AVal, $str, $skipBlank, $rawurlencodeParamName);
1639  } else {
1640  if (!$skipBlank || (string)$AVal !== '') {
1641  $str .= '&' . ($rawurlencodeParamName ? rawurlencode($thisKeyName) : $thisKeyName) . '=' . rawurlencode($AVal);
1642  }
1643  }
1644  }
1645  return $str;
1646  }
1647 
1656  static public function explodeUrl2Array($string, $multidim = FALSE) {
1657  $output = array();
1658  if ($multidim) {
1659  parse_str($string, $output);
1660  } else {
1661  $p = explode('&', $string);
1662  foreach ($p as $v) {
1663  if (strlen($v)) {
1664  list($pK, $pV) = explode('=', $v, 2);
1665  $output[rawurldecode($pK)] = rawurldecode($pV);
1666  }
1667  }
1668  }
1669  return $output;
1670  }
1671 
1681  static public function compileSelectedGetVarsFromArray($varList, array $getArray, $GPvarAlt = TRUE) {
1682  $keys = self::trimExplode(',', $varList, TRUE);
1683  $outArr = array();
1684  foreach ($keys as $v) {
1685  if (isset($getArray[$v])) {
1686  $outArr[$v] = $getArray[$v];
1687  } elseif ($GPvarAlt) {
1688  $outArr[$v] = self::_GP($v);
1689  }
1690  }
1691  return $outArr;
1692  }
1693 
1703  static public function addSlashesOnArray(array &$theArray) {
1704  foreach ($theArray as &$value) {
1705  if (is_array($value)) {
1706  self::addSlashesOnArray($value);
1707  } else {
1708  $value = addslashes($value);
1709  }
1710  }
1711  unset($value);
1712  reset($theArray);
1713  }
1714 
1724  static public function stripSlashesOnArray(array &$theArray) {
1725  foreach ($theArray as &$value) {
1726  if (is_array($value)) {
1727  self::stripSlashesOnArray($value);
1728  } else {
1729  $value = stripslashes($value);
1730  }
1731  }
1732  unset($value);
1733  reset($theArray);
1734  }
1735 
1743  static public function slashArray(array $arr, $cmd) {
1744  if ($cmd == 'strip') {
1745  self::stripSlashesOnArray($arr);
1746  }
1747  if ($cmd == 'add') {
1748  self::addSlashesOnArray($arr);
1749  }
1750  return $arr;
1751  }
1752 
1759  static public function remapArrayKeys(&$array, $mappingTable) {
1760  if (is_array($mappingTable)) {
1761  foreach ($mappingTable as $old => $new) {
1762  if ($new && isset($array[$old])) {
1763  $array[$new] = $array[$old];
1764  unset($array[$old]);
1765  }
1766  }
1767  }
1768  }
1769 
1784  static public function array_merge_recursive_overrule(array $arr0, array $arr1, $notAddKeys = FALSE, $includeEmptyValues = TRUE, $enableUnsetFeature = TRUE) {
1785  self::logDeprecatedFunction();
1786  ArrayUtility::mergeRecursiveWithOverrule($arr0, $arr1, !$notAddKeys, $includeEmptyValues, $enableUnsetFeature);
1787  // Our local $arr0 has been modified now, so return it as result
1788  return $arr0;
1789  }
1790 
1798  static public function array_merge(array $arr1, array $arr2) {
1799  return $arr2 + $arr1;
1800  }
1801 
1810  static public function arrayDiffAssocRecursive(array $array1, array $array2) {
1811  $differenceArray = array();
1812  foreach ($array1 as $key => $value) {
1813  if (!array_key_exists($key, $array2)) {
1814  $differenceArray[$key] = $value;
1815  } elseif (is_array($value)) {
1816  if (is_array($array2[$key])) {
1817  $differenceArray[$key] = self::arrayDiffAssocRecursive($value, $array2[$key]);
1818  }
1819  }
1820  }
1821  return $differenceArray;
1822  }
1823 
1832  static public function csvValues(array $row, $delim = ',', $quote = '"') {
1833  $out = array();
1834  foreach ($row as $value) {
1835  $out[] = str_replace($quote, $quote . $quote, $value);
1836  }
1837  $str = $quote . implode(($quote . $delim . $quote), $out) . $quote;
1838  return $str;
1839  }
1840 
1848  static public function removeDotsFromTS(array $ts) {
1849  $out = array();
1850  foreach ($ts as $key => $value) {
1851  if (is_array($value)) {
1852  $key = rtrim($key, '.');
1853  $out[$key] = self::removeDotsFromTS($value);
1854  } else {
1855  $out[$key] = $value;
1856  }
1857  }
1858  return $out;
1859  }
1860 
1867  static public function naturalKeySortRecursive(&$array) {
1868  if (!is_array($array)) {
1869  return FALSE;
1870  }
1871  uksort($array, 'strnatcasecmp');
1872  foreach ($array as $key => $value) {
1873  self::naturalKeySortRecursive($array[$key]);
1874  }
1875  return TRUE;
1876  }
1877 
1878  /*************************
1879  *
1880  * HTML/XML PROCESSING
1881  *
1882  *************************/
1891  static public function get_tag_attributes($tag) {
1892  $components = self::split_tag_attributes($tag);
1893  // Attribute name is stored here
1894  $name = '';
1895  $valuemode = FALSE;
1896  $attributes = array();
1897  foreach ($components as $key => $val) {
1898  // Only if $name is set (if there is an attribute, that waits for a value), that valuemode is enabled. This ensures that the attribute is assigned it's value
1899  if ($val != '=') {
1900  if ($valuemode) {
1901  if ($name) {
1902  $attributes[$name] = $val;
1903  $name = '';
1904  }
1905  } else {
1906  if ($key = strtolower(preg_replace('/[^[:alnum:]_\\:\\-]/', '', $val))) {
1907  $attributes[$key] = '';
1908  $name = $key;
1909  }
1910  }
1911  $valuemode = FALSE;
1912  } else {
1913  $valuemode = TRUE;
1914  }
1915  }
1916  return $attributes;
1917  }
1918 
1926  static public function split_tag_attributes($tag) {
1927  $tag_tmp = trim(preg_replace('/^<[^[:space:]]*/', '', trim($tag)));
1928  // Removes any > in the end of the string
1929  $tag_tmp = trim(rtrim($tag_tmp, '>'));
1930  $value = array();
1931  // Compared with empty string instead , 030102
1932  while ($tag_tmp !== '') {
1933  $firstChar = $tag_tmp[0];
1934  if ($firstChar === '"' || $firstChar === '\'') {
1935  $reg = explode($firstChar, $tag_tmp, 3);
1936  $value[] = $reg[1];
1937  $tag_tmp = trim($reg[2]);
1938  } elseif ($firstChar === '=') {
1939  $value[] = '=';
1940  // Removes = chars.
1941  $tag_tmp = trim(substr($tag_tmp, 1));
1942  } else {
1943  // There are '' around the value. We look for the next ' ' or '>'
1944  $reg = preg_split('/[[:space:]=]/', $tag_tmp, 2);
1945  $value[] = trim($reg[0]);
1946  $tag_tmp = trim(substr($tag_tmp, strlen($reg[0]), 1) . $reg[1]);
1947  }
1948  }
1949  reset($value);
1950  return $value;
1951  }
1952 
1961  static public function implodeAttributes(array $arr, $xhtmlSafe = FALSE, $dontOmitBlankAttribs = FALSE) {
1962  if ($xhtmlSafe) {
1963  $newArr = array();
1964  foreach ($arr as $p => $v) {
1965  if (!isset($newArr[strtolower($p)])) {
1966  $newArr[strtolower($p)] = htmlspecialchars($v);
1967  }
1968  }
1969  $arr = $newArr;
1970  }
1971  $list = array();
1972  foreach ($arr as $p => $v) {
1973  if ((string)$v !== '' || $dontOmitBlankAttribs) {
1974  $list[] = $p . '="' . $v . '"';
1975  }
1976  }
1977  return implode(' ', $list);
1978  }
1979 
1989  static public function wrapJS($string, $linebreak = TRUE) {
1990  if (trim($string)) {
1991  // <script wrapped in nl?
1992  $cr = $linebreak ? LF : '';
1993  // remove nl from the beginning
1994  $string = preg_replace('/^\\n+/', '', $string);
1995  // re-ident to one tab using the first line as reference
1996  $match = array();
1997  if (preg_match('/^(\\t+)/', $string, $match)) {
1998  $string = str_replace($match[1], TAB, $string);
1999  }
2000  $string = $cr . '<script type="text/javascript">
2001 /*<![CDATA[*/
2002 ' . $string . '
2003 /*]]>*/
2004 </script>' . $cr;
2005  }
2006  return trim($string);
2007  }
2008 
2017  static public function xml2tree($string, $depth = 999) {
2018  // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
2019  $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
2020  $parser = xml_parser_create();
2021  $vals = array();
2022  $index = array();
2023  xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2024  xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
2025  xml_parse_into_struct($parser, $string, $vals, $index);
2026  libxml_disable_entity_loader($previousValueOfEntityLoader);
2027  if (xml_get_error_code($parser)) {
2028  return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser));
2029  }
2030  xml_parser_free($parser);
2031  $stack = array(array());
2032  $stacktop = 0;
2033  $startPoint = 0;
2034  $tagi = array();
2035  foreach ($vals as $key => $val) {
2036  $type = $val['type'];
2037  // open tag:
2038  if ($type == 'open' || $type == 'complete') {
2039  $stack[$stacktop++] = $tagi;
2040  if ($depth == $stacktop) {
2041  $startPoint = $key;
2042  }
2043  $tagi = array('tag' => $val['tag']);
2044  if (isset($val['attributes'])) {
2045  $tagi['attrs'] = $val['attributes'];
2046  }
2047  if (isset($val['value'])) {
2048  $tagi['values'][] = $val['value'];
2049  }
2050  }
2051  // finish tag:
2052  if ($type == 'complete' || $type == 'close') {
2053  $oldtagi = $tagi;
2054  $tagi = $stack[--$stacktop];
2055  $oldtag = $oldtagi['tag'];
2056  unset($oldtagi['tag']);
2057  if ($depth == $stacktop + 1) {
2058  if ($key - $startPoint > 0) {
2059  $partArray = array_slice($vals, $startPoint + 1, $key - $startPoint - 1);
2060  $oldtagi['XMLvalue'] = self::xmlRecompileFromStructValArray($partArray);
2061  } else {
2062  $oldtagi['XMLvalue'] = $oldtagi['values'][0];
2063  }
2064  }
2065  $tagi['ch'][$oldtag][] = $oldtagi;
2066  unset($oldtagi);
2067  }
2068  // cdata
2069  if ($type == 'cdata') {
2070  $tagi['values'][] = $val['value'];
2071  }
2072  }
2073  return $tagi['ch'];
2074  }
2075 
2086  static public function array2xml_cs(array $array, $docTag = 'phparray', array $options = array(), $charset = '') {
2087  // Set default charset unless explicitly specified
2088  $charset = $charset ?: 'utf-8';
2089  // Return XML:
2090  return '<?xml version="1.0" encoding="' . htmlspecialchars($charset) . '" standalone="yes" ?>' . LF . self::array2xml($array, '', 0, $docTag, 0, $options);
2091  }
2092 
2115  static public function array2xml(array $array, $NSprefix = '', $level = 0, $docTag = 'phparray', $spaceInd = 0, array $options = array(), array $stackData = array()) {
2116  // The list of byte values which will trigger binary-safe storage. If any value has one of these char values in it, it will be encoded in base64
2117  $binaryChars = chr(0) . chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . chr(6) . chr(7) . chr(8) . chr(11) . chr(12) . chr(14) . chr(15) . chr(16) . chr(17) . chr(18) . chr(19) . chr(20) . chr(21) . chr(22) . chr(23) . chr(24) . chr(25) . chr(26) . chr(27) . chr(28) . chr(29) . chr(30) . chr(31);
2118  // Set indenting mode:
2119  $indentChar = $spaceInd ? ' ' : TAB;
2120  $indentN = $spaceInd > 0 ? $spaceInd : 1;
2121  $nl = $spaceInd >= 0 ? LF : '';
2122  // Init output variable:
2123  $output = '';
2124  // Traverse the input array
2125  foreach ($array as $k => $v) {
2126  $attr = '';
2127  $tagName = $k;
2128  // Construct the tag name.
2129  // Use tag based on grand-parent + parent tag name
2130  if (isset($options['grandParentTagMap'][$stackData['grandParentTagName'] . '/' . $stackData['parentTagName']])) {
2131  $attr .= ' index="' . htmlspecialchars($tagName) . '"';
2132  $tagName = (string) $options['grandParentTagMap'][($stackData['grandParentTagName'] . '/' . $stackData['parentTagName'])];
2133  } elseif (isset($options['parentTagMap'][$stackData['parentTagName'] . ':_IS_NUM']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($tagName)) {
2134  // Use tag based on parent tag name + if current tag is numeric
2135  $attr .= ' index="' . htmlspecialchars($tagName) . '"';
2136  $tagName = (string) $options['parentTagMap'][($stackData['parentTagName'] . ':_IS_NUM')];
2137  } elseif (isset($options['parentTagMap'][$stackData['parentTagName'] . ':' . $tagName])) {
2138  // Use tag based on parent tag name + current tag
2139  $attr .= ' index="' . htmlspecialchars($tagName) . '"';
2140  $tagName = (string) $options['parentTagMap'][($stackData['parentTagName'] . ':' . $tagName)];
2141  } elseif (isset($options['parentTagMap'][$stackData['parentTagName']])) {
2142  // Use tag based on parent tag name:
2143  $attr .= ' index="' . htmlspecialchars($tagName) . '"';
2144  $tagName = (string) $options['parentTagMap'][$stackData['parentTagName']];
2145  } elseif (MathUtility::canBeInterpretedAsInteger($tagName)) {
2146  // If integer...;
2147  if ($options['useNindex']) {
2148  // If numeric key, prefix "n"
2149  $tagName = 'n' . $tagName;
2150  } else {
2151  // Use special tag for num. keys:
2152  $attr .= ' index="' . $tagName . '"';
2153  $tagName = $options['useIndexTagForNum'] ?: 'numIndex';
2154  }
2155  } elseif ($options['useIndexTagForAssoc']) {
2156  // Use tag for all associative keys:
2157  $attr .= ' index="' . htmlspecialchars($tagName) . '"';
2158  $tagName = $options['useIndexTagForAssoc'];
2159  }
2160  // The tag name is cleaned up so only alphanumeric chars (plus - and _) are in there and not longer than 100 chars either.
2161  $tagName = substr(preg_replace('/[^[:alnum:]_-]/', '', $tagName), 0, 100);
2162  // If the value is an array then we will call this function recursively:
2163  if (is_array($v)) {
2164  // Sub elements:
2165  if ($options['alt_options'][$stackData['path'] . '/' . $tagName]) {
2166  $subOptions = $options['alt_options'][$stackData['path'] . '/' . $tagName];
2167  $clearStackPath = $subOptions['clearStackPath'];
2168  } else {
2169  $subOptions = $options;
2170  $clearStackPath = FALSE;
2171  }
2172  if (empty($v)) {
2173  $content = '';
2174  } else {
2175  $content = $nl . self::array2xml($v, $NSprefix, ($level + 1), '', $spaceInd, $subOptions, array(
2176  'parentTagName' => $tagName,
2177  'grandParentTagName' => $stackData['parentTagName'],
2178  'path' => ($clearStackPath ? '' : $stackData['path'] . '/' . $tagName)
2179  )) . ($spaceInd >= 0 ? str_pad('', ($level + 1) * $indentN, $indentChar) : '');
2180  }
2181  // Do not set "type = array". Makes prettier XML but means that empty arrays are not restored with xml2array
2182  if ((int)$options['disableTypeAttrib'] != 2) {
2183  $attr .= ' type="array"';
2184  }
2185  } else {
2186  // Just a value:
2187  // Look for binary chars:
2188  // Check for length, because PHP 5.2.0 may crash when first argument of strcspn is empty
2189  $vLen = strlen($v);
2190  // Go for base64 encoding if the initial segment NOT matching any binary char has the same length as the whole string!
2191  if ($vLen && strcspn($v, $binaryChars) != $vLen) {
2192  // If the value contained binary chars then we base64-encode it an set an attribute to notify this situation:
2193  $content = $nl . chunk_split(base64_encode($v));
2194  $attr .= ' base64="1"';
2195  } else {
2196  // Otherwise, just htmlspecialchar the stuff:
2197  $content = htmlspecialchars($v);
2198  $dType = gettype($v);
2199  if ($dType == 'string') {
2200  if ($options['useCDATA'] && $content != $v) {
2201  $content = '<![CDATA[' . $v . ']]>';
2202  }
2203  } elseif (!$options['disableTypeAttrib']) {
2204  $attr .= ' type="' . $dType . '"';
2205  }
2206  }
2207  }
2208  if ((string)$tagName !== '') {
2209  // Add the element to the output string:
2210  $output .= ($spaceInd >= 0 ? str_pad('', ($level + 1) * $indentN, $indentChar) : '')
2211  . '<' . $NSprefix . $tagName . $attr . '>' . $content . '</' . $NSprefix . $tagName . '>' . $nl;
2212  }
2213  }
2214  // If we are at the outer-most level, then we finally wrap it all in the document tags and return that as the value:
2215  if (!$level) {
2216  $output = '<' . $docTag . '>' . $nl . $output . '</' . $docTag . '>';
2217  }
2218  return $output;
2219  }
2220 
2232  static public function xml2array($string, $NSprefix = '', $reportDocTag = FALSE) {
2233  static $firstLevelCache = array();
2234  $identifier = md5($string . $NSprefix . ($reportDocTag ? '1' : '0'));
2235  // Look up in first level cache
2236  if (!empty($firstLevelCache[$identifier])) {
2237  $array = $firstLevelCache[$identifier];
2238  } else {
2239  // Look up in second level cache
2240  $array = \TYPO3\CMS\Frontend\Page\PageRepository::getHash($identifier, 0);
2241  if (!is_array($array)) {
2242  $array = self::xml2arrayProcess($string, $NSprefix, $reportDocTag);
2243  \TYPO3\CMS\Frontend\Page\PageRepository::storeHash($identifier, $array, 'ident_xml2array');
2244  }
2245  // Store content in first level cache
2246  $firstLevelCache[$identifier] = $array;
2247  }
2248  return $array;
2249  }
2250 
2261  static protected function xml2arrayProcess($string, $NSprefix = '', $reportDocTag = FALSE) {
2262  // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
2263  $previousValueOfEntityLoader = libxml_disable_entity_loader(TRUE);
2264  // Create parser:
2265  $parser = xml_parser_create();
2266  $vals = array();
2267  $index = array();
2268  xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2269  xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
2270  // Default output charset is UTF-8, only ASCII, ISO-8859-1 and UTF-8 are supported!!!
2271  $match = array();
2272  preg_match('/^[[:space:]]*<\\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/', substr($string, 0, 200), $match);
2273  $theCharset = $match[1] ?: 'utf-8';
2274  // us-ascii / utf-8 / iso-8859-1
2275  xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset);
2276  // Parse content:
2277  xml_parse_into_struct($parser, $string, $vals, $index);
2278  libxml_disable_entity_loader($previousValueOfEntityLoader);
2279  // If error, return error message:
2280  if (xml_get_error_code($parser)) {
2281  return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser));
2282  }
2283  xml_parser_free($parser);
2284  // Init vars:
2285  $stack = array(array());
2286  $stacktop = 0;
2287  $current = array();
2288  $tagName = '';
2289  $documentTag = '';
2290  // Traverse the parsed XML structure:
2291  foreach ($vals as $key => $val) {
2292  // First, process the tag-name (which is used in both cases, whether "complete" or "close")
2293  $tagName = $val['tag'];
2294  if (!$documentTag) {
2295  $documentTag = $tagName;
2296  }
2297  // Test for name space:
2298  $tagName = $NSprefix && substr($tagName, 0, strlen($NSprefix)) == $NSprefix ? substr($tagName, strlen($NSprefix)) : $tagName;
2299  // Test for numeric tag, encoded on the form "nXXX":
2300  $testNtag = substr($tagName, 1);
2301  // Closing tag.
2302  $tagName = $tagName[0] === 'n' && MathUtility::canBeInterpretedAsInteger($testNtag) ? (int)$testNtag : $tagName;
2303  // Test for alternative index value:
2304  if (strlen($val['attributes']['index'])) {
2305  $tagName = $val['attributes']['index'];
2306  }
2307  // Setting tag-values, manage stack:
2308  switch ($val['type']) {
2309  case 'open':
2310  // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array:
2311  // Setting blank place holder
2312  $current[$tagName] = array();
2313  $stack[$stacktop++] = $current;
2314  $current = array();
2315  break;
2316  case 'close':
2317  // If the tag is "close" then it is an array which is closing and we decrease the stack pointer.
2318  $oldCurrent = $current;
2319  $current = $stack[--$stacktop];
2320  // Going to the end of array to get placeholder key, key($current), and fill in array next:
2321  end($current);
2322  $current[key($current)] = $oldCurrent;
2323  unset($oldCurrent);
2324  break;
2325  case 'complete':
2326  // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it.
2327  if ($val['attributes']['base64']) {
2328  $current[$tagName] = base64_decode($val['value']);
2329  } else {
2330  // Had to cast it as a string - otherwise it would be evaluate FALSE if tested with isset()!!
2331  $current[$tagName] = (string) $val['value'];
2332  // Cast type:
2333  switch ((string) $val['attributes']['type']) {
2334  case 'integer':
2335  $current[$tagName] = (int)$current[$tagName];
2336  break;
2337  case 'double':
2338  $current[$tagName] = (double) $current[$tagName];
2339  break;
2340  case 'boolean':
2341  $current[$tagName] = (bool) $current[$tagName];
2342  break;
2343  case 'NULL':
2344  $current[$tagName] = NULL;
2345  break;
2346  case 'array':
2347  // MUST be an empty array since it is processed as a value; Empty arrays would end up here because they would have no tags inside...
2348  $current[$tagName] = array();
2349  break;
2350  }
2351  }
2352  break;
2353  }
2354  }
2355  if ($reportDocTag) {
2356  $current[$tagName]['_DOCUMENT_TAG'] = $documentTag;
2357  }
2358  // Finally return the content of the document tag.
2359  return $current[$tagName];
2360  }
2361 
2368  static public function xmlRecompileFromStructValArray(array $vals) {
2369  $XMLcontent = '';
2370  foreach ($vals as $val) {
2371  $type = $val['type'];
2372  // Open tag:
2373  if ($type == 'open' || $type == 'complete') {
2374  $XMLcontent .= '<' . $val['tag'];
2375  if (isset($val['attributes'])) {
2376  foreach ($val['attributes'] as $k => $v) {
2377  $XMLcontent .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
2378  }
2379  }
2380  if ($type == 'complete') {
2381  if (isset($val['value'])) {
2382  $XMLcontent .= '>' . htmlspecialchars($val['value']) . '</' . $val['tag'] . '>';
2383  } else {
2384  $XMLcontent .= '/>';
2385  }
2386  } else {
2387  $XMLcontent .= '>';
2388  }
2389  if ($type == 'open' && isset($val['value'])) {
2390  $XMLcontent .= htmlspecialchars($val['value']);
2391  }
2392  }
2393  // Finish tag:
2394  if ($type == 'close') {
2395  $XMLcontent .= '</' . $val['tag'] . '>';
2396  }
2397  // Cdata
2398  if ($type == 'cdata') {
2399  $XMLcontent .= htmlspecialchars($val['value']);
2400  }
2401  }
2402  return $XMLcontent;
2403  }
2404 
2411  static public function xmlGetHeaderAttribs($xmlData) {
2412  $match = array();
2413  if (preg_match('/^\\s*<\\?xml([^>]*)\\?\\>/', $xmlData, $match)) {
2414  return self::get_tag_attributes($match[1]);
2415  }
2416  }
2417 
2425  static public function minifyJavaScript($script, &$error = '') {
2426  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'])) {
2427  $fakeThis = FALSE;
2428  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'] as $hookMethod) {
2429  try {
2430  $parameters = array('script' => $script);
2431  $script = static::callUserFunction($hookMethod, $parameters, $fakeThis);
2432  } catch (\Exception $e) {
2433  $errorMessage = 'Error minifying java script: ' . $e->getMessage();
2434  $error .= $errorMessage;
2435  static::devLog($errorMessage, 'TYPO3\\CMS\\Core\\Utility\\GeneralUtility', 2, array(
2436  'JavaScript' => $script,
2437  'Stack trace' => $e->getTrace(),
2438  'hook' => $hookMethod
2439  ));
2440  }
2441  }
2442  }
2443  return $script;
2444  }
2445 
2446  /*************************
2447  *
2448  * FILES FUNCTIONS
2449  *
2450  *************************/
2461  static public function getUrl($url, $includeHeader = 0, $requestHeaders = FALSE, &$report = NULL) {
2462  $content = FALSE;
2463  if (isset($report)) {
2464  $report['error'] = 0;
2465  $report['message'] = '';
2466  }
2467  // Use cURL for: http, https, ftp, ftps, sftp and scp
2468  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] == '1' && preg_match('/^(?:http|ftp)s?|s(?:ftp|cp):/', $url)) {
2469  if (isset($report)) {
2470  $report['lib'] = 'cURL';
2471  }
2472  // External URL without error checking.
2473  if (!function_exists('curl_init') || !($ch = curl_init())) {
2474  if (isset($report)) {
2475  $report['error'] = -1;
2476  $report['message'] = 'Couldn\'t initialize cURL.';
2477  }
2478  return FALSE;
2479  }
2480 
2481  $followLocationSucceeded = @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
2482 
2483  $curlIncludeHeaders = !$followLocationSucceeded || $includeHeader;
2484  curl_setopt($ch, CURLOPT_URL, $url);
2485  curl_setopt($ch, CURLOPT_HEADER, $curlIncludeHeaders ? 1 : 0);
2486  curl_setopt($ch, CURLOPT_NOBODY, $includeHeader == 2 ? 1 : 0);
2487  curl_setopt($ch, CURLOPT_HTTPGET, $includeHeader == 2 ? 'HEAD' : 'GET');
2488  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
2489  curl_setopt($ch, CURLOPT_FAILONERROR, 1);
2490  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, max(0, (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['curlTimeout']));
2491 
2492  if (is_array($requestHeaders)) {
2493  curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
2494  }
2495  // (Proxy support implemented by Arco <arco@appeltaart.mine.nu>)
2496  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']) {
2497  curl_setopt($ch, CURLOPT_PROXY, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']);
2498  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyNTLM']) {
2499  curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
2500  }
2501  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel']) {
2502  curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel']);
2503  }
2504  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass']) {
2505  curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass']);
2506  }
2507  }
2508  $content = curl_exec($ch);
2509  $curlInfo = curl_getinfo($ch);
2510 
2511  // Remove additional proxy header block, when proxy is used for https request and CURL_HEADER is enabled.
2512  // Most HTTPS proxies add a second header before the actual server headers in their response, as a
2513  // response to the CONNECT message sent by the client to the proxy. cURL does not strip this since 2005,
2514  // so there are two headers arriving here, of which the first is not of interest to us—therefore, we can
2515  // safely strip it.
2516  // Detecting two linebreaks followed by a "HTTP/" (as done here) is the only reliable way to detect the
2517  // proxy headers, as the relevant RFCs do not specify the exact status code (it might be any of 2xx) or
2518  // the status message. Therefore, we check if there is a second HTTP headers block and then strip the
2519  // first one.
2520  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']
2521  && $curlIncludeHeaders
2522  && preg_match('/^https:/', $url)
2523  && strpos($content, "\r\n\r\nHTTP/") !== false
2524  ) {
2525  $content = self::stripHttpHeaders($content);
2526  }
2527 
2528  if (!$followLocationSucceeded) {
2529  // Check if we need to do redirects
2530  if ($curlInfo['http_code'] >= 300 && $curlInfo['http_code'] < 400) {
2531  $locationUrl = $curlInfo['redirect_url'];
2532  if (!$locationUrl) {
2533  // Some curllib versions do not return redirect_url. Examine headers.
2534  $locationUrl = self::getRedirectUrlFromHttpHeaders($content);
2535  }
2536  if ($locationUrl) {
2537  $content = self::getUrl($locationUrl, $includeHeader, $requestHeaders, $report);
2538  $followLocationSucceeded = TRUE;
2539  } else {
2540  // Failure: we got a redirection status code but not the URL to redirect to.
2541  $content = FALSE;
2542  }
2543  }
2544  if ($content && !$includeHeader) {
2545  $content = self::stripHttpHeaders($content);
2546  }
2547  }
2548 
2549  if (isset($report)) {
2550  if (!$followLocationSucceeded && $curlInfo['http_code'] >= 300 && $curlInfo['http_code'] < 400) {
2551  $report['http_code'] = $curlInfo['http_code'];
2552  $report['content_type'] = $curlInfo['content_type'];
2553  $report['error'] = CURLE_GOT_NOTHING;
2554  $report['message'] = 'Expected "Location" header but got nothing.';
2555  } elseif ($content === FALSE) {
2556  $report['error'] = curl_errno($ch);
2557  $report['message'] = curl_error($ch);
2558  } elseif ($includeHeader) {
2559  // Set only for $includeHeader to work exactly like PHP variant
2560  $report['http_code'] = $curlInfo['http_code'];
2561  $report['content_type'] = $curlInfo['content_type'];
2562  }
2563  }
2564  curl_close($ch);
2565  } elseif ($includeHeader) {
2566  if (isset($report)) {
2567  $report['lib'] = 'socket';
2568  }
2569  $parsedURL = parse_url($url);
2570  if (!preg_match('/^https?/', $parsedURL['scheme'])) {
2571  if (isset($report)) {
2572  $report['error'] = -1;
2573  $report['message'] = 'Reading headers is not allowed for this protocol.';
2574  }
2575  return FALSE;
2576  }
2577  $port = (int)$parsedURL['port'];
2578  if ($port < 1) {
2579  if ($parsedURL['scheme'] == 'http') {
2580  $port = $port > 0 ? $port : 80;
2581  $scheme = '';
2582  } else {
2583  $port = $port > 0 ? $port : 443;
2584  $scheme = 'ssl://';
2585  }
2586  }
2587  $errno = 0;
2588  $fp = @fsockopen(($scheme . $parsedURL['host']), $port, $errno, $errstr, 2.0);
2589  if (!$fp || $errno > 0) {
2590  if (isset($report)) {
2591  $report['error'] = $errno ?: -1;
2592  $report['message'] = $errno ? ($errstr ?: 'Socket error.') : 'Socket initialization error.';
2593  }
2594  return FALSE;
2595  }
2596  $method = $includeHeader == 2 ? 'HEAD' : 'GET';
2597  $msg = $method . ' ' . (isset($parsedURL['path']) ? $parsedURL['path'] : '/')
2598  . ($parsedURL['query'] ? '?' . $parsedURL['query'] : '') . ' HTTP/1.0' . CRLF
2599  . 'Host: ' . $parsedURL['host'] . CRLF
2600  . 'Connection: close' . CRLF;
2601  if (is_array($requestHeaders)) {
2602  $msg .= implode(CRLF, $requestHeaders) . CRLF;
2603  }
2604  $msg .= CRLF;
2605  fputs($fp, $msg);
2606  while (!feof($fp)) {
2607  $line = fgets($fp, 2048);
2608  if (isset($report)) {
2609  if (preg_match('|^HTTP/\\d\\.\\d +(\\d+)|', $line, $status)) {
2610  $report['http_code'] = $status[1];
2611  } elseif (preg_match('/^Content-Type: *(.*)/i', $line, $type)) {
2612  $report['content_type'] = $type[1];
2613  }
2614  }
2615  $content .= $line;
2616  if (!strlen(trim($line))) {
2617  // Stop at the first empty line (= end of header)
2618  break;
2619  }
2620  }
2621  if ($includeHeader != 2) {
2622  $content .= stream_get_contents($fp);
2623  }
2624  fclose($fp);
2625  } elseif (is_array($requestHeaders)) {
2626  if (isset($report)) {
2627  $report['lib'] = 'file/context';
2628  }
2629  $parsedURL = parse_url($url);
2630  if (!preg_match('/^https?/', $parsedURL['scheme'])) {
2631  if (isset($report)) {
2632  $report['error'] = -1;
2633  $report['message'] = 'Sending request headers is not allowed for this protocol.';
2634  }
2635  return FALSE;
2636  }
2637  $ctx = stream_context_create(array(
2638  'http' => array(
2639  'header' => implode(CRLF, $requestHeaders)
2640  )
2641  ));
2642  $content = @file_get_contents($url, FALSE, $ctx);
2643  if ($content === FALSE && isset($report)) {
2644  $report['error'] = -1;
2645  $report['message'] = 'Couldn\'t get URL: ' . (isset($http_response_header) ? implode(LF, $http_response_header) : $url);
2646  }
2647  } else {
2648  if (isset($report)) {
2649  $report['lib'] = 'file';
2650  }
2651  $content = @file_get_contents($url);
2652  if ($content === FALSE && isset($report)) {
2653  $report['error'] = -1;
2654  $report['message'] = 'Couldn\'t get URL: ' . (isset($http_response_header) ? implode(LF, $http_response_header) : $url);
2655  }
2656  }
2657  return $content;
2658  }
2659 
2667  static protected function getRedirectUrlFromHttpHeaders($content) {
2668  $result = '';
2669  $headers = explode("\r\n", $content);
2670  foreach ($headers as $header) {
2671  if ($header == '') {
2672  break;
2673  }
2674  if (preg_match('/^\s*Location\s*:/i', $header)) {
2675  list(, $result) = self::trimExplode(':', $header, FALSE, 2);
2676  if ($result) {
2677  $result = self::locationHeaderUrl($result);
2678  }
2679  break;
2680  }
2681  }
2682  return $result;
2683  }
2684 
2691  static protected function stripHttpHeaders($content) {
2692  $headersEndPos = strpos($content, "\r\n\r\n");
2693  if ($headersEndPos) {
2694  $content = substr($content, $headersEndPos + 4);
2695  }
2696  return $content;
2697  }
2698 
2707  static public function writeFile($file, $content, $changePermissions = FALSE) {
2708  if (!@is_file($file)) {
2709  $changePermissions = TRUE;
2710  }
2711  if ($fd = fopen($file, 'wb')) {
2712  $res = fwrite($fd, $content);
2713  fclose($fd);
2714  if ($res === FALSE) {
2715  return FALSE;
2716  }
2717  // Change the permissions only if the file has just been created
2718  if ($changePermissions) {
2719  self::fixPermissions($file);
2720  }
2721  return TRUE;
2722  }
2723  return FALSE;
2724  }
2725 
2733  static public function fixPermissions($path, $recursive = FALSE) {
2734  if (TYPO3_OS != 'WIN') {
2735  $result = FALSE;
2736  // Make path absolute
2737  if (!self::isAbsPath($path)) {
2738  $path = self::getFileAbsFileName($path, FALSE);
2739  }
2740  if (self::isAllowedAbsPath($path)) {
2741  if (@is_file($path)) {
2742  $targetFilePermissions = isset($GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'])
2743  ? octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['fileCreateMask'])
2744  : octdec('0644');
2745  // "@" is there because file is not necessarily OWNED by the user
2746  $result = @chmod($path, $targetFilePermissions);
2747  } elseif (@is_dir($path)) {
2748  $targetDirectoryPermissions = isset($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'])
2749  ? octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask'])
2750  : octdec('0755');
2751  // "@" is there because file is not necessarily OWNED by the user
2752  $result = @chmod($path, $targetDirectoryPermissions);
2753  }
2754  // Set createGroup if not empty
2755  if (
2756  isset($GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup'])
2757  && strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']) > 0
2758  ) {
2759  // "@" is there because file is not necessarily OWNED by the user
2760  $changeGroupResult = @chgrp($path, $GLOBALS['TYPO3_CONF_VARS']['BE']['createGroup']);
2761  $result = $changeGroupResult ? $result : FALSE;
2762  }
2763  // Call recursive if recursive flag if set and $path is directory
2764  if ($recursive && @is_dir($path)) {
2765  $handle = opendir($path);
2766  while (($file = readdir($handle)) !== FALSE) {
2767  $recursionResult = NULL;
2768  if ($file !== '.' && $file !== '..') {
2769  if (@is_file(($path . '/' . $file))) {
2770  $recursionResult = self::fixPermissions($path . '/' . $file);
2771  } elseif (@is_dir(($path . '/' . $file))) {
2772  $recursionResult = self::fixPermissions($path . '/' . $file, TRUE);
2773  }
2774  if (isset($recursionResult) && !$recursionResult) {
2775  $result = FALSE;
2776  }
2777  }
2778  }
2779  closedir($handle);
2780  }
2781  }
2782  } else {
2783  $result = TRUE;
2784  }
2785  return $result;
2786  }
2787 
2796  static public function writeFileToTypo3tempDir($filepath, $content) {
2797  // Parse filepath into directory and basename:
2798  $fI = pathinfo($filepath);
2799  $fI['dirname'] .= '/';
2800  // Check parts:
2801  if (self::validPathStr($filepath) && $fI['basename'] && strlen($fI['basename']) < 60) {
2802  if (defined('PATH_site')) {
2803  // Setting main temporary directory name (standard)
2804  $dirName = PATH_site . 'typo3temp/';
2805  if (@is_dir($dirName)) {
2806  if (self::isFirstPartOfStr($fI['dirname'], $dirName)) {
2807  // Checking if the "subdir" is found:
2808  $subdir = substr($fI['dirname'], strlen($dirName));
2809  if ($subdir) {
2810  if (preg_match('/^[[:alnum:]_]+\\/$/', $subdir) || preg_match('/^[[:alnum:]_]+\\/[[:alnum:]_]+\\/$/', $subdir)) {
2811  $dirName .= $subdir;
2812  if (!@is_dir($dirName)) {
2813  self::mkdir_deep(PATH_site . 'typo3temp/', $subdir);
2814  }
2815  } else {
2816  return 'Subdir, "' . $subdir . '", was NOT on the form "[[:alnum:]_]/" or "[[:alnum:]_]/[[:alnum:]_]/"';
2817  }
2818  }
2819  // Checking dir-name again (sub-dir might have been created):
2820  if (@is_dir($dirName)) {
2821  if ($filepath == $dirName . $fI['basename']) {
2822  self::writeFile($filepath, $content);
2823  if (!@is_file($filepath)) {
2824  return 'The file was not written to the disk. Please, check that you have write permissions to the typo3temp/ directory.';
2825  }
2826  } else {
2827  return 'Calculated filelocation didn\'t match input $filepath!';
2828  }
2829  } else {
2830  return '"' . $dirName . '" is not a directory!';
2831  }
2832  } else {
2833  return '"' . $fI['dirname'] . '" was not within directory PATH_site + "typo3temp/"';
2834  }
2835  } else {
2836  return 'PATH_site + "typo3temp/" was not a directory!';
2837  }
2838  } else {
2839  return 'PATH_site constant was NOT defined!';
2840  }
2841  } else {
2842  return 'Input filepath "' . $filepath . '" was generally invalid!';
2843  }
2844  }
2845 
2854  static public function mkdir($newFolder) {
2855  $result = @mkdir($newFolder, octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']));
2856  if ($result) {
2857  self::fixPermissions($newFolder);
2858  }
2859  return $result;
2860  }
2861 
2872  static public function mkdir_deep($directory, $deepDirectory = '') {
2873  if (!is_string($directory)) {
2874  throw new \InvalidArgumentException('The specified directory is of type "' . gettype($directory) . '" but a string is expected.', 1303662955);
2875  }
2876  if (!is_string($deepDirectory)) {
2877  throw new \InvalidArgumentException('The specified directory is of type "' . gettype($deepDirectory) . '" but a string is expected.', 1303662956);
2878  }
2879  // Ensure there is only one slash
2880  $fullPath = rtrim($directory, '/') . '/' . ltrim($deepDirectory, '/');
2881  if (!is_dir($fullPath) && strlen($fullPath) > 0) {
2882  $firstCreatedPath = self::createDirectoryPath($fullPath);
2883  if ($firstCreatedPath !== '') {
2884  self::fixPermissions($firstCreatedPath, TRUE);
2885  }
2886  }
2887  }
2888 
2900  static protected function createDirectoryPath($fullDirectoryPath) {
2901  $currentPath = $fullDirectoryPath;
2902  $firstCreatedPath = '';
2903  $permissionMask = octdec($GLOBALS['TYPO3_CONF_VARS']['BE']['folderCreateMask']);
2904  if (!@is_dir($currentPath)) {
2905  do {
2906  $firstCreatedPath = $currentPath;
2907  $separatorPosition = strrpos($currentPath, DIRECTORY_SEPARATOR);
2908  $currentPath = substr($currentPath, 0, $separatorPosition);
2909  } while (!is_dir($currentPath) && $separatorPosition !== FALSE);
2910  $result = @mkdir($fullDirectoryPath, $permissionMask, TRUE);
2911  // Check existence of directory again to avoid race condition. Directory could have get created by another process between previous is_dir() and mkdir()
2912  if (!$result && !@is_dir($fullDirectoryPath)) {
2913  throw new \RuntimeException('Could not create directory "' . $fullDirectoryPath . '"!', 1170251401);
2914  }
2915  }
2916  return $firstCreatedPath;
2917  }
2918 
2926  static public function rmdir($path, $removeNonEmpty = FALSE) {
2927  $OK = FALSE;
2928  // Remove trailing slash
2929  $path = preg_replace('|/$|', '', $path);
2930  if (file_exists($path)) {
2931  $OK = TRUE;
2932  if (!is_link($path) && is_dir($path)) {
2933  if ($removeNonEmpty == TRUE && ($handle = @opendir($path))) {
2934  while ($OK && FALSE !== ($file = readdir($handle))) {
2935  if ($file == '.' || $file == '..') {
2936  continue;
2937  }
2938  $OK = self::rmdir($path . '/' . $file, $removeNonEmpty);
2939  }
2940  closedir($handle);
2941  }
2942  if ($OK) {
2943  $OK = @rmdir($path);
2944  }
2945  } elseif (is_link($path) && is_dir($path) && TYPO3_OS === 'WIN') {
2946  $OK = @rmdir($path);
2947  } else {
2948  // If $path is a file, simply remove it
2949  $OK = @unlink($path);
2950  }
2951  clearstatcache();
2952  } elseif (is_link($path)) {
2953  $OK = @unlink($path);
2954  clearstatcache();
2955  }
2956  return $OK;
2957  }
2958 
2969  static public function flushDirectory($directory, $keepOriginalDirectory = FALSE, $flushOpcodeCache = FALSE) {
2970  $result = FALSE;
2971 
2972  if (is_dir($directory)) {
2973  $temporaryDirectory = rtrim($directory, '/') . '.' . uniqid('remove', TRUE) . '/';
2974  if (rename($directory, $temporaryDirectory)) {
2975  if ($keepOriginalDirectory) {
2976  self::mkdir($directory);
2977  }
2978  $flushOpcodeCache && OpcodeCacheUtility::clearAllActive($directory);
2979  clearstatcache();
2980  $result = self::rmdir($temporaryDirectory, TRUE);
2981  }
2982  }
2983 
2984  return $result;
2985  }
2986 
2994  static public function get_dirs($path) {
2995  if ($path) {
2996  if (is_dir($path)) {
2997  $dir = scandir($path);
2998  $dirs = array();
2999  foreach ($dir as $entry) {
3000  if (is_dir($path . '/' . $entry) && $entry != '..' && $entry != '.') {
3001  $dirs[] = $entry;
3002  }
3003  }
3004  } else {
3005  $dirs = 'error';
3006  }
3007  }
3008  return $dirs;
3009  }
3010 
3023  static public function getFilesInDir($path, $extensionList = '', $prependPath = FALSE, $order = '', $excludePattern = '') {
3024  $excludePattern = (string)$excludePattern;
3025  $path = rtrim($path, '/');
3026  if (!@is_dir($path)) {
3027  return array();
3028  }
3029 
3030  $rawFileList = scandir($path);
3031  if ($rawFileList === FALSE) {
3032  return 'error opening path: "' . $path . '"';
3033  }
3034 
3035  $pathPrefix = $path . '/';
3036  $extensionList = ',' . $extensionList . ',';
3037  $files = array();
3038  foreach ($rawFileList as $entry) {
3039  $completePathToEntry = $pathPrefix . $entry;
3040  if (!@is_file($completePathToEntry)) {
3041  continue;
3042  }
3043 
3044  if (
3045  ($extensionList === ',,' || stripos($extensionList, ',' . pathinfo($entry, PATHINFO_EXTENSION) . ',') !== FALSE)
3046  && ($excludePattern === '' || !preg_match(('/^' . $excludePattern . '$/'), $entry))
3047  ) {
3048  if ($order !== 'mtime') {
3049  $files[] = $entry;
3050  } else {
3051  // Store the value in the key so we can do a fast asort later.
3052  $files[$entry] = filemtime($completePathToEntry);
3053  }
3054  }
3055  }
3056 
3057  $valueName = 'value';
3058  if ($order === 'mtime') {
3059  asort($files);
3060  $valueName = 'key';
3061  }
3062 
3063  $valuePathPrefix = $prependPath ? $pathPrefix : '';
3064  $foundFiles = array();
3065  foreach ($files as $key => $value) {
3066  // Don't change this ever - extensions may depend on the fact that the hash is an md5 of the path! (import/export extension)
3067  $foundFiles[md5($pathPrefix . ${$valueName})] = $valuePathPrefix . ${$valueName};
3068  }
3069 
3070  return $foundFiles;
3071  }
3072 
3084  static public function getAllFilesAndFoldersInPath(array $fileArr, $path, $extList = '', $regDirs = FALSE, $recursivityLevels = 99, $excludePattern = '') {
3085  if ($regDirs) {
3086  $fileArr[] = $path;
3087  }
3088  $fileArr = array_merge($fileArr, self::getFilesInDir($path, $extList, 1, 1, $excludePattern));
3089  $dirs = self::get_dirs($path);
3090  if ($recursivityLevels > 0 && is_array($dirs)) {
3091  foreach ($dirs as $subdirs) {
3092  if ((string) $subdirs != '' && (!strlen($excludePattern) || !preg_match(('/^' . $excludePattern . '$/'), $subdirs))) {
3093  $fileArr = self::getAllFilesAndFoldersInPath($fileArr, $path . $subdirs . '/', $extList, $regDirs, $recursivityLevels - 1, $excludePattern);
3094  }
3095  }
3096  }
3097  return $fileArr;
3098  }
3099 
3107  static public function removePrefixPathFromList(array $fileArr, $prefixToRemove) {
3108  foreach ($fileArr as $k => &$absFileRef) {
3109  if (self::isFirstPartOfStr($absFileRef, $prefixToRemove)) {
3110  $absFileRef = substr($absFileRef, strlen($prefixToRemove));
3111  } else {
3112  return 'ERROR: One or more of the files was NOT prefixed with the prefix-path!';
3113  }
3114  }
3115  unset($absFileRef);
3116  return $fileArr;
3117  }
3118 
3125  static public function fixWindowsFilePath($theFile) {
3126  return str_replace(array('\\', '//'), '/', $theFile);
3127  }
3128 
3136  static public function resolveBackPath($pathStr) {
3137  if (strpos($pathStr, '..') === FALSE) {
3138  return $pathStr;
3139  }
3140  $parts = explode('/', $pathStr);
3141  $output = array();
3142  $c = 0;
3143  foreach ($parts as $part) {
3144  if ($part === '..') {
3145  if ($c) {
3146  array_pop($output);
3147  --$c;
3148  } else {
3149  $output[] = $part;
3150  }
3151  } else {
3152  ++$c;
3153  $output[] = $part;
3154  }
3155  }
3156  return implode('/', $output);
3157  }
3158 
3169  static public function locationHeaderUrl($path) {
3170  $uI = parse_url($path);
3171  // relative to HOST
3172  if ($path[0] === '/') {
3173  $path = self::getIndpEnv('TYPO3_REQUEST_HOST') . $path;
3174  } elseif (!$uI['scheme']) {
3175  // No scheme either
3176  $path = self::getIndpEnv('TYPO3_REQUEST_DIR') . $path;
3177  }
3178  if (strpbrk($path, "\r\n") !== false) {
3179  throw new \InvalidArgumentException('HTTP header injection attempt in "' . $path . '"', 1448194036);
3180  }
3181  return $path;
3182  }
3183 
3193  static public function getMaxUploadFileSize($localLimit = 0) {
3194  // Don't allow more than the global max file size at all
3195  $t3Limit = (int)($localLimit > 0 ? $localLimit : $GLOBALS['TYPO3_CONF_VARS']['BE']['maxFileSize']);
3196  // As TYPO3 is handling the file size in KB, multiply by 1024 to get bytes
3197  $t3Limit = $t3Limit * 1024;
3198  // Check for PHP restrictions of the maximum size of one of the $_FILES
3199  $phpUploadLimit = self::getBytesFromSizeMeasurement(ini_get('upload_max_filesize'));
3200  // Check for PHP restrictions of the maximum $_POST size
3201  $phpPostLimit = self::getBytesFromSizeMeasurement(ini_get('post_max_size'));
3202  // If the total amount of post data is smaller (!) than the upload_max_filesize directive,
3203  // then this is the real limit in PHP
3204  $phpUploadLimit = $phpPostLimit > 0 && $phpPostLimit < $phpUploadLimit ? $phpPostLimit : $phpUploadLimit;
3205  // Is the allowed PHP limit (upload_max_filesize) lower than the TYPO3 limit?, also: revert back to KB
3206  return floor(($phpUploadLimit < $t3Limit ? $phpUploadLimit : $t3Limit)) / 1024;
3207  }
3208 
3215  static public function getBytesFromSizeMeasurement($measurement) {
3216  $bytes = doubleval($measurement);
3217  if (stripos($measurement, 'G')) {
3218  $bytes *= 1024 * 1024 * 1024;
3219  } elseif (stripos($measurement, 'M')) {
3220  $bytes *= 1024 * 1024;
3221  } elseif (stripos($measurement, 'K')) {
3222  $bytes *= 1024;
3223  }
3224  return $bytes;
3225  }
3226 
3232  static public function getMaximumPathLength() {
3233  return PHP_MAXPATHLEN;
3234  }
3235 
3253  static public function createVersionNumberedFilename($file, $forceQueryString = FALSE) {
3254  $lookupFile = explode('?', $file);
3255  $path = self::resolveBackPath(self::dirname(PATH_thisScript) . '/' . $lookupFile[0]);
3256 
3257  $doNothing = FALSE;
3258  if (TYPO3_MODE == 'FE') {
3259  $mode = strtolower($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['versionNumberInFilename']);
3260  if ($mode === 'embed') {
3261  $mode = TRUE;
3262  } else {
3263  if ($mode === 'querystring') {
3264  $mode = FALSE;
3265  } else {
3266  $doNothing = TRUE;
3267  }
3268  }
3269  } else {
3270  $mode = $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['versionNumberInFilename'];
3271  }
3272  if (!file_exists($path) || $doNothing) {
3273  // File not found, return filename unaltered
3274  $fullName = $file;
3275  } else {
3276  if (!$mode || $forceQueryString) {
3277  // If use of .htaccess rule is not configured,
3278  // we use the default query-string method
3279  if ($lookupFile[1]) {
3280  $separator = '&';
3281  } else {
3282  $separator = '?';
3283  }
3284  $fullName = $file . $separator . filemtime($path);
3285  } else {
3286  // Change the filename
3287  $name = explode('.', $lookupFile[0]);
3288  $extension = array_pop($name);
3289  array_push($name, filemtime($path), $extension);
3290  $fullName = implode('.', $name);
3291  // Append potential query string
3292  $fullName .= $lookupFile[1] ? '?' . $lookupFile[1] : '';
3293  }
3294  }
3295  return $fullName;
3296  }
3297 
3298  /*************************
3299  *
3300  * SYSTEM INFORMATION
3301  *
3302  *************************/
3308  static public function getThisUrl() {
3309  // Url of this script
3310  $p = parse_url(self::getIndpEnv('TYPO3_REQUEST_SCRIPT'));
3311  $dir = self::dirname($p['path']) . '/';
3312  // Strip file
3313  $url = str_replace('//', '/', $p['host'] . ($p['port'] ? ':' . $p['port'] : '') . $dir);
3314  return $url;
3315  }
3316 
3325  static public function linkThisScript(array $getParams = array()) {
3326  $parts = self::getIndpEnv('SCRIPT_NAME');
3327  $params = self::_GET();
3328  foreach ($getParams as $key => $value) {
3329  if ($value !== '') {
3330  $params[$key] = $value;
3331  } else {
3332  unset($params[$key]);
3333  }
3334  }
3335  $pString = self::implodeArrayForUrl('', $params);
3336  return $pString ? $parts . '?' . preg_replace('/^&/', '', $pString) : $parts;
3337  }
3338 
3347  static public function linkThisUrl($url, array $getParams = array()) {
3348  $parts = parse_url($url);
3349  $getP = array();
3350  if ($parts['query']) {
3351  parse_str($parts['query'], $getP);
3352  }
3353  ArrayUtility::mergeRecursiveWithOverrule($getP, $getParams);
3354  $uP = explode('?', $url);
3355  $params = self::implodeArrayForUrl('', $getP);
3356  $outurl = $uP[0] . ($params ? '?' . substr($params, 1) : '');
3357  return $outurl;
3358  }
3359 
3368  static public function getIndpEnv($getEnvName) {
3369  /*
3370  Conventions:
3371  output from parse_url():
3372  URL: http://username:password@192.168.1.4:8080/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value#link1
3373  [scheme] => 'http'
3374  [user] => 'username'
3375  [pass] => 'password'
3376  [host] => '192.168.1.4'
3377  [port] => '8080'
3378  [path] => '/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/'
3379  [query] => 'arg1,arg2,arg3&p1=parameter1&p2[key]=value'
3380  [fragment] => 'link1'Further definition: [path_script] = '/typo3/32/temp/phpcheck/index.php'
3381  [path_dir] = '/typo3/32/temp/phpcheck/'
3382  [path_info] = '/arg1/arg2/arg3/'
3383  [path] = [path_script/path_dir][path_info]Keys supported:URI______:
3384  REQUEST_URI = [path]?[query] = /typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value
3385  HTTP_HOST = [host][:[port]] = 192.168.1.4:8080
3386  SCRIPT_NAME = [path_script]++ = /typo3/32/temp/phpcheck/index.php // NOTICE THAT SCRIPT_NAME will return the php-script name ALSO. [path_script] may not do that (eg. '/somedir/' may result in SCRIPT_NAME '/somedir/index.php')!
3387  PATH_INFO = [path_info] = /arg1/arg2/arg3/
3388  QUERY_STRING = [query] = arg1,arg2,arg3&p1=parameter1&p2[key]=value
3389  HTTP_REFERER = [scheme]://[host][:[port]][path] = http://192.168.1.4:8080/typo3/32/temp/phpcheck/index.php/arg1/arg2/arg3/?arg1,arg2,arg3&p1=parameter1&p2[key]=value
3390  (Notice: NO username/password + NO fragment)CLIENT____:
3391  REMOTE_ADDR = (client IP)
3392  REMOTE_HOST = (client host)
3393  HTTP_USER_AGENT = (client user agent)
3394  HTTP_ACCEPT_LANGUAGE = (client accept language)SERVER____:
3395  SCRIPT_FILENAME = Absolute filename of script (Differs between windows/unix). On windows 'C:\\blabla\\blabl\\' will be converted to 'C:/blabla/blabl/'Special extras:
3396  TYPO3_HOST_ONLY = [host] = 192.168.1.4
3397  TYPO3_PORT = [port] = 8080 (blank if 80, taken from host value)
3398  TYPO3_REQUEST_HOST = [scheme]://[host][:[port]]
3399  TYPO3_REQUEST_URL = [scheme]://[host][:[port]][path]?[query] (scheme will by default be "http" until we can detect something different)
3400  TYPO3_REQUEST_SCRIPT = [scheme]://[host][:[port]][path_script]
3401  TYPO3_REQUEST_DIR = [scheme]://[host][:[port]][path_dir]
3402  TYPO3_SITE_URL = [scheme]://[host][:[port]][path_dir] of the TYPO3 website frontend
3403  TYPO3_SITE_PATH = [path_dir] of the TYPO3 website frontend
3404  TYPO3_SITE_SCRIPT = [script / Speaking URL] of the TYPO3 website
3405  TYPO3_DOCUMENT_ROOT = Absolute path of root of documents: TYPO3_DOCUMENT_ROOT.SCRIPT_NAME = SCRIPT_FILENAME (typically)
3406  TYPO3_SSL = Returns TRUE if this session uses SSL/TLS (https)
3407  TYPO3_PROXY = Returns TRUE if this session runs over a well known proxyNotice: [fragment] is apparently NEVER available to the script!Testing suggestions:
3408  - Output all the values.
3409  - In the script, make a link to the script it self, maybe add some parameters and click the link a few times so HTTP_REFERER is seen
3410  - ALSO TRY the script from the ROOT of a site (like 'http://www.mytest.com/' and not 'http://www.mytest.com/test/' !!)
3411  */
3412  $retVal = '';
3413  switch ((string) $getEnvName) {
3414  case 'SCRIPT_NAME':
3415  $retVal = self::isRunningOnCgiServerApi()
3416  && ($_SERVER['ORIG_PATH_INFO'] ?: $_SERVER['PATH_INFO'])
3417  ? ($_SERVER['ORIG_PATH_INFO'] ?: $_SERVER['PATH_INFO'])
3418  : ($_SERVER['ORIG_SCRIPT_NAME'] ?: $_SERVER['SCRIPT_NAME']);
3419  // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
3420  if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
3421  if (self::getIndpEnv('TYPO3_SSL') && $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL']) {
3422  $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL'] . $retVal;
3423  } elseif ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix']) {
3424  $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'] . $retVal;
3425  }
3426  }
3427  break;
3428  case 'SCRIPT_FILENAME':
3429  $retVal = PATH_thisScript;
3430  break;
3431  case 'REQUEST_URI':
3432  // Typical application of REQUEST_URI is return urls, forms submitting to itself etc. Example: returnUrl='.rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI'))
3433  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar']) {
3434  // This is for URL rewriters that store the original URI in a server variable (eg ISAPI_Rewriter for IIS: HTTP_X_REWRITE_URL)
3435  list($v, $n) = explode('|', $GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar']);
3436  $retVal = $GLOBALS[$v][$n];
3437  } elseif (!$_SERVER['REQUEST_URI']) {
3438  // This is for ISS/CGI which does not have the REQUEST_URI available.
3439  $retVal = '/' . ltrim(self::getIndpEnv('SCRIPT_NAME'), '/') . ($_SERVER['QUERY_STRING'] ? '?' . $_SERVER['QUERY_STRING'] : '');
3440  } else {
3441  $retVal = '/' . ltrim($_SERVER['REQUEST_URI'], '/');
3442  }
3443  // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
3444  if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
3445  if (self::getIndpEnv('TYPO3_SSL') && $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL']) {
3446  $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefixSSL'] . $retVal;
3447  } elseif ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix']) {
3448  $retVal = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyPrefix'] . $retVal;
3449  }
3450  }
3451  break;
3452  case 'PATH_INFO':
3453  // $_SERVER['PATH_INFO'] != $_SERVER['SCRIPT_NAME'] is necessary because some servers (Windows/CGI)
3454  // are seen to set PATH_INFO equal to script_name
3455  // Further, there must be at least one '/' in the path - else the PATH_INFO value does not make sense.
3456  // IF 'PATH_INFO' never works for our purpose in TYPO3 with CGI-servers,
3457  // then 'PHP_SAPI=='cgi'' might be a better check.
3458  // Right now strcmp($_SERVER['PATH_INFO'], GeneralUtility::getIndpEnv('SCRIPT_NAME')) will always
3459  // return FALSE for CGI-versions, but that is only as long as SCRIPT_NAME is set equal to PATH_INFO
3460  // because of PHP_SAPI=='cgi' (see above)
3461  if (!self::isRunningOnCgiServerApi()) {
3462  $retVal = $_SERVER['PATH_INFO'];
3463  }
3464  break;
3465  case 'TYPO3_REV_PROXY':
3466  $retVal = self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP']);
3467  break;
3468  case 'REMOTE_ADDR':
3469  $retVal = $_SERVER['REMOTE_ADDR'];
3470  if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
3471  $ip = self::trimExplode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
3472  // Choose which IP in list to use
3473  if (count($ip)) {
3474  switch ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyHeaderMultiValue']) {
3475  case 'last':
3476  $ip = array_pop($ip);
3477  break;
3478  case 'first':
3479  $ip = array_shift($ip);
3480  break;
3481  case 'none':
3482 
3483  default:
3484  $ip = '';
3485  }
3486  }
3487  if (self::validIP($ip)) {
3488  $retVal = $ip;
3489  }
3490  }
3491  break;
3492  case 'HTTP_HOST':
3493  $retVal = $_SERVER['HTTP_HOST'];
3494  if (self::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
3495  $host = self::trimExplode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
3496  // Choose which host in list to use
3497  if (count($host)) {
3498  switch ($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyHeaderMultiValue']) {
3499  case 'last':
3500  $host = array_pop($host);
3501  break;
3502  case 'first':
3503  $host = array_shift($host);
3504  break;
3505  case 'none':
3506 
3507  default:
3508  $host = '';
3509  }
3510  }
3511  if ($host) {
3512  $retVal = $host;
3513  }
3514  }
3515  if (!static::isAllowedHostHeaderValue($retVal)) {
3516  throw new \UnexpectedValueException(
3517  'The current host header value does not match the configured trusted hosts pattern! Check the pattern defined in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'trustedHostsPattern\'] and adapt it, if you want to allow the current host header \'' . $retVal . '\' for your installation.',
3518  1396795884
3519  );
3520  }
3521  break;
3522  case 'HTTP_REFERER':
3523 
3524  case 'HTTP_USER_AGENT':
3525 
3526  case 'HTTP_ACCEPT_ENCODING':
3527 
3528  case 'HTTP_ACCEPT_LANGUAGE':
3529 
3530  case 'REMOTE_HOST':
3531 
3532  case 'QUERY_STRING':
3533  $retVal = '';
3534  if (isset($_SERVER[$getEnvName])) {
3535  $retVal = $_SERVER[$getEnvName];
3536  }
3537  break;
3538  case 'TYPO3_DOCUMENT_ROOT':
3539  // Get the web root (it is not the root of the TYPO3 installation)
3540  // The absolute path of the script can be calculated with TYPO3_DOCUMENT_ROOT + SCRIPT_FILENAME
3541  // Some CGI-versions (LA13CGI) and mod-rewrite rules on MODULE versions will deliver a 'wrong' DOCUMENT_ROOT (according to our description). Further various aliases/mod_rewrite rules can disturb this as well.
3542  // Therefore the DOCUMENT_ROOT is now always calculated as the SCRIPT_FILENAME minus the end part shared with SCRIPT_NAME.
3543  $SFN = self::getIndpEnv('SCRIPT_FILENAME');
3544  $SN_A = explode('/', strrev(self::getIndpEnv('SCRIPT_NAME')));
3545  $SFN_A = explode('/', strrev($SFN));
3546  $acc = array();
3547  foreach ($SN_A as $kk => $vv) {
3548  if ((string)$SFN_A[$kk] === (string)$vv) {
3549  $acc[] = $vv;
3550  } else {
3551  break;
3552  }
3553  }
3554  $commonEnd = strrev(implode('/', $acc));
3555  if ((string)$commonEnd !== '') {
3556  $DR = substr($SFN, 0, -(strlen($commonEnd) + 1));
3557  }
3558  $retVal = $DR;
3559  break;
3560  case 'TYPO3_HOST_ONLY':
3561  $httpHost = self::getIndpEnv('HTTP_HOST');
3562  $httpHostBracketPosition = strpos($httpHost, ']');
3563  $httpHostParts = explode(':', $httpHost);
3564  $retVal = $httpHostBracketPosition !== FALSE ? substr($httpHost, 0, $httpHostBracketPosition + 1) : array_shift($httpHostParts);
3565  break;
3566  case 'TYPO3_PORT':
3567  $httpHost = self::getIndpEnv('HTTP_HOST');
3568  $httpHostOnly = self::getIndpEnv('TYPO3_HOST_ONLY');
3569  $retVal = strlen($httpHost) > strlen($httpHostOnly) ? substr($httpHost, strlen($httpHostOnly) + 1) : '';
3570  break;
3571  case 'TYPO3_REQUEST_HOST':
3572  $retVal = (self::getIndpEnv('TYPO3_SSL') ? 'https://' : 'http://') . self::getIndpEnv('HTTP_HOST');
3573  break;
3574  case 'TYPO3_REQUEST_URL':
3575  $retVal = self::getIndpEnv('TYPO3_REQUEST_HOST') . self::getIndpEnv('REQUEST_URI');
3576  break;
3577  case 'TYPO3_REQUEST_SCRIPT':
3578  $retVal = self::getIndpEnv('TYPO3_REQUEST_HOST') . self::getIndpEnv('SCRIPT_NAME');
3579  break;
3580  case 'TYPO3_REQUEST_DIR':
3581  $retVal = self::getIndpEnv('TYPO3_REQUEST_HOST') . self::dirname(self::getIndpEnv('SCRIPT_NAME')) . '/';
3582  break;
3583  case 'TYPO3_SITE_URL':
3584  $url = self::getIndpEnv('TYPO3_REQUEST_DIR');
3585  // This can only be set by external entry scripts
3586  if (defined('TYPO3_PATH_WEB')) {
3587  $retVal = $url;
3588  } elseif (defined('PATH_thisScript') && defined('PATH_site')) {
3589  $lPath = \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix(dirname(PATH_thisScript)) . '/';
3590  $siteUrl = substr($url, 0, -strlen($lPath));
3591  if (substr($siteUrl, -1) != '/') {
3592  $siteUrl .= '/';
3593  }
3594  $retVal = $siteUrl;
3595  }
3596  break;
3597  case 'TYPO3_SITE_PATH':
3598  $retVal = substr(self::getIndpEnv('TYPO3_SITE_URL'), strlen(self::getIndpEnv('TYPO3_REQUEST_HOST')));
3599  break;
3600  case 'TYPO3_SITE_SCRIPT':
3601  $retVal = substr(self::getIndpEnv('TYPO3_REQUEST_URL'), strlen(self::getIndpEnv('TYPO3_SITE_URL')));
3602  break;
3603  case 'TYPO3_SSL':
3604  $proxySSL = trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL']);
3605  if ($proxySSL == '*') {
3606  $proxySSL = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'];
3607  }
3608  if (self::cmpIP($_SERVER['REMOTE_ADDR'], $proxySSL)) {
3609  $retVal = TRUE;
3610  } else {
3611  $retVal = $_SERVER['SSL_SESSION_ID'] || strtolower($_SERVER['HTTPS']) === 'on' || (string)$_SERVER['HTTPS'] === '1' ? TRUE : FALSE;
3612  }
3613  break;
3614  case '_ARRAY':
3615  $out = array();
3616  // Here, list ALL possible keys to this function for debug display.
3617  $envTestVars = array(
3618  'HTTP_HOST',
3619  'TYPO3_HOST_ONLY',
3620  'TYPO3_PORT',
3621  'PATH_INFO',
3622  'QUERY_STRING',
3623  'REQUEST_URI',
3624  'HTTP_REFERER',
3625  'TYPO3_REQUEST_HOST',
3626  'TYPO3_REQUEST_URL',
3627  'TYPO3_REQUEST_SCRIPT',
3628  'TYPO3_REQUEST_DIR',
3629  'TYPO3_SITE_URL',
3630  'TYPO3_SITE_SCRIPT',
3631  'TYPO3_SSL',
3632  'TYPO3_REV_PROXY',
3633  'SCRIPT_NAME',
3634  'TYPO3_DOCUMENT_ROOT',
3635  'SCRIPT_FILENAME',
3636  'REMOTE_ADDR',
3637  'REMOTE_HOST',
3638  'HTTP_USER_AGENT',
3639  'HTTP_ACCEPT_LANGUAGE'
3640  );
3641  foreach ($envTestVars as $v) {
3642  $out[$v] = self::getIndpEnv($v);
3643  }
3644  reset($out);
3645  $retVal = $out;
3646  break;
3647  }
3648  return $retVal;
3649  }
3650 
3658  static public function isAllowedHostHeaderValue($hostHeaderValue) {
3659  if (static::$allowHostHeaderValue === TRUE) {
3660  return TRUE;
3661  }
3662 
3663  if (static::isInternalRequestType()) {
3664  return static::$allowHostHeaderValue = TRUE;
3665  }
3666 
3667  // Deny the value if trusted host patterns is empty, which means we are early in the bootstrap
3668  if (empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'])) {
3669  return FALSE;
3670  }
3671 
3672  if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === self::ENV_TRUSTED_HOSTS_PATTERN_ALLOW_ALL) {
3673  static::$allowHostHeaderValue = TRUE;
3674  } elseif ($GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] === self::ENV_TRUSTED_HOSTS_PATTERN_SERVER_NAME) {
3675  // Allow values that equal the server name
3676  // Note that this is only secure if name base virtual host are configured correctly in the webserver
3677  $defaultPort = self::getIndpEnv('TYPO3_SSL') ? '443' : '80';
3678  $parsedHostValue = parse_url('http://' . $hostHeaderValue);
3679  if (isset($parsedHostValue['port'])) {
3680  static::$allowHostHeaderValue = (strtolower($parsedHostValue['host']) === strtolower($_SERVER['SERVER_NAME']) && (string)$parsedHostValue['port'] === $_SERVER['SERVER_PORT']);
3681  } else {
3682  static::$allowHostHeaderValue = (strtolower($hostHeaderValue) === strtolower($_SERVER['SERVER_NAME']) && $defaultPort === $_SERVER['SERVER_PORT']);
3683  }
3684  } else {
3685  // In case name based virtual hosts are not possible, we allow setting a trusted host pattern
3686  // See https://typo3.org/teams/security/security-bulletins/typo3-core/typo3-core-sa-2014-001/ for further details
3687  static::$allowHostHeaderValue = (bool)preg_match('/^' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] . '$/i', $hostHeaderValue);
3688  }
3689 
3690  return static::$allowHostHeaderValue;
3691  }
3692 
3701  static protected function isInternalRequestType() {
3702  return (defined('TYPO3_REQUESTTYPE') && TYPO3_REQUESTTYPE & (TYPO3_REQUESTTYPE_INSTALL | TYPO3_REQUESTTYPE_CLI));
3703  }
3704 
3710  static public function milliseconds() {
3711  return round(microtime(TRUE) * 1000);
3712  }
3713 
3720  static public function clientInfo($useragent = '') {
3721  if (!$useragent) {
3722  $useragent = self::getIndpEnv('HTTP_USER_AGENT');
3723  }
3724  $bInfo = array();
3725  // Which browser?
3726  if (strpos($useragent, 'Konqueror') !== FALSE) {
3727  $bInfo['BROWSER'] = 'konqu';
3728  } elseif (strpos($useragent, 'Opera') !== FALSE) {
3729  $bInfo['BROWSER'] = 'opera';
3730  } elseif (strpos($useragent, 'MSIE') !== FALSE) {
3731  $bInfo['BROWSER'] = 'msie';
3732  } elseif (strpos($useragent, 'Mozilla') !== FALSE) {
3733  $bInfo['BROWSER'] = 'net';
3734  } elseif (strpos($useragent, 'Flash') !== FALSE) {
3735  $bInfo['BROWSER'] = 'flash';
3736  }
3737  if (isset($bInfo['BROWSER'])) {
3738  // Browser version
3739  switch ($bInfo['BROWSER']) {
3740  case 'net':
3741  $bInfo['VERSION'] = doubleval(substr($useragent, 8));
3742  if (strpos($useragent, 'Netscape6/') !== FALSE) {
3743  $bInfo['VERSION'] = doubleval(substr(strstr($useragent, 'Netscape6/'), 10));
3744  }
3745  // Will we ever know if this was a typo or intention...?! :-(
3746  if (strpos($useragent, 'Netscape/6') !== FALSE) {
3747  $bInfo['VERSION'] = doubleval(substr(strstr($useragent, 'Netscape/6'), 10));
3748  }
3749  if (strpos($useragent, 'Netscape/7') !== FALSE) {
3750  $bInfo['VERSION'] = doubleval(substr(strstr($useragent, 'Netscape/7'), 9));
3751  }
3752  break;
3753  case 'msie':
3754  $tmp = strstr($useragent, 'MSIE');
3755  $bInfo['VERSION'] = doubleval(preg_replace('/^[^0-9]*/', '', substr($tmp, 4)));
3756  break;
3757  case 'opera':
3758  $tmp = strstr($useragent, 'Opera');
3759  $bInfo['VERSION'] = doubleval(preg_replace('/^[^0-9]*/', '', substr($tmp, 5)));
3760  break;
3761  case 'konqu':
3762  $tmp = strstr($useragent, 'Konqueror/');
3763  $bInfo['VERSION'] = doubleval(substr($tmp, 10));
3764  break;
3765  }
3766  // Client system
3767  if (strpos($useragent, 'Win') !== FALSE) {
3768  $bInfo['SYSTEM'] = 'win';
3769  } elseif (strpos($useragent, 'Mac') !== FALSE) {
3770  $bInfo['SYSTEM'] = 'mac';
3771  } elseif (strpos($useragent, 'Linux') !== FALSE || strpos($useragent, 'X11') !== FALSE || strpos($useragent, 'SGI') !== FALSE || strpos($useragent, ' SunOS ') !== FALSE || strpos($useragent, ' HP-UX ') !== FALSE) {
3772  $bInfo['SYSTEM'] = 'unix';
3773  }
3774  }
3775  return $bInfo;
3776  }
3777 
3784  static public function getHostname($requestHost = TRUE) {
3785  $host = '';
3786  // If not called from the command-line, resolve on getIndpEnv()
3787  // Note that TYPO3_REQUESTTYPE is not used here as it may not yet be defined
3788  if ($requestHost && (!defined('TYPO3_cliMode') || !TYPO3_cliMode)) {
3789  $host = self::getIndpEnv('HTTP_HOST');
3790  }
3791  if (!$host) {
3792  // will fail for PHP 4.1 and 4.2
3793  $host = @php_uname('n');
3794  // 'n' is ignored in broken installations
3795  if (strpos($host, ' ')) {
3796  $host = '';
3797  }
3798  }
3799  // We have not found a FQDN yet
3800  if ($host && strpos($host, '.') === FALSE) {
3801  $ip = gethostbyname($host);
3802  // We got an IP address
3803  if ($ip != $host) {
3804  $fqdn = gethostbyaddr($ip);
3805  if ($ip != $fqdn) {
3806  $host = $fqdn;
3807  }
3808  }
3809  }
3810  if (!$host) {
3811  $host = 'localhost.localdomain';
3812  }
3813  return $host;
3814  }
3815 
3816  /*************************
3817  *
3818  * TYPO3 SPECIFIC FUNCTIONS
3819  *
3820  *************************/
3832  static public function getFileAbsFileName($filename, $onlyRelative = TRUE, $relToTYPO3_mainDir = FALSE) {
3833  if ((string)$filename === '') {
3834  return '';
3835  }
3836  $relPathPrefix = PATH_site;
3837  if ($relToTYPO3_mainDir) {
3838  $relPathPrefix = PATH_typo3;
3839  }
3840 
3841  // Extension
3842  if (strpos($filename, 'EXT:') === 0) {
3843  list($extKey, $local) = explode('/', substr($filename, 4), 2);
3844  $filename = '';
3845  if ((string)$extKey !== '' && \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded($extKey) && (string)$local !== '') {
3847  }
3848  } elseif (!self::isAbsPath($filename)) {
3849  // relative. Prepended with $relPathPrefix
3850  $filename = $relPathPrefix . $filename;
3851  } elseif ($onlyRelative && !self::isFirstPartOfStr($filename, $relPathPrefix)) {
3852  // absolute, but set to blank if not allowed
3853  $filename = '';
3854  }
3855  if ((string)$filename !== '' && self::validPathStr($filename)) {
3856  // checks backpath.
3857  return $filename;
3858  }
3859  return '';
3860  }
3861 
3874  static public function validPathStr($theFile) {
3875  return strpos($theFile, '//') === FALSE && strpos($theFile, '\\') === FALSE
3876  && preg_match('#(?:^\\.\\.|/\\.\\./|[[:cntrl:]])#u', $theFile) === 0;
3877  }
3878 
3885  static public function isAbsPath($path) {
3886  return $path[0] === '/' || TYPO3_OS === 'WIN' && (strpos($path, ':/') === 1 || strpos($path, ':\\') === 1);
3887  }
3888 
3895  static public function isAllowedAbsPath($path) {
3896  $lockRootPath = $GLOBALS['TYPO3_CONF_VARS']['BE']['lockRootPath'];
3897  return self::isAbsPath($path) && self::validPathStr($path)
3898  && (self::isFirstPartOfStr($path, PATH_site)
3899  || $lockRootPath && self::isFirstPartOfStr($path, $lockRootPath));
3900  }
3901 
3911  static public function verifyFilenameAgainstDenyPattern($filename) {
3912  $pattern = '/[[:cntrl:]]/';
3913  if ((string)$filename !== '' && (string)$GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] !== '') {
3914  $pattern = '/(?:[[:cntrl:]]|' . $GLOBALS['TYPO3_CONF_VARS']['BE']['fileDenyPattern'] . ')/i';
3915  }
3916  return !preg_match($pattern, $filename);
3917  }
3918 
3925  public static function copyDirectory($source, $destination) {
3926  if (strpos($source, PATH_site) === FALSE) {
3927  $source = PATH_site . $source;
3928  }
3929  if (strpos($destination, PATH_site) === FALSE) {
3930  $destination = PATH_site . $destination;
3931  }
3932  if (static::isAllowedAbsPath($source) && static::isAllowedAbsPath($destination)) {
3933  $iterator = new \RecursiveIteratorIterator(
3934  new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS),
3935  \RecursiveIteratorIterator::SELF_FIRST
3936  );
3937  foreach ($iterator as $item) {
3938  $target = $destination . '/' . $iterator->getSubPathName();
3939  if ($item->isDir()) {
3940  static::mkdir($target);
3941  } else {
3942  static::upload_copy_move($item, $target);
3943  }
3944  }
3945  }
3946  }
3947 
3955  static public function sanitizeLocalUrl($url = '') {
3956  $sanitizedUrl = '';
3957  $decodedUrl = rawurldecode($url);
3958  if (!empty($url) && self::removeXSS($decodedUrl) === $decodedUrl) {
3959  $parsedUrl = parse_url($decodedUrl);
3960  $testAbsoluteUrl = self::resolveBackPath($decodedUrl);
3961  $testRelativeUrl = self::resolveBackPath(self::dirname(self::getIndpEnv('SCRIPT_NAME')) . '/' . $decodedUrl);
3962  // Pass if URL is on the current host:
3963  if (self::isValidUrl($decodedUrl)) {
3964  if (self::isOnCurrentHost($decodedUrl) && strpos($decodedUrl, self::getIndpEnv('TYPO3_SITE_URL')) === 0) {
3965  $sanitizedUrl = $url;
3966  }
3967  } elseif (self::isAbsPath($decodedUrl) && self::isAllowedAbsPath($decodedUrl)) {
3968  $sanitizedUrl = $url;
3969  } elseif (strpos($testAbsoluteUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && $decodedUrl[0] === '/') {
3970  $sanitizedUrl = $url;
3971  } elseif (empty($parsedUrl['scheme']) && strpos($testRelativeUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && $decodedUrl[0] !== '/') {
3972  $sanitizedUrl = $url;
3973  }
3974  }
3975  if (!empty($url) && empty($sanitizedUrl)) {
3976  self::sysLog('The URL "' . $url . '" is not considered to be local and was denied.', 'Core', self::SYSLOG_SEVERITY_NOTICE);
3977  }
3978  return $sanitizedUrl;
3979  }
3980 
3990  static public function upload_copy_move($source, $destination) {
3991  if (is_uploaded_file($source)) {
3992  $uploaded = TRUE;
3993  // Return the value of move_uploaded_file, and if FALSE the temporary $source is still around so the user can use unlink to delete it:
3994  $uploadedResult = move_uploaded_file($source, $destination);
3995  } else {
3996  $uploaded = FALSE;
3997  @copy($source, $destination);
3998  }
3999  // Change the permissions of the file
4000  self::fixPermissions($destination);
4001  // If here the file is copied and the temporary $source is still around, so when returning FALSE the user can try unlink to delete the $source
4002  return $uploaded ? $uploadedResult : FALSE;
4003  }
4004 
4014  static public function upload_to_tempfile($uploadedFileName) {
4015  if (is_uploaded_file($uploadedFileName)) {
4016  $tempFile = self::tempnam('upload_temp_');
4017  move_uploaded_file($uploadedFileName, $tempFile);
4018  return @is_file($tempFile) ? $tempFile : '';
4019  }
4020  }
4021 
4031  static public function unlink_tempfile($uploadedTempFileName) {
4032  if ($uploadedTempFileName) {
4033  $uploadedTempFileName = self::fixWindowsFilePath($uploadedTempFileName);
4034  if (
4035  self::validPathStr($uploadedTempFileName)
4036  && self::isFirstPartOfStr($uploadedTempFileName, PATH_site . 'typo3temp/')
4037  && @is_file($uploadedTempFileName)
4038  ) {
4039  if (unlink($uploadedTempFileName)) {
4040  return TRUE;
4041  }
4042  }
4043  }
4044  }
4045 
4056  static public function tempnam($filePrefix, $fileSuffix = '') {
4057  $temporaryPath = PATH_site . 'typo3temp/';
4058  if ($fileSuffix === '') {
4059  $tempFileName = $temporaryPath . basename(tempnam($temporaryPath, $filePrefix));
4060  } else {
4061  do {
4062  $tempFileName = $temporaryPath . $filePrefix . mt_rand(1, PHP_INT_MAX) . $fileSuffix;
4063  } while (file_exists($tempFileName));
4064  touch($tempFileName);
4065  clearstatcache(NULL, $tempFileName);
4066  }
4067  return $tempFileName;
4068  }
4069 
4078  static public function stdAuthCode($uid_or_record, $fields = '', $codeLength = 8) {
4079  if (is_array($uid_or_record)) {
4080  $recCopy_temp = array();
4081  if ($fields) {
4082  $fieldArr = self::trimExplode(',', $fields, TRUE);
4083  foreach ($fieldArr as $k => $v) {
4084  $recCopy_temp[$k] = $uid_or_record[$v];
4085  }
4086  } else {
4087  $recCopy_temp = $uid_or_record;
4088  }
4089  $preKey = implode('|', $recCopy_temp);
4090  } else {
4091  $preKey = $uid_or_record;
4092  }
4093  $authCode = $preKey . '||' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
4094  $authCode = substr(md5($authCode), 0, $codeLength);
4095  return $authCode;
4096  }
4097 
4104  static public function hideIfNotTranslated($l18n_cfg_fieldValue) {
4105  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['hidePagesIfNotTranslatedByDefault']) {
4106  return $l18n_cfg_fieldValue & 2 ? FALSE : TRUE;
4107  } else {
4108  return $l18n_cfg_fieldValue & 2 ? TRUE : FALSE;
4109  }
4110  }
4111 
4119  static public function hideIfDefaultLanguage($localizationConfiguration) {
4120  return $localizationConfiguration & 1;
4121  }
4122 
4132  static public function readLLfile($fileRef, $langKey, $charset = '', $errorMode = 0) {
4134  $languageFactory = self::makeInstance('TYPO3\\CMS\\Core\\Localization\\LocalizationFactory');
4135  return $languageFactory->getParsedData($fileRef, $langKey, $charset, $errorMode);
4136  }
4137 
4146  static public function llXmlAutoFileName($fileRef, $language, $sameLocation = FALSE) {
4147  // If $fileRef is already prefixed with "[language key]" then we should return it as is
4148  $fileName = basename($fileRef);
4149  if (self::isFirstPartOfStr($fileName, $language . '.')) {
4150  return $fileRef;
4151  }
4152 
4153  if ($sameLocation) {
4154  return str_replace($fileName, $language . '.' . $fileName, $fileRef);
4155  }
4156 
4157  // Analyse file reference:
4158  // Is system:
4159  if (self::isFirstPartOfStr($fileRef, PATH_typo3 . 'sysext/')) {
4160  $validatedPrefix = PATH_typo3 . 'sysext/';
4161  } elseif (self::isFirstPartOfStr($fileRef, PATH_typo3 . 'ext/')) {
4162  // Is global:
4163  $validatedPrefix = PATH_typo3 . 'ext/';
4164  } elseif (self::isFirstPartOfStr($fileRef, PATH_typo3conf . 'ext/')) {
4165  // Is local:
4166  $validatedPrefix = PATH_typo3conf . 'ext/';
4167  } else {
4168  $validatedPrefix = '';
4169  }
4170  if ($validatedPrefix) {
4171  // Divide file reference into extension key, directory (if any) and base name:
4172  list($file_extKey, $file_extPath) = explode('/', substr($fileRef, strlen($validatedPrefix)), 2);
4173  $temp = self::revExplode('/', $file_extPath, 2);
4174  if (count($temp) === 1) {
4175  array_unshift($temp, '');
4176  }
4177  // Add empty first-entry if not there.
4178  list($file_extPath, $file_fileName) = $temp;
4179  // The filename is prefixed with "[language key]." because it prevents the llxmltranslate tool from detecting it.
4180  $location = 'typo3conf/l10n/' . $language . '/' . $file_extKey . '/' . ($file_extPath ? $file_extPath . '/' : '');
4181  return $location . $language . '.' . $file_fileName;
4182  }
4183  return NULL;
4184  }
4185 
4198  static public function loadTCA($table) {
4199  // This method is obsolete, full TCA is always loaded in all context except eID
4200  static::logDeprecatedFunction();
4201  }
4202 
4211  static public function resolveSheetDefInDS($dataStructArray, $sheet = 'sDEF') {
4212  if (!is_array($dataStructArray)) {
4213  return 'Data structure must be an array';
4214  }
4215  if (is_array($dataStructArray['sheets'])) {
4216  $singleSheet = FALSE;
4217  if (!isset($dataStructArray['sheets'][$sheet])) {
4218  $sheet = 'sDEF';
4219  }
4220  $dataStruct = $dataStructArray['sheets'][$sheet];
4221  // If not an array, but still set, then regard it as a relative reference to a file:
4222  if ($dataStruct && !is_array($dataStruct)) {
4223  $file = self::getFileAbsFileName($dataStruct);
4224  if ($file && @is_file($file)) {
4225  $dataStruct = self::xml2array(self::getUrl($file));
4226  }
4227  }
4228  } else {
4229  $singleSheet = TRUE;
4230  $dataStruct = $dataStructArray;
4231  if (isset($dataStruct['meta'])) {
4232  unset($dataStruct['meta']);
4233  }
4234  // Meta data should not appear there.
4235  // Default sheet
4236  $sheet = 'sDEF';
4237  }
4238  return array($dataStruct, $sheet, $singleSheet);
4239  }
4240 
4248  static public function resolveAllSheetsInDS(array $dataStructArray) {
4249  if (is_array($dataStructArray['sheets'])) {
4250  $out = array('sheets' => array());
4251  foreach ($dataStructArray['sheets'] as $sheetId => $sDat) {
4252  list($ds, $aS) = self::resolveSheetDefInDS($dataStructArray, $sheetId);
4253  if ($sheetId == $aS) {
4254  $out['sheets'][$aS] = $ds;
4255  }
4256  }
4257  } else {
4258  list($ds) = self::resolveSheetDefInDS($dataStructArray);
4259  $out = array('sheets' => array('sDEF' => $ds));
4260  }
4261  return $out;
4262  }
4263 
4276  static public function callUserFunction($funcName, &$params, &$ref, $checkPrefix = '', $errorMode = 0) {
4277  $content = FALSE;
4278  // Check if we're using a closure and invoke it directly.
4279  if (is_object($funcName) && is_a($funcName, 'Closure')) {
4280  return call_user_func_array($funcName, array(&$params, &$ref));
4281  }
4282  // Check persistent object and if found, call directly and exit.
4283  if (is_array($GLOBALS['T3_VAR']['callUserFunction'][$funcName])) {
4284  return call_user_func_array(array(
4285  &$GLOBALS['T3_VAR']['callUserFunction'][$funcName]['obj'],
4286  $GLOBALS['T3_VAR']['callUserFunction'][$funcName]['method']
4287  ), array(&$params, &$ref));
4288  }
4289  // Check file-reference prefix; if found, require_once() the file (should be library of code)
4290  if (strpos($funcName, ':') !== FALSE) {
4291  list($file, $funcRef) = self::revExplode(':', $funcName, 2);
4292  $requireFile = self::getFileAbsFileName($file);
4293  if ($requireFile) {
4294  self::requireOnce($requireFile);
4295  }
4296  } else {
4297  $funcRef = $funcName;
4298  }
4299  // Check for persistent object token, "&"
4300  if ($funcRef[0] === '&') {
4301  $funcRef = substr($funcRef, 1);
4302  $storePersistentObject = TRUE;
4303  } else {
4304  $storePersistentObject = FALSE;
4305  }
4306  // Call function or method:
4307  $parts = explode('->', $funcRef);
4308  if (count($parts) == 2) {
4309  // Class
4310  // Check if class/method exists:
4311  if (class_exists($parts[0])) {
4312  // Get/Create object of class:
4313  if ($storePersistentObject) {
4314  // Get reference to current instance of class:
4315  if (!is_object($GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]])) {
4316  $GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]] = self::makeInstance($parts[0]);
4317  }
4318  $classObj = $GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]];
4319  } else {
4320  // Create new object:
4321  $classObj = self::makeInstance($parts[0]);
4322  }
4323  if (method_exists($classObj, $parts[1])) {
4324  // If persistent object should be created, set reference:
4325  if ($storePersistentObject) {
4326  $GLOBALS['T3_VAR']['callUserFunction'][$funcName] = array(
4327  'method' => $parts[1],
4328  'obj' => &$classObj
4329  );
4330  }
4331  // Call method:
4332  $content = call_user_func_array(array(&$classObj, $parts[1]), array(&$params, &$ref));
4333  } else {
4334  $errorMsg = 'No method name \'' . $parts[1] . '\' in class ' . $parts[0];
4335  if ($errorMode == 2) {
4336  throw new \InvalidArgumentException($errorMsg, 1294585865);
4337  } elseif (!$errorMode) {
4338  debug($errorMsg, 'TYPO3\\CMS\\Core\\Utility\\GeneralUtility::callUserFunction');
4339  }
4340  }
4341  } else {
4342  $errorMsg = 'No class named ' . $parts[0];
4343  if ($errorMode == 2) {
4344  throw new \InvalidArgumentException($errorMsg, 1294585866);
4345  } elseif (!$errorMode) {
4346  debug($errorMsg, 'TYPO3\\CMS\\Core\\Utility\\GeneralUtility::callUserFunction');
4347  }
4348  }
4349  } else {
4350  // Function
4351  if (function_exists($funcRef)) {
4352  $content = call_user_func_array($funcRef, array(&$params, &$ref));
4353  } else {
4354  $errorMsg = 'No function named: ' . $funcRef;
4355  if ($errorMode == 2) {
4356  throw new \InvalidArgumentException($errorMsg, 1294585867);
4357  } elseif (!$errorMode) {
4358  debug($errorMsg, 'TYPO3\\CMS\\Core\\Utility\\GeneralUtility::callUserFunction');
4359  }
4360  }
4361  }
4362  return $content;
4363  }
4364 
4378  static public function getUserObj($classRef, $checkPrefix = '', $silent = FALSE) {
4379  // Check persistent object and if found, call directly and exit.
4380  if (is_object($GLOBALS['T3_VAR']['getUserObj'][$classRef])) {
4381  return $GLOBALS['T3_VAR']['getUserObj'][$classRef];
4382  } else {
4383  // Check file-reference prefix; if found, require_once() the file (should be library of code)
4384  if (strpos($classRef, ':') !== FALSE) {
4385  list($file, $class) = self::revExplode(':', $classRef, 2);
4386  $requireFile = self::getFileAbsFileName($file);
4387  if ($requireFile) {
4388  self::requireOnce($requireFile);
4389  }
4390  } else {
4391  $class = $classRef;
4392  }
4393  // Check for persistent object token, "&"
4394  if ($class[0] === '&') {
4395  $class = substr($class, 1);
4396  $storePersistentObject = TRUE;
4397  } else {
4398  $storePersistentObject = FALSE;
4399  }
4400  // Check if class exists:
4401  if (class_exists($class)) {
4402  $classObj = self::makeInstance($class);
4403  // If persistent object should be created, set reference:
4404  if ($storePersistentObject) {
4405  $GLOBALS['T3_VAR']['getUserObj'][$classRef] = $classObj;
4406  }
4407  return $classObj;
4408  }
4409  }
4410  }
4411 
4424  static public function makeInstance($className) {
4425  if (!is_string($className) || empty($className)) {
4426  throw new \InvalidArgumentException('$className must be a non empty string.', 1288965219);
4427  }
4428  // Never instantiate with a beginning backslash, otherwise things like singletons won't work.
4429  if ($className[0] === '\\') {
4430  $className = substr($className, 1);
4431  }
4432  if (isset(static::$finalClassNameCache[$className])) {
4433  $finalClassName = static::$finalClassNameCache[$className];
4434  } else {
4435  $finalClassName = self::getClassName($className);
4436  static::$finalClassNameCache[$className] = $finalClassName;
4437  }
4438  // Return singleton instance if it is already registered
4439  if (isset(self::$singletonInstances[$finalClassName])) {
4440  return self::$singletonInstances[$finalClassName];
4441  }
4442  // Return instance if it has been injected by addInstance()
4443  if (
4444  isset(self::$nonSingletonInstances[$finalClassName])
4445  && !empty(self::$nonSingletonInstances[$finalClassName])
4446  ) {
4447  return array_shift(self::$nonSingletonInstances[$finalClassName]);
4448  }
4449  // Create new instance and call constructor with parameters
4450  $instance = static::instantiateClass($finalClassName, func_get_args());
4451  // Register new singleton instance
4452  if ($instance instanceof \TYPO3\CMS\Core\SingletonInterface) {
4453  self::$singletonInstances[$finalClassName] = $instance;
4454  }
4455  return $instance;
4456  }
4457 
4465  protected static function instantiateClass($className, $arguments) {
4466  switch (count($arguments)) {
4467  case 1:
4468  $instance = new $className();
4469  break;
4470  case 2:
4471  $instance = new $className($arguments[1]);
4472  break;
4473  case 3:
4474  $instance = new $className($arguments[1], $arguments[2]);
4475  break;
4476  case 4:
4477  $instance = new $className($arguments[1], $arguments[2], $arguments[3]);
4478  break;
4479  case 5:
4480  $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4]);
4481  break;
4482  case 6:
4483  $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]);
4484  break;
4485  case 7:
4486  $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]);
4487  break;
4488  case 8:
4489  $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7]);
4490  break;
4491  case 9:
4492  $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]);
4493  break;
4494  default:
4495  // The default case for classes with constructors that have more than 8 arguments.
4496  // This will fail when one of the arguments shall be passed by reference.
4497  // In case we really need to support this edge case, we can implement the solution from here: https://review.typo3.org/26344
4498  $class = new \ReflectionClass($className);
4499  array_shift($arguments);
4500  $instance = $class->newInstanceArgs($arguments);
4501  return $instance;
4502  }
4503  return $instance;
4504  }
4505 
4513  static protected function getClassName($className) {
4514  if (class_exists($className)) {
4515  while (static::classHasImplementation($className)) {
4516  $className = static::getImplementationForClass($className);
4517  }
4518  }
4519  return \TYPO3\CMS\Core\Core\ClassLoader::getClassNameForAlias($className);
4520  }
4521 
4528  static protected function getImplementationForClass($className) {
4529  return $GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className]['className'];
4530  }
4531 
4538  static protected function classHasImplementation($className) {
4539  // If we are early in the bootstrap, the configuration might not yet be present
4540  if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'])) {
4541  return FALSE;
4542  }
4543 
4544  return isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className])
4545  && is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className])
4546  && !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className]['className']);
4547  }
4548 
4567  static public function setSingletonInstance($className, \TYPO3\CMS\Core\SingletonInterface $instance) {
4568  self::checkInstanceClassName($className, $instance);
4569  self::$singletonInstances[$className] = $instance;
4570  }
4571 
4588  static public function removeSingletonInstance($className, \TYPO3\CMS\Core\SingletonInterface $instance) {
4589  self::checkInstanceClassName($className, $instance);
4590  if (!isset(self::$singletonInstances[$className])) {
4591  throw new \InvalidArgumentException('No Instance registered for ' . $className . '.', 1394099179);
4592  }
4593  if ($instance !== self::$singletonInstances[$className]) {
4594  throw new \InvalidArgumentException('The instance you are trying to remove has not been registered before.', 1394099256);
4595  }
4596  unset(self::$singletonInstances[$className]);
4597  }
4598 
4613  static public function resetSingletonInstances(array $newSingletonInstances) {
4614  static::$singletonInstances = array();
4615  foreach ($newSingletonInstances as $className => $instance) {
4616  static::setSingletonInstance($className, $instance);
4617  }
4618  }
4619 
4632  static public function getSingletonInstances() {
4633  return static::$singletonInstances;
4634  }
4635 
4651  static public function addInstance($className, $instance) {
4652  self::checkInstanceClassName($className, $instance);
4653  if ($instance instanceof \TYPO3\CMS\Core\SingletonInterface) {
4654  throw new \InvalidArgumentException('$instance must not be an instance of TYPO3\\CMS\\Core\\SingletonInterface. ' . 'For setting singletons, please use setSingletonInstance.', 1288969325);
4655  }
4656  if (!isset(self::$nonSingletonInstances[$className])) {
4657  self::$nonSingletonInstances[$className] = array();
4658  }
4659  self::$nonSingletonInstances[$className][] = $instance;
4660  }
4661 
4671  static protected function checkInstanceClassName($className, $instance) {
4672  if ($className === '') {
4673  throw new \InvalidArgumentException('$className must not be empty.', 1288967479);
4674  }
4675  if (!$instance instanceof $className) {
4676  throw new \InvalidArgumentException('$instance must be an instance of ' . $className . ', but actually is an instance of ' . get_class($instance) . '.', 1288967686);
4677  }
4678  }
4679 
4691  static public function purgeInstances() {
4692  self::$singletonInstances = array();
4693  self::$nonSingletonInstances = array();
4694  }
4695 
4705  static public function makeInstanceService($serviceType, $serviceSubType = '', $excludeServiceKeys = array()) {
4706  $error = FALSE;
4707  if (!is_array($excludeServiceKeys)) {
4708  $excludeServiceKeys = self::trimExplode(',', $excludeServiceKeys, TRUE);
4709  }
4710  $requestInfo = array(
4711  'requestedServiceType' => $serviceType,
4712  'requestedServiceSubType' => $serviceSubType,
4713  'requestedExcludeServiceKeys' => $excludeServiceKeys
4714  );
4715  while ($info = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::findService($serviceType, $serviceSubType, $excludeServiceKeys)) {
4716  // provide information about requested service to service object
4717  $info = array_merge($info, $requestInfo);
4718  // Check persistent object and if found, call directly and exit.
4719  if (is_object($GLOBALS['T3_VAR']['makeInstanceService'][$info['className']])) {
4720  // update request info in persistent object
4721  $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']]->info = $info;
4722  // reset service and return object
4723  $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']]->reset();
4724  return $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']];
4725  } else {
4726  if (isset($info['classFile'])) {
4727  // @deprecated since 6.1, will be removed in TYPO3 CMS 6.3
4728  // Option is deprecated, since we now have the autoloader function
4729  self::deprecationLog(
4730  'The option "classFile" of "' . $info['className'] .
4731  '" in T3_SERVICES has been deprecated, as this should now be done by the respective ' .
4732  'ext_autoload.php of each extension. This option will be removed in TYPO3 CMS v6.3.'
4733  );
4734  $requireFile = self::getFileAbsFileName($info['classFile']);
4735  if (@is_file($requireFile)) {
4736  self::requireOnce($requireFile);
4737  }
4738  }
4739 
4740  $obj = self::makeInstance($info['className']);
4741  if (is_object($obj)) {
4742  if (!@is_callable(array($obj, 'init'))) {
4743  // use silent logging??? I don't think so.
4744  die('Broken service:' . \TYPO3\CMS\Core\Utility\DebugUtility::viewArray($info));
4745  }
4746  $obj->info = $info;
4747  // service available?
4748  if ($obj->init()) {
4749  // create persistent object
4750  $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']] = $obj;
4751  return $obj;
4752  }
4753  $error = $obj->getLastErrorArray();
4754  unset($obj);
4755  }
4756  }
4757  // deactivate the service
4758  \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::deactivateService($info['serviceType'], $info['serviceKey']);
4759  }
4760  return $error;
4761  }
4762 
4770  static public function requireOnce($requireFile) {
4771  // Needed for require_once
4772  global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
4773  require_once $requireFile;
4774  }
4775 
4784  static public function requireFile($requireFile) {
4785  // Needed for require
4786  global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
4787  require $requireFile;
4788  }
4789 
4805  static public function plainMailEncoded($email, $subject, $message, $headers = '', $encoding = 'quoted-printable', $charset = '', $dontEncodeHeader = FALSE) {
4806  self::logDeprecatedFunction();
4807  if (!$charset) {
4808  $charset = 'utf-8';
4809  }
4810  $email = self::normalizeMailAddress($email);
4811  if (!$dontEncodeHeader) {
4812  // Mail headers must be ASCII, therefore we convert the whole header to either base64 or quoted_printable
4813  $newHeaders = array();
4814  // Split the header in lines and convert each line separately
4815  foreach (explode(LF, $headers) as $line) {
4816  // Field tags must not be encoded
4817  $parts = explode(': ', $line, 2);
4818  if (count($parts) == 2) {
4819  if (0 == strcasecmp($parts[0], 'from')) {
4820  $parts[1] = self::normalizeMailAddress($parts[1]);
4821  }
4822  $parts[1] = self::encodeHeader($parts[1], $encoding, $charset);
4823  $newHeaders[] = implode(': ', $parts);
4824  } else {
4825  // Should never happen - is such a mail header valid? Anyway, just add the unchanged line...
4826  $newHeaders[] = $line;
4827  }
4828  }
4829  $headers = implode(LF, $newHeaders);
4830  unset($newHeaders);
4831  // Email address must not be encoded, but it could be appended by a name which should be so (e.g. "Kasper SkÃ¥rhøj <kasperYYYY@typo3.com>")
4832  $email = self::encodeHeader($email, $encoding, $charset);
4833  $subject = self::encodeHeader($subject, $encoding, $charset);
4834  }
4835  switch ((string) $encoding) {
4836  case 'base64':
4837  $headers = trim($headers) . LF . 'Mime-Version: 1.0' . LF . 'Content-Type: text/plain; charset="' . $charset . '"' . LF . 'Content-Transfer-Encoding: base64';
4838  // Adding LF because I think MS outlook 2002 wants it... may be removed later again.
4839  $message = trim(chunk_split(base64_encode(($message . LF)))) . LF;
4840  break;
4841  case '8bit':
4842  $headers = trim($headers) . LF . 'Mime-Version: 1.0' . LF . 'Content-Type: text/plain; charset=' . $charset . LF . 'Content-Transfer-Encoding: 8bit';
4843  break;
4844  case 'quoted-printable':
4845 
4846  default:
4847  $headers = trim($headers) . LF . 'Mime-Version: 1.0' . LF . 'Content-Type: text/plain; charset=' . $charset . LF . 'Content-Transfer-Encoding: quoted-printable';
4848  $message = self::quoted_printable($message);
4849  }
4850  // Headers must be separated by CRLF according to RFC 2822, not just LF.
4851  // But many servers (Gmail, for example) behave incorrectly and want only LF.
4852  // So we stick to LF in all cases.
4853  // Make sure no empty lines are there.
4854  $headers = trim(implode(LF, self::trimExplode(LF, $headers, TRUE)));
4855  return \TYPO3\CMS\Core\Utility\MailUtility::mail($email, $subject, $message, $headers);
4856  }
4857 
4866  static public function quoted_printable($string, $maxlen = 76) {
4867  // Make sure the string contains only Unix line breaks
4868  // Replace Windows breaks (\r\n)
4869  $string = str_replace(CRLF, LF, $string);
4870  // Replace Mac breaks (\r)
4871  $string = str_replace(CR, LF, $string);
4872  // Default line break for Unix systems.
4873  $linebreak = LF;
4874  if (TYPO3_OS == 'WIN') {
4875  // Line break for Windows. This is needed because PHP on Windows systems send mails via SMTP instead of using sendmail, and thus the line break needs to be \r\n.
4876  $linebreak = CRLF;
4877  }
4878  $newString = '';
4879  // Split lines
4880  $theLines = explode(LF, $string);
4881  foreach ($theLines as $val) {
4882  $newVal = '';
4883  $theValLen = strlen($val);
4884  $len = 0;
4885  // Walk through each character of this line
4886  for ($index = 0; $index < $theValLen; $index++) {
4887  $char = substr($val, $index, 1);
4888  $ordVal = ord($char);
4889  if ($len > $maxlen - 4 || $len > $maxlen - 14 && $ordVal == 32) {
4890  // Add a line break
4891  $newVal .= '=' . $linebreak;
4892  // Reset the length counter
4893  $len = 0;
4894  }
4895  if ($ordVal >= 33 && $ordVal <= 60 || $ordVal >= 62 && $ordVal <= 126 || $ordVal == 9 || $ordVal == 32) {
4896  // This character is ok, add it to the message
4897  $newVal .= $char;
4898  $len++;
4899  } else {
4900  // Special character, needs to be encoded
4901  $newVal .= sprintf('=%02X', $ordVal);
4902  $len += 3;
4903  }
4904  }
4905  // Replaces a possible SPACE-character at the end of a line
4906  $newVal = preg_replace('/' . chr(32) . '$/', '=20', $newVal);
4907  // Replaces a possible TAB-character at the end of a line
4908  $newVal = preg_replace('/' . TAB . '$/', '=09', $newVal);
4909  $newString .= $newVal . $linebreak;
4910  }
4911  // Remove last newline
4912  return preg_replace('/' . $linebreak . '$/', '', $newString);
4913  }
4914 
4924  static public function encodeHeader($line, $enc = 'quoted-printable', $charset = 'utf-8') {
4925  // Avoid problems if "###" is found in $line (would conflict with the placeholder which is used below)
4926  if (strpos($line, '###') !== FALSE) {
4927  return $line;
4928  }
4929  // Check if any non-ASCII characters are found - otherwise encoding is not needed
4930  if (!preg_match(('/[^' . chr(32) . '-' . chr(127) . ']/'), $line)) {
4931  return $line;
4932  }
4933  // Wrap email addresses in a special marker
4934  $line = preg_replace('/([^ ]+@[^ ]+)/', '###$1###', $line);
4935  $matches = preg_split('/(.?###.+###.?|\\(|\\))/', $line, -1, PREG_SPLIT_NO_EMPTY);
4936  foreach ($matches as $part) {
4937  $oldPart = $part;
4938  $partWasQuoted = $part[0] == '"';
4939  $part = trim($part, '"');
4940  switch ((string) $enc) {
4941  case 'base64':
4942  $part = '=?' . $charset . '?B?' . base64_encode($part) . '?=';
4943  break;
4944  case 'quoted-printable':
4945 
4946  default:
4947  $qpValue = self::quoted_printable($part, 1000);
4948  if ($part != $qpValue) {
4949  // Encoded words in the header should not contain non-encoded:
4950  // * spaces. "_" is a shortcut for "=20". See RFC 2047 for details.
4951  // * question mark. See RFC 1342 (http://tools.ietf.org/html/rfc1342)
4952  $search = array(' ', '?');
4953  $replace = array('_', '=3F');
4954  $qpValue = str_replace($search, $replace, $qpValue);
4955  $part = '=?' . $charset . '?Q?' . $qpValue . '?=';
4956  }
4957  }
4958  if ($partWasQuoted) {
4959  $part = '"' . $part . '"';
4960  }
4961  $line = str_replace($oldPart, $part, $line);
4962  }
4963  // Remove the wrappers
4964  $line = preg_replace('/###(.+?)###/', '$1', $line);
4965  return $line;
4966  }
4967 
4978  static public function substUrlsInPlainText($message, $urlmode = '76', $index_script_url = '') {
4979  switch ((string) $urlmode) {
4980  case '':
4981  $lengthLimit = FALSE;
4982  break;
4983  case 'all':
4984  $lengthLimit = 0;
4985  break;
4986  case '76':
4987 
4988  default:
4989  $lengthLimit = (int)$urlmode;
4990  }
4991  if ($lengthLimit === FALSE) {
4992  // No processing
4993  $messageSubstituted = $message;
4994  } else {
4995  $messageSubstituted = preg_replace_callback(
4996  '/(http|https):\\/\\/.+(?=[\\]\\.\\?]*([\\! \'"()<>]+|$))/iU',
4997  function (array $matches) use ($lengthLimit, $index_script_url) {
4998  return GeneralUtility::makeRedirectUrl($matches[0], $lengthLimit, $index_script_url);
4999  },
5000  $message
5001  );
5002  }
5003  return $messageSubstituted;
5004  }
5005 
5014  static public function makeRedirectUrl($inUrl, $l = 0, $index_script_url = '') {
5015  if (strlen($inUrl) > $l) {
5016  $md5 = substr(md5($inUrl), 0, 20);
5017  $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', 'cache_md5params', 'md5hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($md5, 'cache_md5params'));
5018  if (!$count) {
5019  $insertFields = array(
5020  'md5hash' => $md5,
5021  'tstamp' => $GLOBALS['EXEC_TIME'],
5022  'type' => 2,
5023  'params' => $inUrl
5024  );
5025  $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_md5params', $insertFields);
5026  }
5027  $inUrl = ($index_script_url ? $index_script_url : self::getIndpEnv('TYPO3_REQUEST_DIR') . 'index.php') . '?RDCT=' . $md5;
5028  }
5029  return $inUrl;
5030  }
5031 
5038  static public function freetypeDpiComp($font_size) {
5039  $dpi = (int)$GLOBALS['TYPO3_CONF_VARS']['GFX']['TTFdpi'];
5040  if ($dpi != 72) {
5041  $font_size = $font_size / $dpi * 72;
5042  }
5043  return $font_size;
5044  }
5045 
5052  static public function initSysLog() {
5053  // For CLI logging name is <fqdn-hostname>:<TYPO3-path>
5054  // Note that TYPO3_REQUESTTYPE is not used here as it may not yet be defined
5055  if (defined('TYPO3_cliMode') && TYPO3_cliMode) {
5056  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] = self::getHostname(($requestHost = FALSE)) . ':' . PATH_site;
5057  } else {
5058  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] = self::getIndpEnv('TYPO3_SITE_URL');
5059  }
5060  // Init custom logging
5061  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'])) {
5062  $params = array('initLog' => TRUE);
5063  $fakeThis = FALSE;
5064  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] as $hookMethod) {
5065  self::callUserFunction($hookMethod, $params, $fakeThis);
5066  }
5067  }
5068  // Init TYPO3 logging
5069  foreach (explode(';', $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog'], 2) as $log) {
5070  list($type, $destination) = explode(',', $log, 3);
5071  if ($type == 'syslog') {
5072  if (TYPO3_OS == 'WIN') {
5073  $facility = LOG_USER;
5074  } else {
5075  $facility = constant('LOG_' . strtoupper($destination));
5076  }
5077  openlog($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'], LOG_ODELAY, $facility);
5078  }
5079  }
5080  $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'], 0, 4);
5081  $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit'] = TRUE;
5082  }
5083 
5095  static public function sysLog($msg, $extKey, $severity = 0) {
5096  $severity = \TYPO3\CMS\Core\Utility\MathUtility::forceIntegerInRange($severity, 0, 4);
5097  // Is message worth logging?
5098  if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] > $severity) {
5099  return;
5100  }
5101  // Initialize logging
5102  if (!$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit']) {
5103  self::initSysLog();
5104  }
5105  // Do custom logging
5106  if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'])) {
5107  $params = array('msg' => $msg, 'extKey' => $extKey, 'backTrace' => debug_backtrace(), 'severity' => $severity);
5108  $fakeThis = FALSE;
5109  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] as $hookMethod) {
5110  self::callUserFunction($hookMethod, $params, $fakeThis);
5111  }
5112  }
5113  // TYPO3 logging enabled?
5114  if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog']) {
5115  return;
5116  }
5117  $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
5118  $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
5119  // Use all configured logging options
5120  foreach (explode(';', $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog'], 2) as $log) {
5121  list($type, $destination, $level) = explode(',', $log, 4);
5122  // Is message worth logging for this log type?
5123  if ((int)$level > $severity) {
5124  continue;
5125  }
5126  $msgLine = ' - ' . $extKey . ': ' . $msg;
5127  // Write message to a file
5128  if ($type == 'file') {
5129  $file = fopen($destination, 'a');
5130  if ($file) {
5131  fwrite($file, date(($dateFormat . ' ' . $timeFormat)) . $msgLine . LF);
5132  fclose($file);
5133  self::fixPermissions($destination);
5134  }
5135  } elseif ($type == 'mail') {
5136  list($to, $from) = explode('/', $destination);
5137  if (!self::validEmail($from)) {
5139  }
5141  $mail = self::makeInstance('TYPO3\\CMS\\Core\\Mail\\MailMessage');
5142  $mail->setTo($to)->setFrom($from)->setSubject('Warning - error in TYPO3 installation')->setBody('Host: ' . $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] . LF . 'Extension: ' . $extKey . LF . 'Severity: ' . $severity . LF . LF . $msg);
5143  $mail->send();
5144  } elseif ($type == 'error_log') {
5145  error_log($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] . $msgLine, 0);
5146  } elseif ($type == 'syslog') {
5147  $priority = array(LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT);
5148  syslog($priority[(int)$severity], $msgLine);
5149  }
5150  }
5151  }
5152 
5167  static public function devLog($msg, $extKey, $severity = 0, $dataVar = FALSE) {
5168  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog'])) {
5169  $params = array('msg' => $msg, 'extKey' => $extKey, 'severity' => $severity, 'dataVar' => $dataVar);
5170  $fakeThis = FALSE;
5171  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog'] as $hookMethod) {
5172  self::callUserFunction($hookMethod, $params, $fakeThis);
5173  }
5174  }
5175  }
5176 
5183  static public function deprecationLog($msg) {
5184  if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) {
5185  return;
5186  }
5187  // Legacy values (no strict comparison, $log can be boolean, string or int)
5188  $log = $GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog'];
5189  if ($log === TRUE || $log == '1') {
5190  $log = array('file');
5191  } else {
5192  $log = self::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog'], TRUE);
5193  }
5194  $date = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] . ': ');
5195  if (in_array('file', $log) !== FALSE) {
5196  // In case lock is acquired before autoloader was defined:
5197  if (class_exists('TYPO3\\CMS\\Core\\Locking\\Locker') === FALSE) {
5198  require_once ExtensionManagementUtility::extPath('core') . 'Classes/Locking/Locker.php';
5199  }
5200  // Write a longer message to the deprecation log
5201  $destination = self::getDeprecationLogFileName();
5202  $file = @fopen($destination, 'a');
5203  if ($file) {
5204  @fwrite($file, ($date . $msg . LF));
5205  @fclose($file);
5206  self::fixPermissions($destination);
5207  }
5208  }
5209  if (in_array('devlog', $log) !== FALSE) {
5210  // Copy message also to the developer log
5211  self::devLog($msg, 'Core', self::SYSLOG_SEVERITY_WARNING);
5212  }
5213  // Do not use console in login screen
5214  if (in_array('console', $log) !== FALSE && isset($GLOBALS['BE_USER']->user['uid'])) {
5215  \TYPO3\CMS\Core\Utility\DebugUtility::debug($msg, $date, 'Deprecation Log');
5216  }
5217  }
5218 
5224  static public function getDeprecationLogFileName() {
5225  return PATH_typo3conf . 'deprecation_' . self::shortMD5((PATH_site . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) . '.log';
5226  }
5227 
5234  static public function logDeprecatedFunction() {
5235  if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['enableDeprecationLog']) {
5236  return;
5237  }
5238 
5239  // This require_once is needed for deprecation calls
5240  // thrown early during bootstrap, if the autoloader is
5241  // not instantiated yet. This can happen for example if
5242  // ext_localconf triggers a deprecation.
5243  require_once 'DebugUtility.php';
5244 
5245  $trail = debug_backtrace();
5246  if ($trail[1]['type']) {
5247  $function = new \ReflectionMethod($trail[1]['class'], $trail[1]['function']);
5248  } else {
5249  $function = new \ReflectionFunction($trail[1]['function']);
5250  }
5251  $msg = '';
5252  if (preg_match('/@deprecated\\s+(.*)/', $function->getDocComment(), $match)) {
5253  $msg = $match[1];
5254  }
5255  // Write a longer message to the deprecation log: <function> <annotion> - <trace> (<source>)
5256  $logMsg = $trail[1]['class'] . $trail[1]['type'] . $trail[1]['function'];
5257  $logMsg .= '() - ' . $msg . ' - ' . \TYPO3\CMS\Core\Utility\DebugUtility::debugTrail();
5258  $logMsg .= ' (' . \TYPO3\CMS\Core\Utility\PathUtility::stripPathSitePrefix($function->getFileName()) . '#' . $function->getStartLine() . ')';
5259  self::deprecationLog($logMsg);
5260  }
5261 
5271  static public function arrayToLogString(array $arr, $valueList = array(), $valueLength = 20) {
5272  $str = '';
5273  if (!is_array($valueList)) {
5274  $valueList = self::trimExplode(',', $valueList, TRUE);
5275  }
5276  $valListCnt = count($valueList);
5277  foreach ($arr as $key => $value) {
5278  if (!$valListCnt || in_array($key, $valueList)) {
5279  $str .= ((string) $key . trim((': ' . self::fixed_lgd_cs(str_replace(LF, '|', (string) $value), $valueLength)))) . '; ';
5280  }
5281  }
5282  return $str;
5283  }
5284 
5293  static public function imageMagickCommand($command, $parameters, $path = '') {
5294  return \TYPO3\CMS\Core\Utility\CommandUtility::imageMagickCommand($command, $parameters, $path);
5295  }
5296 
5304  static public function unQuoteFilenames($parameters, $unQuote = FALSE) {
5305  $paramsArr = explode(' ', trim($parameters));
5306  // Whenever a quote character (") is found, $quoteActive is set to the element number inside of $params. A value of -1 means that there are not open quotes at the current position.
5307  $quoteActive = -1;
5308  foreach ($paramsArr as $k => $v) {
5309  if ($quoteActive > -1) {
5310  $paramsArr[$quoteActive] .= ' ' . $v;
5311  unset($paramsArr[$k]);
5312  if (substr($v, -1) === $paramsArr[$quoteActive][0]) {
5313  $quoteActive = -1;
5314  }
5315  } elseif (!trim($v)) {
5316  // Remove empty elements
5317  unset($paramsArr[$k]);
5318  } elseif (preg_match('/^(["\'])/', $v) && substr($v, -1) !== $v[0]) {
5319  $quoteActive = $k;
5320  }
5321  }
5322  if ($unQuote) {
5323  foreach ($paramsArr as $key => &$val) {
5324  $val = preg_replace('/(^"|"$)/', '', $val);
5325  $val = preg_replace('/(^\'|\'$)/', '', $val);
5326  }
5327  unset($val);
5328  }
5329  // Return reindexed array
5330  return array_values($paramsArr);
5331  }
5332 
5339  static public function quoteJSvalue($value) {
5340  return strtr(
5341  json_encode((string)$value, JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_TAG),
5342  array(
5343  '"' => '\'',
5344  '\\\\' => '\\u005C',
5345  ' ' => '\\u0020',
5346  '!' => '\\u0021',
5347  '\\t' => '\\u0009',
5348  '\\n' => '\\u000A',
5349  '\\r' => '\\u000D'
5350  )
5351  );
5352  }
5353 
5359  static public function cleanOutputBuffers() {
5360  while (ob_end_clean()) {
5361 
5362  }
5363  header('Content-Encoding: None', TRUE);
5364  }
5365 
5371  static public function flushOutputBuffers() {
5372  $obContent = '';
5373  while ($content = ob_get_clean()) {
5374  $obContent .= $content;
5375  }
5376  // If previously a "Content-Encoding: whatever" has been set, we have to unset it
5377  if (!headers_sent()) {
5378  $headersList = headers_list();
5379  foreach ($headersList as $header) {
5380  // Split it up at the :
5381  list($key, $value) = self::trimExplode(':', $header, TRUE);
5382  // Check if we have a Content-Encoding other than 'None'
5383  if (strtolower($key) === 'content-encoding' && strtolower($value) !== 'none') {
5384  header('Content-Encoding: None');
5385  break;
5386  }
5387  }
5388  }
5389  echo $obContent;
5390  }
5391 
5402  static public function presetApplicationContext(\TYPO3\CMS\Core\Core\ApplicationContext $applicationContext) {
5403  if (is_null(static::$applicationContext)) {
5404  static::$applicationContext = $applicationContext;
5405  } else {
5406  throw new \RuntimeException('Trying to override applicationContext which has already been defined!', 1376084316);
5407  }
5408  }
5409 
5415  static public function getApplicationContext() {
5416  return static::$applicationContext;
5417  }
5418 
5423  static public function isRunningOnCgiServerApi() {
5424  return in_array(PHP_SAPI, self::$supportedCgiServerApis, TRUE);
5425  }
5426 }
static modifyHTMLColor($color, $R, $G, $B)
static createDirectoryPath($fullDirectoryPath)
static imageMagickCommand($command, $parameters, $path='')
static stripSlashesOnArray(array &$theArray)
static minifyJavaScript($script, &$error='')
static implodeAttributes(array $arr, $xhtmlSafe=FALSE, $dontOmitBlankAttribs=FALSE)
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=TRUE, $includeEmptyValues=TRUE, $enableUnsetFeature=TRUE)
static uniqueList($in_list, $secondParameter=NULL)
$TYPO3_CONF_VARS['SYS']['contentTable']
static setSingletonInstance($className, \TYPO3\CMS\Core\SingletonInterface $instance)
static unlink_tempfile($uploadedTempFileName)
static substUrlsInPlainText($message, $urlmode='76', $index_script_url='')
static explodeUrl2Array($string, $multidim=FALSE)
static mkdir_deep($directory, $deepDirectory='')
static addInstance($className, $instance)
static getAllFilesAndFoldersInPath(array $fileArr, $path, $extList='', $regDirs=FALSE, $recursivityLevels=99, $excludePattern='')
static writeFile($file, $content, $changePermissions=FALSE)
$parameters
Definition: FileDumpEID.php:15
static quoted_printable($string, $maxlen=76)
static stdAuthCode($uid_or_record, $fields='', $codeLength=8)
static xml2tree($string, $depth=999)
static debug($var='', $header='', $group='Debug')
static devLog($msg, $extKey, $severity=0, $dataVar=FALSE)
static isFirstPartOfStr($str, $partStr)
static slashJS($string, $extended=FALSE, $char='\'')
static array2xml_cs(array $array, $docTag='phparray', array $options=array(), $charset='')
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
static csvValues(array $row, $delim=',', $quote='"')
static generateRandomBytesUrandom($bytesToGenerate)
static resolveAllSheetsInDS(array $dataStructArray)
static arrayToLogString(array $arr, $valueList=array(), $valueLength=20)
static intExplode($delimiter, $string, $removeEmptyValues=FALSE, $limit=0)
static llXmlAutoFileName($fileRef, $language, $sameLocation=FALSE)
static writeFileToTypo3tempDir($filepath, $content)
const TYPO3_MODE
Definition: init.php:40
static rmdir($path, $removeNonEmpty=FALSE)
static getUserObj($classRef, $checkPrefix='', $silent=FALSE)
static getMaxUploadFileSize($localLimit=0)
static hmac($input, $additionalSecret='')
static makeInstanceService($serviceType, $serviceSubType='', $excludeServiceKeys=array())
static fixPermissions($path, $recursive=FALSE)
static generateRandomBytes($bytesToReturn)
die
Definition: index.php:6
static isAllowedHostHeaderValue($hostHeaderValue)
static hideIfDefaultLanguage($localizationConfiguration)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
static verifyFilenameAgainstDenyPattern($filename)
static remapArrayKeys(&$array, $mappingTable)
static copyDirectory($source, $destination)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static removeSingletonInstance($className, \TYPO3\CMS\Core\SingletonInterface $instance)
static hideIfNotTranslated($l18n_cfg_fieldValue)
static _GETset($inputGet, $key='')
static array2xml(array $array, $NSprefix='', $level=0, $docTag='phparray', $spaceInd=0, array $options=array(), array $stackData=array())
static read_png_gif($theFile, $output_png=FALSE)
static unQuoteFilenames($parameters, $unQuote=FALSE)
static resetSingletonInstances(array $newSingletonInstances)
static split_fileref($fileNameWithPath)
static addSlashesOnArray(array &$theArray)
static flushDirectory($directory, $keepOriginalDirectory=FALSE, $flushOpcodeCache=FALSE)
static resolveSheetDefInDS($dataStructArray, $sheet='sDEF')
static linkThisScript(array $getParams=array())
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
static gif_compress($theFile, $type)
static compileSelectedGetVarsFromArray($varList, array $getArray, $GPvarAlt=TRUE)
static createVersionNumberedFilename($file, $forceQueryString=FALSE)
static getUrl($url, $includeHeader=0, $requestHeaders=FALSE, &$report=NULL)
static buildUrl(array $urlParts)
static getBytesFromSizeMeasurement($measurement)
static storeHash($hash, $data, $ident, $lifetime=0)
static inArray(array $in_array, $item)
static upload_to_tempfile($uploadedFileName)
static xml2arrayProcess($string, $NSprefix='', $reportDocTag=FALSE)
static tempnam($filePrefix, $fileSuffix='')
$host
Definition: server.php:35
static generateRandomBytesMcrypt($bytesToGenerate)
static getHostname($requestHost=TRUE)
static splitCalc($string, $operators)
static presetApplicationContext(\TYPO3\CMS\Core\Core\ApplicationContext $applicationContext)
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=FALSE, $rawurlencodeParamName=FALSE)
static formatSize($sizeInBytes, $labels='')
debug($variable='', $name=' *variable *', $line=' *line *', $file=' *file *', $recursiveDepth=3, $debugLevel=E_DEBUG)
static array_merge(array $arr1, array $arr2)
static getFilesInDir($path, $extensionList='', $prependPath=FALSE, $order='', $excludePattern='')
static array_merge_recursive_overrule(array $arr0, array $arr1, $notAddKeys=FALSE, $includeEmptyValues=TRUE, $enableUnsetFeature=TRUE)
static fixed_lgd_cs($string, $chars, $appendString='...')
if(isset($ajaxID)) if(in_array( $ajaxID, $noUserAjaxIDs))
Re-apply pairs of single-quotes to the text.
Definition: ajax.php:40
static plainMailEncoded($email, $subject, $message, $headers='', $encoding='quoted-printable', $charset='', $dontEncodeHeader=FALSE)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static removeArrayEntryByValue(array $array, $cmpValue)
static revExplode($delimiter, $string, $count=0)
static checkInstanceClassName($className, $instance)
static generateRandomBytesFallback($bytesToReturn)
static xml2array($string, $NSprefix='', $reportDocTag=FALSE)
static getFileAbsFileName($filename, $onlyRelative=TRUE, $relToTYPO3_mainDir=FALSE)
static linkThisUrl($url, array $getParams=array())
static removePrefixPathFromList(array $fileArr, $prefixToRemove)
static findService($serviceType, $serviceSubType='', $excludeServiceKeys=array())
static xmlRecompileFromStructValArray(array $vals)
static encodeHeader($line, $enc='quoted-printable', $charset='utf-8')
static arrayDiffAssocRecursive(array $array1, array $array2)
static exec($command, &$output=NULL, &$returnValue=0)
static generateRandomBytesOpenSsl($bytesToGenerate)
static makeRedirectUrl($inUrl, $l=0, $index_script_url='')
static upload_copy_move($source, $destination)
static wrapJS($string, $linebreak=TRUE)
static keepItemsInArray(array $array, $keepItems, $getValueFunc=NULL)
static instantiateClass($className, $arguments)