[BUGFIX] Remove side effects from ErrorController tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Utility / GeneralUtility.php
old mode 100755 (executable)
new mode 100644 (file)
index 0ddaf9c..fc14c97
@@ -14,11 +14,17 @@ namespace TYPO3\CMS\Core\Utility;
  * The TYPO3 project - inspiring people to share!
  */
 
+use GuzzleHttp\Exception\RequestException;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
 use TYPO3\CMS\Core\Core\ApplicationContext;
 use TYPO3\CMS\Core\Core\ClassLoadingInformation;
+use TYPO3\CMS\Core\Http\RequestFactory;
+use TYPO3\CMS\Core\Log\LogLevel;
+use TYPO3\CMS\Core\Log\LogManager;
 use TYPO3\CMS\Core\Service\OpcodeCacheService;
 use TYPO3\CMS\Core\SingletonInterface;
-use TYPO3\CMS\Frontend\Page\PageRepository;
+use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
 
 /**
  * The legendary "t3lib_div" class - Miscellaneous functions for general purpose.
@@ -34,7 +40,8 @@ use TYPO3\CMS\Frontend\Page\PageRepository;
  */
 class GeneralUtility
 {
-    // Severity constants used by \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog()
+    // Severity constants used by \TYPO3\CMS\Core\Utility\GeneralUtility::devLog()
+    // @deprecated since TYPO3 CMS 9, will be removed in TYPO3 CMS 10.
     const SYSLOG_SEVERITY_INFO = 0;
     const SYSLOG_SEVERITY_NOTICE = 1;
     const SYSLOG_SEVERITY_WARNING = 2;
@@ -58,21 +65,21 @@ class GeneralUtility
      *
      * @var array<\TYPO3\CMS\Core\SingletonInterface>
      */
-    protected static $singletonInstances = array();
+    protected static $singletonInstances = [];
 
     /**
      * Instances returned by makeInstance, using the class names as array keys
      *
      * @var array<array><object>
      */
-    protected static $nonSingletonInstances = array();
+    protected static $nonSingletonInstances = [];
 
     /**
      * Cache for makeInstance with given class name and final class names to reduce number of self::getClassName() calls
      *
      * @var array Given class name => final class name
      */
-    protected static $finalClassNameCache = array();
+    protected static $finalClassNameCache = [];
 
     /**
      * The application context
@@ -86,12 +93,12 @@ class GeneralUtility
      *
      * @var array<string>
      */
-    protected static $idnaStringCache = array();
+    protected static $idnaStringCache = [];
 
     /**
      * IDNA converter
      *
-     * @var \idna_convert
+     * @var \Mso\IdnaConvert\IdnaConvert
      */
     protected static $idnaConverter = null;
 
@@ -100,13 +107,13 @@ class GeneralUtility
      * NOTICE: This is a duplicate of the SAME array in SystemEnvironmentBuilder
      * @var array
      */
-    protected static $supportedCgiServerApis = array(
+    protected static $supportedCgiServerApis = [
         'fpm-fcgi',
         'cgi',
         'isapi',
         'cgi-fcgi',
         'srv', // HHVM with fastcgi
-    );
+    ];
 
     /**
      * @var array
@@ -162,8 +169,8 @@ class GeneralUtility
      */
     public static function _GPmerged($parameter)
     {
-        $postParameter = isset($_POST[$parameter]) && is_array($_POST[$parameter]) ? $_POST[$parameter] : array();
-        $getParameter = isset($_GET[$parameter]) && is_array($_GET[$parameter]) ? $_GET[$parameter] : array();
+        $postParameter = isset($_POST[$parameter]) && is_array($_POST[$parameter]) ? $_POST[$parameter] : [];
+        $getParameter = isset($_GET[$parameter]) && is_array($_GET[$parameter]) ? $_GET[$parameter] : [];
         $mergedParameters = $getParameter;
         ArrayUtility::mergeRecursiveWithOverrule($mergedParameters, $postParameter);
         return $mergedParameters;
@@ -198,7 +205,7 @@ class GeneralUtility
      */
     public static function _POST($var = null)
     {
-        $value = $var === null ? $_POST : (empty($var) ? null : $_POST[$var]);
+        $value = $var === null ? $_POST : (empty($var) || !isset($_POST[$var]) ? null : $_POST[$var]);
         // This is there for backwards-compatibility, in order to avoid NULL
         if (isset($value) && !is_array($value)) {
             $value = (string)$value;
@@ -211,14 +218,13 @@ class GeneralUtility
      *
      * @param mixed $inputGet
      * @param string $key
-     * @return void
      */
     public static function _GETset($inputGet, $key = '')
     {
         if ($key != '') {
             if (strpos($key, '|') !== false) {
                 $pieces = explode('|', $key);
-                $newGet = array();
+                $newGet = [];
                 $pointer = &$newGet;
                 foreach ($pieces as $piece) {
                     $pointer = &$pointer[$piece];
@@ -238,26 +244,6 @@ class GeneralUtility
         }
     }
 
-    /**
-     * Wrapper for the RemoveXSS function.
-     * Removes potential XSS code from an input string.
-     *
-     * Using an external class by Travis Puderbaugh <kallahar@quickwired.com>
-     *
-     * @param string $string Input string
-     * @return string Input string with potential XSS code removed
-     */
-    public static function removeXSS($string)
-    {
-        return \RemoveXSS::process($string);
-    }
-
-    /*************************
-     *
-     * IMAGE FUNCTIONS
-     *
-     *************************/
-
     /*************************
      *
      * STRING FUNCTIONS
@@ -273,16 +259,15 @@ class GeneralUtility
      */
     public static function fixed_lgd_cs($string, $chars, $appendString = '...')
     {
-        if (is_object($GLOBALS['LANG'])) {
-            return $GLOBALS['LANG']->csConvObj->crop($GLOBALS['LANG']->charSet, $string, $chars, $appendString);
-        } elseif (is_object($GLOBALS['TSFE']) && is_object($GLOBALS['TSFE']->csConvObj)) {
-            $charSet = $GLOBALS['TSFE']->renderCharset != '' ? $GLOBALS['TSFE']->renderCharset : $GLOBALS['TSFE']->defaultCharSet;
-            return $GLOBALS['TSFE']->csConvObj->crop($charSet, $string, $chars, $appendString);
+        if ((int)$chars === 0 || mb_strlen($string, 'utf-8') <= abs($chars)) {
+            return $string;
+        }
+        if ($chars > 0) {
+            $string = mb_substr($string, 0, $chars, 'utf-8') . $appendString;
         } else {
-            // This case should not happen
-            $csConvObj = self::makeInstance(\TYPO3\CMS\Core\Charset\CharsetConverter::class);
-            return $csConvObj->crop('utf-8', $string, $chars, $appendString);
+            $string = $appendString . mb_substr($string, $chars, mb_strlen($string, 'utf-8'), 'utf-8');
         }
+        return $string;
     }
 
     /**
@@ -298,14 +283,14 @@ class GeneralUtility
         $list = trim($list);
         if ($list === '') {
             return false;
-        } elseif ($list === '*') {
+        }
+        if ($list === '*') {
             return true;
         }
         if (strpos($baseIP, ':') !== false && self::validIPv6($baseIP)) {
             return self::cmpIPv6($baseIP, $list);
-        } else {
-            return self::cmpIPv4($baseIP, $list);
         }
+        return self::cmpIPv4($baseIP, $list);
     }
 
     /**
@@ -447,7 +432,7 @@ class GeneralUtility
         // According to RFC lowercase-representation is recommended
         $address = strtolower($address);
         // Normalized representation has 39 characters (0000:0000:0000:0000:0000:0000:0000:0000)
-        if (strlen($address) == 39) {
+        if (strlen($address) === 39) {
             // Already in full expanded form
             return $address;
         }
@@ -459,7 +444,7 @@ class GeneralUtility
             $left = count($chunksLeft);
             $right = count($chunksRight);
             // Special case: leading zero-only blocks count to 1, should be 0
-            if ($left == 1 && strlen($chunksLeft[0]) == 0) {
+            if ($left === 1 && strlen($chunksLeft[0]) === 0) {
                 $left = 0;
             }
             $hiddenBlocks = 8 - ($left + $right);
@@ -469,7 +454,7 @@ class GeneralUtility
                 $hiddenPart .= '0000:';
                 $h++;
             }
-            if ($left == 0) {
+            if ($left === 0) {
                 $stageOneAddress = $hiddenPart . $chunks[1];
             } else {
                 $stageOneAddress = $chunks[0] . ':' . $hiddenPart . $chunks[1];
@@ -601,9 +586,8 @@ class GeneralUtility
                         if ($wildcardMatched) {
                             // Match found by recursive compare
                             return true;
-                        } else {
-                            $yes = false;
                         }
+                        $yes = false;
                     }
                 } elseif ($baseHostNameParts[$index] !== $val) {
                     // In case of no match
@@ -673,7 +657,7 @@ class GeneralUtility
     public static function expandList($list)
     {
         $items = explode(',', $list);
-        $list = array();
+        $list = [];
         foreach ($items as $item) {
             $range = explode('-', $item);
             if (isset($range[1])) {
@@ -693,19 +677,6 @@ class GeneralUtility
     }
 
     /**
-     * Returns TRUE if the current TYPO3 version (or compatibility version) is compatible to the input version
-     * Notice that this function compares branches, not versions (4.0.1 would be > 4.0.0 although they use the same compat_version)
-     *
-     * @param string $verNumberStr Minimum branch number required (format x.y / e.g. "4.0" NOT "4.0.0"!)
-     * @return bool Returns TRUE if this setup is compatible with the provided version number
-     * @todo Still needs a function to convert versions to branches
-     */
-    public static function compat_version($verNumberStr)
-    {
-        return VersionNumberUtility::convertVersionNumberToInteger(TYPO3_branch) >= VersionNumberUtility::convertVersionNumberToInteger($verNumberStr);
-    }
-
-    /**
      * Makes a positive integer hash out of the first 7 chars from the md5 hash of the input
      *
      * @param string $str String to md5-hash
@@ -732,14 +703,13 @@ class GeneralUtility
      * Returns a proper HMAC on a given input string and secret TYPO3 encryption key.
      *
      * @param string $input Input string to create HMAC from
-     * @param string $additionalSecret additionalSecret to prevent hmac beeing used in a different context
+     * @param string $additionalSecret additionalSecret to prevent hmac being used in a different context
      * @return string resulting (hexadecimal) HMAC currently with a length of 40 (HMAC-SHA-1)
      */
     public static function hmac($input, $additionalSecret = '')
     {
         $hashAlgorithm = 'sha1';
         $hashBlocksize = 64;
-        $hmac = '';
         $secret = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . $additionalSecret;
         if (extension_loaded('hash') && function_exists('hash_hmac') && function_exists('hash_algos') && in_array($hashAlgorithm, hash_algos())) {
             $hmac = hash_hmac($hashAlgorithm, $input, $secret);
@@ -787,7 +757,7 @@ class GeneralUtility
      */
     public static function split_fileref($fileNameWithPath)
     {
-        $reg = array();
+        $reg = [];
         if (preg_match('/(.*\\/)(.*)$/', $fileNameWithPath, $reg)) {
             $info['path'] = $reg[1];
             $info['file'] = $reg[2];
@@ -852,10 +822,10 @@ class GeneralUtility
      */
     public static function formatSize($sizeInBytes, $labels = '', $base = 0)
     {
-        $defaultFormats = array(
-            'iec' => array('base' => 1024, 'labels' => array(' ', ' Ki', ' Mi', ' Gi', ' Ti', ' Pi', ' Ei', ' Zi', ' Yi')),
-            'si' => array('base' => 1000, 'labels' => array(' ', ' k', ' M', ' G', ' T', ' P', ' E', ' Z', ' Y')),
-        );
+        $defaultFormats = [
+            'iec' => ['base' => 1024, 'labels' => [' ', ' Ki', ' Mi', ' Gi', ' Ti', ' Pi', ' Ei', ' Zi', ' Yi']],
+            'si' => ['base' => 1000, 'labels' => [' ', ' k', ' M', ' G', ' T', ' P', ' E', ' Z', ' Y']],
+        ];
         // Set labels and base:
         if (empty($labels)) {
             $labels = 'iec';
@@ -892,18 +862,6 @@ class GeneralUtility
     }
 
     /**
-     * Returns microtime input to milliseconds
-     *
-     * @param string $microtime Microtime
-     * @return int Microtime input string converted to an integer (milliseconds)
-     */
-    public static function convertMicrotime($microtime)
-    {
-        $parts = explode(' ', $microtime);
-        return round(($parts[0] + $parts[1]) * 1000);
-    }
-
-    /**
      * This splits a string by the chars in $operators (typical /+-*) and returns an array with them in
      *
      * @param string $string Input string, eg "123 + 456 / 789 - 4
@@ -913,12 +871,12 @@ class GeneralUtility
      */
     public static function splitCalc($string, $operators)
     {
-        $res = array();
+        $res = [];
         $sign = '+';
         while ($string) {
             $valueLen = strcspn($string, $operators);
             $value = substr($string, 0, $valueLen);
-            $res[] = array($sign, trim($value));
+            $res[] = [$sign, trim($value)];
             $sign = substr($string, $valueLen, 1);
             $string = substr($string, $valueLen + 1);
         }
@@ -927,60 +885,6 @@ class GeneralUtility
     }
 
     /**
-     * Re-converts HTML entities if they have been converted by htmlspecialchars()
-     * Note: Use htmlspecialchars($str, ENT_COMPAT, 'UTF-8', FALSE) to avoid double encoding.
-     *       This makes the call to this method obsolete.
-     *
-     * @param string $str String which contains eg. "&amp;amp;" which should stay "&amp;". Or "&amp;#1234;" to "&#1234;". Or "&amp;#x1b;" to "&#x1b;
-     * @return string Converted result.
-     *
-     */
-    public static function deHSCentities($str)
-    {
-        return preg_replace('/&amp;([#[:alnum:]]*;)/', '&\\1', $str);
-    }
-
-    /**
-     * This function is used to escape any ' -characters when transferring text to JavaScript!
-     *
-     * @param string $string String to escape
-     * @param bool $extended If set, also backslashes are escaped.
-     * @param string $char The character to escape, default is ' (single-quote)
-     * @return string Processed input string
-     */
-    public static function slashJS($string, $extended = false, $char = '\'')
-    {
-        if ($extended) {
-            $string = str_replace('\\', '\\\\', $string);
-        }
-        return str_replace($char, '\\' . $char, $string);
-    }
-
-    /**
-     * Version of rawurlencode() where all spaces (%20) are re-converted to space-characters.
-     * Useful when passing text to JavaScript where you simply url-encode it to get around problems with syntax-errors, linebreaks etc.
-     *
-     * @param string $str String to raw-url-encode with spaces preserved
-     * @return string Rawurlencoded result of input string, but with all %20 (space chars) converted to real spaces.
-     */
-    public static function rawUrlEncodeJS($str)
-    {
-        return str_replace('%20', ' ', rawurlencode($str));
-    }
-
-    /**
-     * rawurlencode which preserves "/" chars
-     * Useful when file paths should keep the "/" chars, but have all other special chars encoded.
-     *
-     * @param string $str Input string
-     * @return string Output string
-     */
-    public static function rawUrlEncodeFP($str)
-    {
-        return str_replace('%2F', '/', rawurlencode($str));
-    }
-
-    /**
      * Checking syntax of input email address
      *
      * http://tools.ietf.org/html/rfc3696
@@ -1012,147 +916,13 @@ class GeneralUtility
         $domain = substr($email, $atPosition + 1);
         $user = substr($email, 0, $atPosition);
         if (!preg_match('/^[a-z0-9.\\-]*$/i', $domain)) {
-            $domain = self::idnaEncode($domain);
-        }
-        return filter_var($user . '@' . $domain, FILTER_VALIDATE_EMAIL) !== false;
-    }
-
-    /**
-     * Converts string to uppercase
-     * The function converts all Latin characters (a-z, but no accents, etc) to
-     * uppercase. It is safe for all supported character sets (incl. utf-8).
-     * Unlike strtoupper() it does not honour the locale.
-     *
-     * @param string $str Input string
-     * @return string Uppercase String
-     */
-    public static function strtoupper($str)
-    {
-        return strtr((string)$str, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
-    }
-
-    /**
-     * Converts string to lowercase
-     * The function converts all Latin characters (A-Z, but no accents, etc) to
-     * lowercase. It is safe for all supported character sets (incl. utf-8).
-     * Unlike strtolower() it does not honour the locale.
-     *
-     * @param string $str Input string
-     * @return string Lowercase String
-     */
-    public static function strtolower($str)
-    {
-        return strtr((string)$str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
-    }
-
-    /**
-     * Returns a string of highly randomized bytes (over the full 8-bit range).
-     *
-     * Note: Returned values are not guaranteed to be crypto-safe,
-     * most likely they are not, depending on the used retrieval method.
-     *
-     * @param int $bytesToReturn Number of characters (bytes) to return
-     * @return string Random Bytes
-     * @see http://bugs.php.net/bug.php?id=52523
-     * @see http://www.php-security.org/2010/05/09/mops-submission-04-generating-unpredictable-session-ids-and-hashes/index.html
-     */
-    public static function generateRandomBytes($bytesToReturn)
-    {
-        // Cache 4k of the generated bytestream.
-        static $bytes = '';
-        $bytesToGenerate = max(4096, $bytesToReturn);
-        // if we have not enough random bytes cached, we generate new ones
-        if (!isset($bytes[$bytesToReturn - 1])) {
-            if (TYPO3_OS === 'WIN') {
-                // Openssl seems to be deadly slow on Windows, so try to use mcrypt
-                $bytes .= self::generateRandomBytesMcrypt($bytesToGenerate);
-            } else {
-                // Try to use native PHP functions first, precedence has openssl
-                $bytes .= self::generateRandomBytesOpenSsl($bytesToGenerate);
-                if (!isset($bytes[$bytesToReturn - 1])) {
-                    $bytes .= self::generateRandomBytesMcrypt($bytesToGenerate);
-                }
-                // If openssl and mcrypt failed, try /dev/urandom
-                if (!isset($bytes[$bytesToReturn - 1])) {
-                    $bytes .= self::generateRandomBytesUrandom($bytesToGenerate);
-                }
-            }
-            // Fall back if other random byte generation failed until now
-            if (!isset($bytes[$bytesToReturn - 1])) {
-                $bytes .= self::generateRandomBytesFallback($bytesToReturn);
+            try {
+                $domain = self::idnaEncode($domain);
+            } catch (\InvalidArgumentException $exception) {
+                return false;
             }
         }
-        // get first $bytesToReturn and remove it from the byte cache
-        $output = substr($bytes, 0, $bytesToReturn);
-        $bytes = substr($bytes, $bytesToReturn);
-        return $output;
-    }
-
-    /**
-     * Generate random bytes using openssl if available
-     *
-     * @param string $bytesToGenerate
-     * @return string
-     */
-    protected static function generateRandomBytesOpenSsl($bytesToGenerate)
-    {
-        if (!function_exists('openssl_random_pseudo_bytes')) {
-            return '';
-        }
-        $isStrong = null;
-        return (string)openssl_random_pseudo_bytes($bytesToGenerate, $isStrong);
-    }
-
-    /**
-     * Generate random bytes using mcrypt if available
-     *
-     * @param $bytesToGenerate
-     * @return string
-     */
-    protected static function generateRandomBytesMcrypt($bytesToGenerate)
-    {
-        if (!function_exists('mcrypt_create_iv')) {
-            return '';
-        }
-        return (string)(@mcrypt_create_iv($bytesToGenerate, MCRYPT_DEV_URANDOM));
-    }
-
-    /**
-     * Read random bytes from /dev/urandom if it is accessible
-     *
-     * @param $bytesToGenerate
-     * @return string
-     */
-    protected static function generateRandomBytesUrandom($bytesToGenerate)
-    {
-        $bytes = '';
-        $fh = @fopen('/dev/urandom', 'rb');
-        if ($fh) {
-            // PHP only performs buffered reads, so in reality it will always read
-            // at least 4096 bytes. Thus, it costs nothing extra to read and store
-            // that much so as to speed any additional invocations.
-            $bytes = fread($fh, $bytesToGenerate);
-            fclose($fh);
-        }
-        return $bytes;
-    }
-
-    /**
-     * Generate pseudo random bytes as last resort
-     *
-     * @param $bytesToReturn
-     * @return string
-     */
-    protected static function generateRandomBytesFallback($bytesToReturn)
-    {
-        $bytes = '';
-        // We initialize with somewhat random.
-        $randomState = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] . base_convert(memory_get_usage() % pow(10, 6), 10, 2) . microtime() . StringUtility::getUniqueId() . getmypid();
-        while (!isset($bytes[$bytesToReturn - 1])) {
-            $randomState = sha1(microtime() . mt_rand() . $randomState);
-            $bytes .= sha1(mt_rand() . $randomState, true);
-        }
-        return $bytes;
+        return filter_var($user . '@' . $domain, FILTER_VALIDATE_EMAIL) !== false;
     }
 
     /**
@@ -1165,24 +935,12 @@ class GeneralUtility
     {
         if (isset(self::$idnaStringCache[$value])) {
             return self::$idnaStringCache[$value];
-        } else {
-            if (!self::$idnaConverter) {
-                self::$idnaConverter = new \idna_convert(array('idn_version' => 2008));
-            }
-            self::$idnaStringCache[$value] = self::$idnaConverter->encode($value);
-            return self::$idnaStringCache[$value];
         }
-    }
-
-    /**
-     * Returns a hex representation of a random byte string.
-     *
-     * @param int $count Number of hex characters to return
-     * @return string Random Bytes
-     */
-    public static function getRandomHexString($count)
-    {
-        return substr(bin2hex(self::generateRandomBytes((int)(($count + 1) / 2))), 0, $count);
+        if (!self::$idnaConverter) {
+            self::$idnaConverter = new \Mso\IdnaConvert\IdnaConvert(['idn_version' => 2008]);
+        }
+        self::$idnaStringCache[$value] = self::$idnaConverter->encode($value);
+        return self::$idnaStringCache[$value];
     }
 
     /**
@@ -1194,8 +952,7 @@ class GeneralUtility
      */
     public static function underscoredToUpperCamelCase($string)
     {
-        $upperCamelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', self::strtolower($string))));
-        return $upperCamelCase;
+        return str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($string))));
     }
 
     /**
@@ -1207,9 +964,7 @@ class GeneralUtility
      */
     public static function underscoredToLowerCamelCase($string)
     {
-        $upperCamelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', self::strtolower($string))));
-        $lowerCamelCase = self::lcfirst($upperCamelCase);
-        return $lowerCamelCase;
+        return lcfirst(str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($string)))));
     }
 
     /**
@@ -1221,19 +976,8 @@ class GeneralUtility
      */
     public static function camelCaseToLowerCaseUnderscored($string)
     {
-        return self::strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $string));
-    }
-
-    /**
-     * Converts the first char of a string to lowercase if it is a latin character (A-Z).
-     * Example: Converts "Hello World" to "hello World"
-     *
-     * @param string $string The string to be used to lowercase the first character
-     * @return string The string with the first character as lowercase
-     */
-    public static function lcfirst($string)
-    {
-        return self::strtolower($string[0]) . substr($string, 1);
+        $value = preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $string);
+        return mb_strtolower($value, 'utf-8');
     }
 
     /**
@@ -1279,7 +1023,11 @@ class GeneralUtility
             return false;
         }
         if (isset($parsedUrl['host']) && !preg_match('/^[a-z0-9.\\-]*$/i', $parsedUrl['host'])) {
-            $parsedUrl['host'] = self::idnaEncode($parsedUrl['host']);
+            try {
+                $parsedUrl['host'] = self::idnaEncode($parsedUrl['host']);
+            } catch (\InvalidArgumentException $exception) {
+                return false;
+            }
         }
         return filter_var(HttpUtility::buildUrl($parsedUrl), FILTER_VALIDATE_URL) !== false;
     }
@@ -1291,7 +1039,7 @@ class GeneralUtility
      *************************/
 
     /**
-     * Explodes a $string delimited by $delim and casts each item in the array to (int).
+     * Explodes a $string delimited by $delimiter and casts each item in the array to (int).
      * Corresponds to \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(), but with conversion to integers for all values.
      *
      * @param string $delimiter Delimiter string to explode with
@@ -1343,17 +1091,16 @@ class GeneralUtility
         if ($count === 2) {
             $position = strrpos($string, strrev($delimiter));
             if ($position !== false) {
-                return array(substr($string, 0, $position), substr($string, $position + strlen($delimiter)));
-            } else {
-                return array($string);
+                return [substr($string, 0, $position), substr($string, $position + strlen($delimiter))];
             }
-        } elseif ($count <= 1) {
-            return array($string);
-        } else {
-            $explodedValues = explode($delimiter, strrev($string), $count);
-            $explodedValues = array_map('strrev', $explodedValues);
-            return array_reverse($explodedValues);
+            return [$string];
+        }
+        if ($count <= 1) {
+            return [$string];
         }
+        $explodedValues = explode($delimiter, strrev($string), $count);
+        $explodedValues = array_map('strrev', $explodedValues);
+        return array_reverse($explodedValues);
     }
 
     /**
@@ -1372,7 +1119,7 @@ class GeneralUtility
     {
         $result = explode($delim, $string);
         if ($removeEmptyValues) {
-            $temp = array();
+            $temp = [];
             foreach ($result as $value) {
                 if (trim($value) !== '') {
                     $temp[] = $value;
@@ -1426,7 +1173,7 @@ class GeneralUtility
      */
     public static function explodeUrl2Array($string, $multidim = false)
     {
-        $output = array();
+        $output = [];
         if ($multidim) {
             parse_str($string, $output);
         } else {
@@ -1453,7 +1200,7 @@ class GeneralUtility
     public static function compileSelectedGetVarsFromArray($varList, array $getArray, $GPvarAlt = true)
     {
         $keys = self::trimExplode(',', $varList, true);
-        $outArr = array();
+        $outArr = [];
         foreach ($keys as $v) {
             if (isset($getArray[$v])) {
                 $outArr[$v] = $getArray[$v];
@@ -1465,24 +1212,6 @@ class GeneralUtility
     }
 
     /**
-     * Takes a row and returns a CSV string of the values with $delim (default is ,) and $quote (default is ") as separator chars.
-     *
-     * @param array $row Input array of values
-     * @param string $delim Delimited, default is comma
-     * @param string $quote Quote-character to wrap around the values.
-     * @return string A single line of CSV
-     */
-    public static function csvValues(array $row, $delim = ',', $quote = '"')
-    {
-        $out = array();
-        foreach ($row as $value) {
-            $out[] = str_replace($quote, $quote . $quote, $value);
-        }
-        $str = $quote . implode(($quote . $delim . $quote), $out) . $quote;
-        return $str;
-    }
-
-    /**
      * Removes dots "." from end of a key identifier of TypoScript styled array.
      * array('key.' => array('property.' => 'value')) --> array('key' => array('property' => 'value'))
      *
@@ -1491,7 +1220,7 @@ class GeneralUtility
      */
     public static function removeDotsFromTS(array $ts)
     {
-        $out = array();
+        $out = [];
         foreach ($ts as $key => $value) {
             if (is_array($value)) {
                 $key = rtrim($key, '.');
@@ -1522,10 +1251,10 @@ class GeneralUtility
         // Attribute name is stored here
         $name = '';
         $valuemode = false;
-        $attributes = array();
+        $attributes = [];
         foreach ($components as $key => $val) {
             // 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
-            if ($val != '=') {
+            if ($val !== '=') {
                 if ($valuemode) {
                     if ($name) {
                         $attributes[$name] = $val;
@@ -1557,7 +1286,7 @@ class GeneralUtility
         $tag_tmp = trim(preg_replace('/^<[^[:space:]]*/', '', trim($tag)));
         // Removes any > in the end of the string
         $tag_tmp = trim(rtrim($tag_tmp, '>'));
-        $value = array();
+        $value = [];
         // Compared with empty string instead , 030102
         while ($tag_tmp !== '') {
             $firstChar = $tag_tmp[0];
@@ -1591,7 +1320,7 @@ class GeneralUtility
     public static function implodeAttributes(array $arr, $xhtmlSafe = false, $dontOmitBlankAttribs = false)
     {
         if ($xhtmlSafe) {
-            $newArr = array();
+            $newArr = [];
             foreach ($arr as $p => $v) {
                 if (!isset($newArr[strtolower($p)])) {
                     $newArr[strtolower($p)] = htmlspecialchars($v);
@@ -1599,7 +1328,7 @@ class GeneralUtility
             }
             $arr = $newArr;
         }
-        $list = array();
+        $list = [];
         foreach ($arr as $p => $v) {
             if ((string)$v !== '' || $dontOmitBlankAttribs) {
                 $list[] = $p . '="' . $v . '"';
@@ -1614,28 +1343,25 @@ class GeneralUtility
      * This is nice for indenting JS code with PHP code on the same level.
      *
      * @param string $string JavaScript code
-     * @param bool $linebreak Wrap script element in line breaks? Default is TRUE.
      * @return string The wrapped JS code, ready to put into a XHTML page
      */
-    public static function wrapJS($string, $linebreak = true)
+    public static function wrapJS($string)
     {
         if (trim($string)) {
-            // <script wrapped in nl?
-            $cr = $linebreak ? LF : '';
             // remove nl from the beginning
-            $string = preg_replace('/^\\n+/', '', $string);
+            $string = ltrim($string, LF);
             // re-ident to one tab using the first line as reference
-            $match = array();
+            $match = [];
             if (preg_match('/^(\\t+)/', $string, $match)) {
                 $string = str_replace($match[1], TAB, $string);
             }
-            $string = $cr . '<script type="text/javascript">
+            return '<script type="text/javascript">
 /*<![CDATA[*/
 ' . $string . '
 /*]]>*/
-</script>' . $cr;
+</script>';
         }
-        return trim($string);
+        return '';
     }
 
     /**
@@ -1646,34 +1372,37 @@ class GeneralUtility
      * @param array $parserOptions Options that will be passed to PHP's xml_parser_set_option()
      * @return mixed The array with the parsed structure unless the XML parser returns with an error in which case the error message string is returned.
      */
-    public static function xml2tree($string, $depth = 999, $parserOptions = array())
+    public static function xml2tree($string, $depth = 999, $parserOptions = [])
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         $parser = xml_parser_create();
-        $vals = array();
-        $index = array();
+        $vals = [];
+        $index = [];
         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
         foreach ($parserOptions as $option => $value) {
             xml_parser_set_option($parser, $option, $value);
         }
         xml_parse_into_struct($parser, $string, $vals, $index);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         if (xml_get_error_code($parser)) {
             return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser));
         }
         xml_parser_free($parser);
-        $stack = array(array());
+        $stack = [[]];
         $stacktop = 0;
         $startPoint = 0;
-        $tagi = array();
+        $tagi = [];
         foreach ($vals as $key => $val) {
             $type = $val['type'];
             // open tag:
-            if ($type == 'open' || $type == 'complete') {
+            if ($type === 'open' || $type === 'complete') {
                 $stack[$stacktop++] = $tagi;
                 if ($depth == $stacktop) {
                     $startPoint = $key;
                 }
-                $tagi = array('tag' => $val['tag']);
+                $tagi = ['tag' => $val['tag']];
                 if (isset($val['attributes'])) {
                     $tagi['attrs'] = $val['attributes'];
                 }
@@ -1682,7 +1411,7 @@ class GeneralUtility
                 }
             }
             // finish tag:
-            if ($type == 'complete' || $type == 'close') {
+            if ($type === 'complete' || $type === 'close') {
                 $oldtagi = $tagi;
                 $tagi = $stack[--$stacktop];
                 $oldtag = $oldtagi['tag'];
@@ -1699,7 +1428,7 @@ class GeneralUtility
                 unset($oldtagi);
             }
             // cdata
-            if ($type == 'cdata') {
+            if ($type === 'cdata') {
                 $tagi['values'][] = $val['value'];
             }
         }
@@ -1707,26 +1436,6 @@ class GeneralUtility
     }
 
     /**
-     * Turns PHP array into XML. See array2xml()
-     *
-     * @param array $array The input PHP array with any kind of data; text, binary, integers. Not objects though.
-     * @param string $docTag Alternative document tag. Default is "phparray".
-     * @param array $options Options for the compilation. See array2xml() for description.
-     * @param string $charset Forced charset to prologue
-     * @return string An XML string made from the input content in the array.
-     * @see xml2array(),array2xml()
-     */
-    public static function array2xml_cs(array $array, $docTag = 'phparray', array $options = array(), $charset = '')
-    {
-        // Set default charset unless explicitly specified
-        $charset = $charset ?: 'utf-8';
-        // Return XML:
-        return '<?xml version="1.0" encoding="' . htmlspecialchars($charset) . '" standalone="yes" ?>' . LF . self::array2xml($array, '', 0, $docTag, 0, $options);
-    }
-
-    /**
-     * Deprecated to call directly (unless you are aware of using XML prologues)! Use "array2xml_cs" instead (which adds an XML-prologue)
-     *
      * Converts a PHP array into an XML string.
      * The XML output is optimized for readability since associative keys are used as tag names.
      * This also means that only alphanumeric characters are allowed in the tag names AND only keys NOT starting with numbers (so watch your usage of keys!). However there are options you can set to avoid this problem.
@@ -1746,7 +1455,7 @@ class GeneralUtility
      * @return string An XML string made from the input content in the array.
      * @see xml2array()
      */
-    public static function array2xml(array $array, $NSprefix = '', $level = 0, $docTag = 'phparray', $spaceInd = 0, array $options = array(), array $stackData = array())
+    public static function array2xml(array $array, $NSprefix = '', $level = 0, $docTag = 'phparray', $spaceInd = 0, array $options = [], array $stackData = [])
     {
         // 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
         $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);
@@ -1807,11 +1516,11 @@ class GeneralUtility
                 if (empty($v)) {
                     $content = '';
                 } else {
-                    $content = $nl . self::array2xml($v, $NSprefix, ($level + 1), '', $spaceInd, $subOptions, array(
+                    $content = $nl . self::array2xml($v, $NSprefix, ($level + 1), '', $spaceInd, $subOptions, [
                             'parentTagName' => $tagName,
                             'grandParentTagName' => $stackData['parentTagName'],
                             'path' => ($clearStackPath ? '' : $stackData['path'] . '/' . $tagName)
-                        )) . ($spaceInd >= 0 ? str_pad('', ($level + 1) * $indentN, $indentChar) : '');
+                        ]) . ($spaceInd >= 0 ? str_pad('', ($level + 1) * $indentN, $indentChar) : '');
                 }
                 // Do not set "type = array". Makes prettier XML but means that empty arrays are not restored with xml2array
                 if ((int)$options['disableTypeAttrib'] != 2) {
@@ -1830,7 +1539,7 @@ class GeneralUtility
                     // Otherwise, just htmlspecialchar the stuff:
                     $content = htmlspecialchars($v);
                     $dType = gettype($v);
-                    if ($dType == 'string') {
+                    if ($dType === 'string') {
                         if ($options['useCDATA'] && $content != $v) {
                             $content = '<![CDATA[' . $v . ']]>';
                         }
@@ -1865,19 +1574,13 @@ class GeneralUtility
      */
     public static function xml2array($string, $NSprefix = '', $reportDocTag = false)
     {
-        static $firstLevelCache = array();
+        static $firstLevelCache = [];
         $identifier = md5($string . $NSprefix . ($reportDocTag ? '1' : '0'));
         // Look up in first level cache
         if (!empty($firstLevelCache[$identifier])) {
             $array = $firstLevelCache[$identifier];
         } else {
-            // Look up in second level cache
-            // @todo: Is this cache really required? It basically substitutes a little cpu work with a db query?
-            $array = PageRepository::getHash($identifier, 0);
-            if (!is_array($array)) {
-                $array = self::xml2arrayProcess($string, $NSprefix, $reportDocTag);
-                PageRepository::storeHash($identifier, $array, 'ident_xml2array');
-            }
+            $array = self::xml2arrayProcess(trim($string), $NSprefix, $reportDocTag);
             // Store content in first level cache
             $firstLevelCache[$identifier] = $array;
         }
@@ -1896,29 +1599,32 @@ class GeneralUtility
      */
     protected static function xml2arrayProcess($string, $NSprefix = '', $reportDocTag = false)
     {
+        // Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
+        $previousValueOfEntityLoader = libxml_disable_entity_loader(true);
         // Create parser:
         $parser = xml_parser_create();
-        $vals = array();
-        $index = array();
+        $vals = [];
+        $index = [];
         xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
         xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0);
         // Default output charset is UTF-8, only ASCII, ISO-8859-1 and UTF-8 are supported!!!
-        $match = array();
+        $match = [];
         preg_match('/^[[:space:]]*<\\?xml[^>]*encoding[[:space:]]*=[[:space:]]*"([^"]*)"/', substr($string, 0, 200), $match);
         $theCharset = $match[1] ?: 'utf-8';
         // us-ascii / utf-8 / iso-8859-1
         xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, $theCharset);
         // Parse content:
         xml_parse_into_struct($parser, $string, $vals, $index);
+        libxml_disable_entity_loader($previousValueOfEntityLoader);
         // If error, return error message:
         if (xml_get_error_code($parser)) {
             return 'Line ' . xml_get_current_line_number($parser) . ': ' . xml_error_string(xml_get_error_code($parser));
         }
         xml_parser_free($parser);
         // Init vars:
-        $stack = array(array());
+        $stack = [[]];
         $stacktop = 0;
-        $current = array();
+        $current = [];
         $tagName = '';
         $documentTag = '';
         // Traverse the parsed XML structure:
@@ -1935,7 +1641,7 @@ class GeneralUtility
             // Closing tag.
             $tagName = $tagName[0] === 'n' && MathUtility::canBeInterpretedAsInteger($testNtag) ? (int)$testNtag : $tagName;
             // Test for alternative index value:
-            if ((string)$val['attributes']['index'] !== '') {
+            if ((string)($val['attributes']['index'] ?? '') !== '') {
                 $tagName = $val['attributes']['index'];
             }
             // Setting tag-values, manage stack:
@@ -1943,9 +1649,9 @@ class GeneralUtility
                 case 'open':
                     // If open tag it means there is an array stored in sub-elements. Therefore increase the stackpointer and reset the accumulation array:
                     // Setting blank place holder
-                    $current[$tagName] = array();
+                    $current[$tagName] = [];
                     $stack[$stacktop++] = $current;
-                    $current = array();
+                    $current = [];
                     break;
                 case 'close':
                     // If the tag is "close" then it is an array which is closing and we decrease the stack pointer.
@@ -1958,18 +1664,18 @@ class GeneralUtility
                     break;
                 case 'complete':
                     // If "complete", then it's a value. If the attribute "base64" is set, then decode the value, otherwise just set it.
-                    if ($val['attributes']['base64']) {
+                    if (!empty($val['attributes']['base64'])) {
                         $current[$tagName] = base64_decode($val['value']);
                     } else {
                         // Had to cast it as a string - otherwise it would be evaluate FALSE if tested with isset()!!
-                        $current[$tagName] = (string)$val['value'];
+                        $current[$tagName] = (string)($val['value'] ?? '');
                         // Cast type:
-                        switch ((string)$val['attributes']['type']) {
+                        switch ((string)($val['attributes']['type'] ?? '')) {
                             case 'integer':
                                 $current[$tagName] = (int)$current[$tagName];
                                 break;
                             case 'double':
-                                $current[$tagName] = (double) $current[$tagName];
+                                $current[$tagName] = (double)$current[$tagName];
                                 break;
                             case 'boolean':
                                 $current[$tagName] = (bool)$current[$tagName];
@@ -1979,7 +1685,7 @@ class GeneralUtility
                                 break;
                             case 'array':
                                 // 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...
-                                $current[$tagName] = array();
+                                $current[$tagName] = [];
                                 break;
                         }
                     }
@@ -2005,14 +1711,14 @@ class GeneralUtility
         foreach ($vals as $val) {
             $type = $val['type'];
             // Open tag:
-            if ($type == 'open' || $type == 'complete') {
+            if ($type === 'open' || $type === 'complete') {
                 $XMLcontent .= '<' . $val['tag'];
                 if (isset($val['attributes'])) {
                     foreach ($val['attributes'] as $k => $v) {
                         $XMLcontent .= ' ' . $k . '="' . htmlspecialchars($v) . '"';
                     }
                 }
-                if ($type == 'complete') {
+                if ($type === 'complete') {
                     if (isset($val['value'])) {
                         $XMLcontent .= '>' . htmlspecialchars($val['value']) . '</' . $val['tag'] . '>';
                     } else {
@@ -2021,16 +1727,16 @@ class GeneralUtility
                 } else {
                     $XMLcontent .= '>';
                 }
-                if ($type == 'open' && isset($val['value'])) {
+                if ($type === 'open' && isset($val['value'])) {
                     $XMLcontent .= htmlspecialchars($val['value']);
                 }
             }
             // Finish tag:
-            if ($type == 'close') {
+            if ($type === 'close') {
                 $XMLcontent .= '</' . $val['tag'] . '>';
             }
             // Cdata
-            if ($type == 'cdata') {
+            if ($type === 'cdata') {
                 $XMLcontent .= htmlspecialchars($val['value']);
             }
         }
@@ -2038,20 +1744,6 @@ class GeneralUtility
     }
 
     /**
-     * Extracts the attributes (typically encoding and version) of an XML prologue (header).
-     *
-     * @param string $xmlData XML data
-     * @return array Attributes of the xml prologue (header)
-     */
-    public static function xmlGetHeaderAttribs($xmlData)
-    {
-        $match = array();
-        if (preg_match('/^\\s*<\\?xml([^>]*)\\?\\>/', $xmlData, $match)) {
-            return self::get_tag_attributes($match[1]);
-        }
-    }
-
-    /**
      * Minifies JavaScript
      *
      * @param string $script Script to minify
@@ -2060,21 +1752,19 @@ class GeneralUtility
      */
     public static function minifyJavaScript($script, &$error = '')
     {
-        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'])) {
-            $fakeThis = false;
-            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'] as $hookMethod) {
-                try {
-                    $parameters = array('script' => $script);
-                    $script = static::callUserFunction($hookMethod, $parameters, $fakeThis);
-                } catch (\Exception $e) {
-                    $errorMessage = 'Error minifying java script: ' . $e->getMessage();
-                    $error .= $errorMessage;
-                    static::devLog($errorMessage, \TYPO3\CMS\Core\Utility\GeneralUtility::class, 2, array(
-                        'JavaScript' => $script,
-                        'Stack trace' => $e->getTrace(),
-                        'hook' => $hookMethod
-                    ));
-                }
+        $fakeThis = false;
+        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'] ?? [] as $hookMethod) {
+            try {
+                $parameters = ['script' => $script];
+                $script = static::callUserFunction($hookMethod, $parameters, $fakeThis);
+            } catch (\Exception $e) {
+                $errorMessage = 'Error minifying java script: ' . $e->getMessage();
+                $error .= $errorMessage;
+                static::getLogger()->warning($errorMessage, [
+                    'JavaScript' => $script,
+                    'hook' => $hookMethod,
+                    'exception' => $e,
+                ]);
             }
         }
         return $script;
@@ -2087,7 +1777,7 @@ class GeneralUtility
      *************************/
     /**
      * Reads the file or url $url and returns the content
-     * If you are having trouble with proxys when reading URLs you can configure your way out of that with settings like $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] etc.
+     * If you are having trouble with proxies when reading URLs you can configure your way out of that with settings within $GLOBALS['TYPO3_CONF_VARS']['HTTP'].
      *
      * @param string $url File/URL to read
      * @param int $includeHeader Whether the HTTP header should be fetched or not. 0=disable, 1=fetch header+content, 2=fetch header only
@@ -2095,179 +1785,75 @@ class GeneralUtility
      * @param array $report Error code/message and, if $includeHeader is 1, response meta data (HTTP status and content type)
      * @return mixed The content from the resource given as input. FALSE if an error has occurred.
      */
-    public static function getUrl($url, $includeHeader = 0, $requestHeaders = false, &$report = null)
+    public static function getUrl($url, $includeHeader = 0, $requestHeaders = null, &$report = null)
     {
-        $content = false;
         if (isset($report)) {
             $report['error'] = 0;
             $report['message'] = '';
         }
-        // Use cURL for: http, https, ftp, ftps, sftp and scp
-        if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlUse'] == '1' && preg_match('/^(?:http|ftp)s?|s(?:ftp|cp):/', $url)) {
-            if (isset($report)) {
-                $report['lib'] = 'cURL';
-            }
-            // External URL without error checking.
-            if (!function_exists('curl_init') || !($ch = curl_init())) {
-                if (isset($report)) {
-                    $report['error'] = -1;
-                    $report['message'] = 'Couldn\'t initialize cURL.';
-                }
-                return false;
-            }
-
-            $followLocationSucceeded = @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
-
-            curl_setopt($ch, CURLOPT_URL, $url);
-            curl_setopt($ch, CURLOPT_HEADER, !$followLocationSucceeded || $includeHeader ? 1 : 0);
-            curl_setopt($ch, CURLOPT_NOBODY, $includeHeader == 2 ? 1 : 0);
-            curl_setopt($ch, CURLOPT_HTTPGET, $includeHeader == 2 ? 'HEAD' : 'GET');
-            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-            curl_setopt($ch, CURLOPT_FAILONERROR, 1);
-            curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, max(0, (int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['curlTimeout']));
-
+        // Looks like it's an external file, use Guzzle by default
+        if (preg_match('/^(?:http|ftp)s?|s(?:ftp|cp):/', $url)) {
+            /** @var RequestFactory $requestFactory */
+            $requestFactory = static::makeInstance(RequestFactory::class);
             if (is_array($requestHeaders)) {
-                curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders);
-            }
-            // (Proxy support implemented by Arco <arco@appeltaart.mine.nu>)
-            if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']) {
-                curl_setopt($ch, CURLOPT_PROXY, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyServer']);
-                if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyNTLM']) {
-                    curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
-                }
-                if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel']) {
-                    curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyTunnel']);
-                }
-                if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass']) {
-                    curl_setopt($ch, CURLOPT_PROXYUSERPWD, $GLOBALS['TYPO3_CONF_VARS']['SYS']['curlProxyUserPass']);
-                }
-            }
-            $content = curl_exec($ch);
-            $curlInfo = curl_getinfo($ch);
-
-            if (!$followLocationSucceeded) {
-                // Check if we need to do redirects
-                if ($curlInfo['http_code'] >= 300 && $curlInfo['http_code'] < 400) {
-                    $locationUrl = $curlInfo['redirect_url'];
-                    if (!$locationUrl) {
-                        // Some curllib versions do not return redirect_url. Examine headers.
-                        $locationUrl = self::getRedirectUrlFromHttpHeaders($content);
-                    }
-                    if ($locationUrl) {
-                        $content = self::getUrl($locationUrl, $includeHeader, $requestHeaders, $report);
-                        $followLocationSucceeded = true;
-                    } else {
-                        // Failure: we got a redirection status code but not the URL to redirect to.
-                        $content = false;
-                    }
-                }
-                if ($content && !$includeHeader) {
-                    $content = self::stripHttpHeaders($content);
-                }
+                $configuration = ['headers' => $requestHeaders];
+            } else {
+                $configuration = [];
             }
 
-            if (isset($report)) {
-                if (!$followLocationSucceeded && $curlInfo['http_code'] >= 300 && $curlInfo['http_code'] < 400) {
-                    $report['http_code'] = $curlInfo['http_code'];
-                    $report['content_type'] = $curlInfo['content_type'];
-                    $report['error'] = CURLE_GOT_NOTHING;
-                    $report['message'] = 'Expected "Location" header but got nothing.';
-                } elseif ($content === false) {
-                    $report['error'] = curl_errno($ch);
-                    $report['message'] = curl_error($ch);
-                } elseif ($includeHeader) {
-                    // Set only for $includeHeader to work exactly like PHP variant
-                    $report['http_code'] = $curlInfo['http_code'];
-                    $report['content_type'] = $curlInfo['content_type'];
-                }
-            }
-            curl_close($ch);
-        } elseif ($includeHeader) {
-            if (isset($report)) {
-                $report['lib'] = 'socket';
-            }
-            $parsedURL = parse_url($url);
-            if (!preg_match('/^https?/', $parsedURL['scheme'])) {
+            try {
                 if (isset($report)) {
-                    $report['error'] = -1;
-                    $report['message'] = 'Reading headers is not allowed for this protocol.';
+                    $report['lib'] = 'GuzzleHttp';
                 }
-                return false;
-            }
-            $port = (int)$parsedURL['port'];
-            if ($port < 1) {
-                if ($parsedURL['scheme'] == 'http') {
-                    $port = $port > 0 ? $port : 80;
-                    $scheme = '';
-                } else {
-                    $port = $port > 0 ? $port : 443;
-                    $scheme = 'ssl://';
-                }
-            }
-            $errno = 0;
-            $fp = @fsockopen(($scheme . $parsedURL['host']), $port, $errno, $errstr, 2.0);
-            if (!$fp || $errno > 0) {
+                $response = $requestFactory->request($url, 'GET', $configuration);
+            } catch (RequestException $exception) {
                 if (isset($report)) {
-                    $report['error'] = $errno ?: -1;
-                    $report['message'] = $errno ? ($errstr ?: 'Socket error.') : 'Socket initialization error.';
+                    $report['error'] = $exception->getCode() ?: 1518707554;
+                    $report['message'] = $exception->getMessage();
+                    $report['exception'] = $exception;
                 }
                 return false;
             }
-            $method = $includeHeader == 2 ? 'HEAD' : 'GET';
-            $msg = $method . ' ' . (isset($parsedURL['path']) ? $parsedURL['path'] : '/')
-                   . ($parsedURL['query'] ? '?' . $parsedURL['query'] : '') . ' HTTP/1.0' . CRLF
-                   . 'Host: ' . $parsedURL['host'] . CRLF
-                   . 'Connection: close' . CRLF;
-            if (is_array($requestHeaders)) {
-                $msg .= implode(CRLF, $requestHeaders) . CRLF;
-            }
-            $msg .= CRLF;
-            fputs($fp, $msg);
-            while (!feof($fp)) {
-                $line = fgets($fp, 2048);
-                if (isset($report)) {
-                    if (preg_match('|^HTTP/\\d\\.\\d +(\\d+)|', $line, $status)) {
-                        $report['http_code'] = $status[1];
-                    } elseif (preg_match('/^Content-Type: *(.*)/i', $line, $type)) {
-                        $report['content_type'] = $type[1];
-                    }
+
+            $content = '';
+
+            // Add the headers to the output
+            $includeHeader = (int)$includeHeader;
+            if ($includeHeader) {
+                $parsedURL = parse_url($url);
+                $method = $includeHeader === 2 ? 'HEAD' : 'GET';
+                $content = $method . ' ' . ($parsedURL['path'] ?? '/')
+                    . (!empty($parsedURL['query']) ? '?' . $parsedURL['query'] : '') . ' HTTP/1.0' . CRLF
+                    . 'Host: ' . $parsedURL['host'] . CRLF
+                    . 'Connection: close' . CRLF;
+                if (is_array($requestHeaders)) {
+                    $content .= implode(CRLF, $requestHeaders) . CRLF;
                 }
-                $content .= $line;
-                if (trim($line) === '') {
-                    // Stop at the first empty line (= end of header)
-                    break;
+                foreach ($response->getHeaders() as $headerName => $headerValues) {
+                    $content .= $headerName . ': ' . implode(', ', $headerValues) . CRLF;
                 }
+                // Headers are separated from the body with two CRLFs
+                $content .= CRLF;
             }
-            if ($includeHeader != 2) {
-                $content .= stream_get_contents($fp);
+            // If not just headers are requested, add the body
+            if ($includeHeader !== 2) {
+                $content .= $response->getBody()->getContents();
             }
-            fclose($fp);
-        } elseif (is_array($requestHeaders)) {
             if (isset($report)) {
-                $report['lib'] = 'file/context';
-            }
-            $parsedURL = parse_url($url);
-            if (!preg_match('/^https?/', $parsedURL['scheme'])) {
-                if (isset($report)) {
-                    $report['error'] = -1;
-                    $report['message'] = 'Sending request headers is not allowed for this protocol.';
+                $report['lib'] = 'http';
+                if ($response->getStatusCode() >= 300 && $response->getStatusCode() < 400) {
+                    $report['http_code'] = $response->getStatusCode();
+                    $report['content_type'] = $response->getHeader('Content-Type');
+                    $report['error'] = $response->getStatusCode();
+                    $report['message'] = $response->getReasonPhrase();
+                } elseif (!empty($content)) {
+                    $report['error'] = $response->getStatusCode();
+                    $report['message'] = $response->getReasonPhrase();
+                } elseif ($includeHeader) {
+                    // Set only for $includeHeader to work exactly like PHP variant
+                    $report['http_code'] = $response->getStatusCode();
+                    $report['content_type'] = $response->getHeader('Content-Type');
                 }
-                return false;
-            }
-            $ctx = stream_context_create(array(
-                'http' => array(
-                    'header' => implode(CRLF, $requestHeaders)
-                )
-            ));
-            $defaultCtx = stream_context_get_default();
-            if ($defaultCtx) {
-                $content = @file_get_contents($url);
-            } else {
-                $content = @file_get_contents($url, false, $ctx);
-            }
-            if ($content === false && isset($report)) {
-                $report['error'] = -1;
-                $report['message'] = 'Couldn\'t get URL: ' . (isset($http_response_header) ? implode(LF, $http_response_header) : $url);
             }
         } else {
             if (isset($report)) {
@@ -2276,54 +1862,13 @@ class GeneralUtility
             $content = @file_get_contents($url);
             if ($content === false && isset($report)) {
                 $report['error'] = -1;
-                $report['message'] = 'Couldn\'t get URL: ' . (isset($http_response_header) ? implode(LF, $http_response_header) : $url);
+                $report['message'] = 'Couldn\'t get URL: ' . $url;
             }
         }
         return $content;
     }
 
     /**
-     * Parses HTTP headers and returns the content of the "Location" header
-     * or the empty string if no such header found.
-     *
-     * @param string $content
-     * @return string
-     */
-    protected static function getRedirectUrlFromHttpHeaders($content)
-    {
-        $result = '';
-        $headers = explode("\r\n", $content);
-        foreach ($headers as $header) {
-            if ($header == '') {
-                break;
-            }
-            if (preg_match('/^\s*Location\s*:/i', $header)) {
-                list(, $result) = self::trimExplode(':', $header, false, 2);
-                if ($result) {
-                    $result = self::locationHeaderUrl($result);
-                }
-                break;
-            }
-        }
-        return $result;
-    }
-
-    /**
-     * Strips HTTP headers from the content.
-     *
-     * @param string $content
-     * @return string
-     */
-    protected static function stripHttpHeaders($content)
-    {
-        $headersEndPos = strpos($content, "\r\n\r\n");
-        if ($headersEndPos) {
-            $content = substr($content, $headersEndPos + 4);
-        }
-        return $content;
-    }
-
-    /**
      * Writes $content to the file $file
      *
      * @param string $file Filepath to write to
@@ -2366,17 +1911,13 @@ class GeneralUtility
         $result = false;
         // Make path absolute
         if (!static::isAbsPath($path)) {
-            $path = static::getFileAbsFileName($path, false);
+            $path = static::getFileAbsFileName($path);
         }
         if (static::isAllowedAbsPath($path)) {
             if (@is_file($path)) {
-                $targetPermissions = isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'])
-                    ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask']
-                    : '0644';
+                $targetPermissions = $GLOBALS['TYPO3_CONF_VARS']['SYS']['fileCreateMask'] ?? '0644';
             } elseif (@is_dir($path)) {
-                $targetPermissions = isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'])
-                    ? $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask']
-                    : '0755';
+                $targetPermissions = $GLOBALS['TYPO3_CONF_VARS']['SYS']['folderCreateMask'] ?? '0755';
             }
             if (!empty($targetPermissions)) {
                 // make sure it's always 4 digits
@@ -2397,20 +1938,22 @@ class GeneralUtility
             // Call recursive if recursive flag if set and $path is directory
             if ($recursive && @is_dir($path)) {
                 $handle = opendir($path);
-                while (($file = readdir($handle)) !== false) {
-                    $recursionResult = null;
-                    if ($file !== '.' && $file !== '..') {
-                        if (@is_file(($path . '/' . $file))) {
-                            $recursionResult = static::fixPermissions($path . '/' . $file);
-                        } elseif (@is_dir(($path . '/' . $file))) {
-                            $recursionResult = static::fixPermissions($path . '/' . $file, true);
-                        }
-                        if (isset($recursionResult) && !$recursionResult) {
-                            $result = false;
+                if (is_resource($handle)) {
+                    while (($file = readdir($handle)) !== false) {
+                        $recursionResult = null;
+                        if ($file !== '.' && $file !== '..') {
+                            if (@is_file(($path . '/' . $file))) {
+                                $recursionResult = static::fixPermissions($path . '/' . $file);
+                            } elseif (@is_dir(($path . '/' . $file))) {
+                                $recursionResult = static::fixPermissions($path . '/' . $file, true);
+                            }
+                            if (isset($recursionResult) && !$recursionResult) {
+                                $result = false;
+                            }
                         }
                     }
+                    closedir($handle);
                 }
-                closedir($handle);
             }
         }
         return $result;
@@ -2426,10 +1969,6 @@ class GeneralUtility
      */
     public static function writeFileToTypo3tempDir($filepath, $content)
     {
-        if (!defined('PATH_site')) {
-            return 'PATH_site constant was NOT defined!';
-        }
-
         // Parse filepath into directory and basename:
         $fI = pathinfo($filepath);
         $fI['dirname'] .= '/';
@@ -2448,24 +1987,24 @@ class GeneralUtility
         // Checking if the "subdir" is found:
         $subdir = substr($fI['dirname'], strlen($dirName));
         if ($subdir) {
-            if (preg_match('/^[[:alnum:]_]+\\/$/', $subdir) || preg_match('/^[[:alnum:]_]+\\/[[:alnum:]_]+\\/$/', $subdir)) {
+            if (preg_match('#^(?:[[:alnum:]_]+/)+$#', $subdir)) {
                 $dirName .= $subdir;
                 if (!@is_dir($dirName)) {
-                    static::mkdir_deep(PATH_site . 'typo3temp/', $subdir);
+                    static::mkdir_deep(PATH_site . 'typo3temp/' . $subdir);
                 }
             } else {
-                return 'Subdir, "' . $subdir . '", was NOT on the form "[[:alnum:]_]/" or  "[[:alnum:]_]/[[:alnum:]_]/"';
+                return 'Subdir, "' . $subdir . '", was NOT on the form "[[:alnum:]_]/+"';
             }
         }
         // Checking dir-name again (sub-dir might have been created):
         if (@is_dir($dirName)) {
-            if ($filepath == $dirName . $fI['basename']) {
+            if ($filepath === $dirName . $fI['basename']) {
                 static::writeFile($filepath, $content);
                 if (!@is_file($filepath)) {
                     return 'The file was not written to the disk. Please, check that you have write permissions to the typo3temp/ directory.';
                 }
             } else {
-                return 'Calculated filelocation didn\'t match input "' . $filepath . '".';
+                return 'Calculated file location didn\'t match input "' . $filepath . '".';
             }
         } else {
             return '"' . $dirName . '" is not a directory!';
@@ -2496,7 +2035,6 @@ class GeneralUtility
      *
      * @param string $directory Target directory to create. Must a have trailing slash
      * @param string $deepDirectory Directory to create. This second parameter
-     * @return void
      * @throws \InvalidArgumentException If $directory or $deepDirectory are not strings
      * @throws \RuntimeException If directory could not be created
      */
@@ -2509,8 +2047,12 @@ class GeneralUtility
             throw new \InvalidArgumentException('The specified directory is of type "' . gettype($deepDirectory) . '" but a string is expected.', 1303662956);
         }
         // Ensure there is only one slash
-        $fullPath = rtrim($directory, '/') . '/' . ltrim($deepDirectory, '/');
-        if ($fullPath !== '' && !is_dir($fullPath)) {
+        $fullPath = rtrim($directory, '/') . '/';
+        if ($deepDirectory !== '') {
+            trigger_error('Second argument $deepDirectory of GeneralUtility::mkdir_deep() will be removed in TYPO3 v10.0, use a combined string as first argument instead.', E_USER_DEPRECATED);
+            $fullPath .= ltrim($deepDirectory, '/');
+        }
+        if ($fullPath !== '/' && !is_dir($fullPath)) {
             $firstCreatedPath = static::createDirectoryPath($fullPath);
             if ($firstCreatedPath !== '') {
                 static::fixPermissions($firstCreatedPath, true);
@@ -2566,7 +2108,7 @@ class GeneralUtility
             if (!is_link($path) && is_dir($path)) {
                 if ($removeNonEmpty == true && ($handle = @opendir($path))) {
                     while ($OK && false !== ($file = readdir($handle))) {
-                        if ($file == '.' || $file == '..') {
+                        if ($file === '.' || $file === '..') {
                             continue;
                         }
                         $OK = static::rmdir($path . '/' . $file, $removeNonEmpty);
@@ -2585,6 +2127,10 @@ class GeneralUtility
             clearstatcache();
         } elseif (is_link($path)) {
             $OK = @unlink($path);
+            if (!$OK && TYPO3_OS === 'WIN') {
+                // Try to delete dead folder links on Windows systems
+                $OK = @rmdir($path);
+            }
             clearstatcache();
         }
         return $OK;
@@ -2608,7 +2154,7 @@ class GeneralUtility
             $temporaryDirectory = rtrim($directory, '/') . '.' . StringUtility::getUniqueId('remove') . '/';
             if (rename($directory, $temporaryDirectory)) {
                 if ($flushOpcodeCache) {
-                    GeneralUtility::makeInstance(OpcodeCacheService::class)->clearAllActive($directory);
+                    self::makeInstance(OpcodeCacheService::class)->clearAllActive($directory);
                 }
                 if ($keepOriginalDirectory) {
                     static::mkdir($directory);
@@ -2630,12 +2176,13 @@ class GeneralUtility
      */
     public static function get_dirs($path)
     {
+        $dirs = null;
         if ($path) {
             if (is_dir($path)) {
                 $dir = scandir($path);
-                $dirs = array();
+                $dirs = [];
                 foreach ($dir as $entry) {
-                    if (is_dir($path . '/' . $entry) && $entry != '..' && $entry != '.') {
+                    if (is_dir($path . '/' . $entry) && $entry !== '..' && $entry !== '.') {
                         $dirs[] = $entry;
                     }
                 }
@@ -2663,7 +2210,7 @@ class GeneralUtility
         $excludePattern = (string)$excludePattern;
         $path = rtrim($path, '/');
         if (!@is_dir($path)) {
-            return array();
+            return [];
         }
 
         $rawFileList = scandir($path);
@@ -2672,23 +2219,26 @@ class GeneralUtility
         }
 
         $pathPrefix = $path . '/';
-        $extensionList = ',' . $extensionList . ',';
-        $files = array();
+        $allowedFileExtensionArray = self::trimExplode(',', $extensionList);
+        $extensionList = ',' . str_replace(' ', '', $extensionList) . ',';
+        $files = [];
         foreach ($rawFileList as $entry) {
             $completePathToEntry = $pathPrefix . $entry;
             if (!@is_file($completePathToEntry)) {
                 continue;
             }
 
-            if (
-                ($extensionList === ',,' || stripos($extensionList, ',' . pathinfo($entry, PATHINFO_EXTENSION) . ',') !== false)
-                && ($excludePattern === '' || !preg_match(('/^' . $excludePattern . '$/'), $entry))
-            ) {
-                if ($order !== 'mtime') {
-                    $files[] = $entry;
-                } else {
-                    // Store the value in the key so we can do a fast asort later.
-                    $files[$entry] = filemtime($completePathToEntry);
+            foreach ($allowedFileExtensionArray as $allowedFileExtension) {
+                if (
+                    ($extensionList === ',,' || stripos($extensionList, ',' . substr($entry, strlen($allowedFileExtension) * -1, strlen($allowedFileExtension)) . ',') !== false)
+                    && ($excludePattern === '' || !preg_match(('/^' . $excludePattern . '$/'), $entry))
+                ) {
+                    if ($order !== 'mtime') {
+                        $files[] = $entry;
+                    } else {
+                        // Store the value in the key so we can do a fast asort later.
+                        $files[$entry] = filemtime($completePathToEntry);
+                    }
                 }
             }
         }
@@ -2700,7 +2250,7 @@ class GeneralUtility
         }
 
         $valuePathPrefix = $prependPath ? $pathPrefix : '';
-        $foundFiles = array();
+        $foundFiles = [];
         foreach ($files as $key => $value) {
             // Don't change this ever - extensions may depend on the fact that the hash is an md5 of the path! (import/export extension)
             $foundFiles[md5($pathPrefix . ${$valueName})] = $valuePathPrefix . ${$valueName};
@@ -2765,7 +2315,7 @@ class GeneralUtility
      */
     public static function fixWindowsFilePath($theFile)
     {
-        return str_replace(array('\\', '//'), '/', $theFile);
+        return str_replace(['\\', '//'], '/', $theFile);
     }
 
     /**
@@ -2781,7 +2331,7 @@ class GeneralUtility
             return $pathStr;
         }
         $parts = explode('/', $pathStr);
-        $output = array();
+        $output = [];
         $c = 0;
         foreach ($parts as $part) {
             if ($part === '..') {
@@ -2807,7 +2357,6 @@ class GeneralUtility
      *
      * @param string $path URL / path to prepend full URL addressing to.
      * @return string
-     * @throws \InvalidArgumentException
      */
     public static function locationHeaderUrl($path)
     {
@@ -2819,10 +2368,6 @@ class GeneralUtility
             // No scheme either
             $path = self::getIndpEnv('TYPO3_REQUEST_DIR') . $path;
         }
-        // Can be removed once minimum PHP requirement is at least 5.5.22 or 5.6.6
-        if (strpbrk($path, "\r\n") !== false) {
-            throw new \InvalidArgumentException('HTTP header injection attempt in "' . $path . '"', 1448194036);
-        }
         return $path;
     }
 
@@ -2853,7 +2398,7 @@ class GeneralUtility
      */
     public static function getBytesFromSizeMeasurement($measurement)
     {
-        $bytes = doubleval($measurement);
+        $bytes = (float)$measurement;
         if (stripos($measurement, 'G')) {
             $bytes *= 1024 * 1024 * 1024;
         } elseif (stripos($measurement, 'M')) {
@@ -2865,16 +2410,6 @@ class GeneralUtility
     }
 
     /**
-     * Retrieves the maximum path length that is valid in the current environment.
-     *
-     * @return int The maximum available path length
-     */
-    public static function getMaximumPathLength()
-    {
-        return PHP_MAXPATHLEN;
-    }
-
-    /**
      * Function for static version numbers on files, based on the filemtime
      *
      * This will make the filename automatically change when a file is
@@ -2896,7 +2431,7 @@ class GeneralUtility
         $path = self::resolveBackPath(self::dirname(PATH_thisScript) . '/' . $lookupFile[0]);
 
         $doNothing = false;
-        if (TYPO3_MODE == 'FE') {
+        if (TYPO3_MODE === 'FE') {
             $mode = strtolower($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['versionNumberInFilename']);
             if ($mode === 'embed') {
                 $mode = true;
@@ -2910,14 +2445,14 @@ class GeneralUtility
         } else {
             $mode = $GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['versionNumberInFilename'];
         }
-        if (!file_exists($path) || $doNothing) {
+        if ($doNothing || !file_exists($path)) {
             // File not found, return filename unaltered
             $fullName = $file;
         } else {
             if (!$mode) {
                 // If use of .htaccess rule is not configured,
                 // we use the default query-string method
-                if ($lookupFile[1]) {
+                if (!empty($lookupFile[1])) {
                     $separator = '&';
                 } else {
                     $separator = '?';
@@ -2950,7 +2485,7 @@ class GeneralUtility
      * @param array $getParams Array of GET parameters to include
      * @return string
      */
-    public static function linkThisScript(array $getParams = array())
+    public static function linkThisScript(array $getParams = [])
     {
         $parts = self::getIndpEnv('SCRIPT_NAME');
         $params = self::_GET();
@@ -2973,10 +2508,10 @@ class GeneralUtility
      * @param array $getParams Array of key/value pairs for get parameters to add/overrule with. Can be multidimensional.
      * @return string Output URL with added getParams.
      */
-    public static function linkThisUrl($url, array $getParams = array())
+    public static function linkThisUrl($url, array $getParams = [])
     {
         $parts = parse_url($url);
-        $getP = array();
+        $getP = [];
         if ($parts['query']) {
             parse_str($parts['query'], $getP);
         }
@@ -3065,7 +2600,7 @@ class GeneralUtility
                 break;
             case 'REQUEST_URI':
                 // Typical application of REQUEST_URI is return urls, forms submitting to itself etc. Example: returnUrl='.rawurlencode(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('REQUEST_URI'))
-                if ($GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar']) {
+                if (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar'])) {
                     // This is for URL rewriters that store the original URI in a server variable (eg ISAPI_Rewriter for IIS: HTTP_X_REWRITE_URL)
                     list($v, $n) = explode('|', $GLOBALS['TYPO3_CONF_VARS']['SYS']['requestURIvar']);
                     $retVal = $GLOBALS[$v][$n];
@@ -3126,7 +2661,7 @@ class GeneralUtility
                 break;
             case 'HTTP_HOST':
                 // if it is not set we're most likely on the cli
-                $retVal = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : null;
+                $retVal = $_SERVER['HTTP_HOST'] ?? null;
                 if (isset($_SERVER['REMOTE_ADDR']) && static::cmpIP($_SERVER['REMOTE_ADDR'], $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'])) {
                     $host = self::trimExplode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
                     // Choose which host in list to use
@@ -3166,7 +2701,6 @@ class GeneralUtility
             case 'REMOTE_HOST':
 
             case 'QUERY_STRING':
-                $retVal = '';
                 if (isset($_SERVER[$getEnvName])) {
                     $retVal = $_SERVER[$getEnvName];
                 }
@@ -3179,7 +2713,7 @@ class GeneralUtility
                 $SFN = self::getIndpEnv('SCRIPT_FILENAME');
                 $SN_A = explode('/', strrev(self::getIndpEnv('SCRIPT_NAME')));
                 $SFN_A = explode('/', strrev($SFN));
-                $acc = array();
+                $acc = [];
                 foreach ($SN_A as $kk => $vv) {
                     if ((string)$SFN_A[$kk] === (string)$vv) {
                         $acc[] = $vv;
@@ -3189,9 +2723,8 @@ class GeneralUtility
                 }
                 $commonEnd = strrev(implode('/', $acc));
                 if ((string)$commonEnd !== '') {
-                    $DR = substr($SFN, 0, -(strlen($commonEnd) + 1));
+                    $retVal = substr($SFN, 0, -(strlen($commonEnd) + 1));
                 }
-                $retVal = $DR;
                 break;
             case 'TYPO3_HOST_ONLY':
                 $httpHost = self::getIndpEnv('HTTP_HOST');
@@ -3224,7 +2757,7 @@ class GeneralUtility
                 } elseif (defined('PATH_thisScript') && defined('PATH_site')) {
                     $lPath = PathUtility::stripPathSitePrefix(dirname(PATH_thisScript)) . '/';
                     $siteUrl = substr($url, 0, -strlen($lPath));
-                    if (substr($siteUrl, -1) != '/') {
+                    if (substr($siteUrl, -1) !== '/') {
                         $siteUrl .= '/';
                     }
                     $retVal = $siteUrl;
@@ -3238,7 +2771,7 @@ class GeneralUtility
                 break;
             case 'TYPO3_SSL':
                 $proxySSL = trim($GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxySSL']);
-                if ($proxySSL == '*') {
+                if ($proxySSL === '*') {
                     $proxySSL = $GLOBALS['TYPO3_CONF_VARS']['SYS']['reverseProxyIP'];
                 }
                 if (self::cmpIP($_SERVER['REMOTE_ADDR'], $proxySSL)) {
@@ -3248,9 +2781,9 @@ class GeneralUtility
                 }
                 break;
             case '_ARRAY':
-                $out = array();
+                $out = [];
                 // Here, list ALL possible keys to this function for debug display.
-                $envTestVars = array(
+                $envTestVars = [
                     'HTTP_HOST',
                     'TYPO3_HOST_ONLY',
                     'TYPO3_PORT',
@@ -3273,7 +2806,7 @@ class GeneralUtility
                     'REMOTE_HOST',
                     'HTTP_USER_AGENT',
                     'HTTP_ACCEPT_LANGUAGE'
-                );
+                ];
                 foreach ($envTestVars as $v) {
                     $out[$v] = self::getIndpEnv($v);
                 }
@@ -3357,7 +2890,7 @@ class GeneralUtility
      */
     protected static function isInternalRequestType()
     {
-        return (!defined('TYPO3_REQUESTTYPE') || (defined('TYPO3_REQUESTTYPE') && TYPO3_REQUESTTYPE & (TYPO3_REQUESTTYPE_INSTALL | TYPO3_REQUESTTYPE_CLI)));
+        return !defined('TYPO3_REQUESTTYPE') || (defined('TYPO3_REQUESTTYPE') && TYPO3_REQUESTTYPE & (TYPO3_REQUESTTYPE_INSTALL | TYPO3_REQUESTTYPE_CLI));
     }
 
     /**
@@ -3381,7 +2914,7 @@ class GeneralUtility
         if (!$useragent) {
             $useragent = self::getIndpEnv('HTTP_USER_AGENT');
         }
-        $bInfo = array();
+        $bInfo = [];
         // Which browser?
         if (strpos($useragent, 'Konqueror') !== false) {
             $bInfo['BROWSER'] = 'konqu';
@@ -3398,29 +2931,29 @@ class GeneralUtility
             // Browser version
             switch ($bInfo['BROWSER']) {
                 case 'net':
-                    $bInfo['VERSION'] = doubleval(substr($useragent, 8));
+                    $bInfo['VERSION'] = (float)substr($useragent, 8);
                     if (strpos($useragent, 'Netscape6/') !== false) {
-                        $bInfo['VERSION'] = doubleval(substr(strstr($useragent, 'Netscape6/'), 10));
+                        $bInfo['VERSION'] = (float)substr(strstr($useragent, 'Netscape6/'), 10);
                     }
                     // Will we ever know if this was a typo or intention...?! :-(
                     if (strpos($useragent, 'Netscape/6') !== false) {
-                        $bInfo['VERSION'] = doubleval(substr(strstr($useragent, 'Netscape/6'), 10));
+                        $bInfo['VERSION'] = (float)substr(strstr($useragent, 'Netscape/6'), 10);
                     }
                     if (strpos($useragent, 'Netscape/7') !== false) {
-                        $bInfo['VERSION'] = doubleval(substr(strstr($useragent, 'Netscape/7'), 9));
+                        $bInfo['VERSION'] = (float)substr(strstr($useragent, 'Netscape/7'), 9);
                     }
                     break;
                 case 'msie':
                     $tmp = strstr($useragent, 'MSIE');
-                    $bInfo['VERSION'] = doubleval(preg_replace('/^[^0-9]*/', '', substr($tmp, 4)));
+                    $bInfo['VERSION'] = (float)preg_replace('/^[^0-9]*/', '', substr($tmp, 4));
                     break;
                 case 'opera':
                     $tmp = strstr($useragent, 'Opera');
-                    $bInfo['VERSION'] = doubleval(preg_replace('/^[^0-9]*/', '', substr($tmp, 5)));
+                    $bInfo['VERSION'] = (float)preg_replace('/^[^0-9]*/', '', substr($tmp, 5));
                     break;
                 case 'konqu':
                     $tmp = strstr($useragent, 'Konqueror/');
-                    $bInfo['VERSION'] = doubleval(substr($tmp, 10));
+                    $bInfo['VERSION'] = (float)substr($tmp, 10);
                     break;
             }
             // Client system
@@ -3445,7 +2978,6 @@ class GeneralUtility
     {
         $host = '';
         // If not called from the command-line, resolve on getIndpEnv()
-        // Note that TYPO3_REQUESTTYPE is not used here as it may not yet be defined
         if ($requestHost && !(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI)) {
             $host = self::getIndpEnv('HTTP_HOST');
         }
@@ -3486,20 +3018,13 @@ class GeneralUtility
      * \TYPO3\CMS\Core\Utility\GeneralUtility::validPathStr().
      *
      * @param string $filename The input filename/filepath to evaluate
-     * @param bool $onlyRelative If $onlyRelative is set (which it is by default), then only return values relative to the current PATH_site is accepted.
-     * @param bool $relToTYPO3_mainDir If $relToTYPO3_mainDir is set, then relative paths are relative to PATH_typo3 constant - otherwise (default) they are relative to PATH_site
      * @return string Returns the absolute filename of $filename if valid, otherwise blank string.
      */
-    public static function getFileAbsFileName($filename, $onlyRelative = true, $relToTYPO3_mainDir = false)
+    public static function getFileAbsFileName($filename)
     {
         if ((string)$filename === '') {
             return '';
         }
-        $relPathPrefix = PATH_site;
-        if ($relToTYPO3_mainDir) {
-            $relPathPrefix = PATH_typo3;
-        }
-
         // Extension
         if (strpos($filename, 'EXT:') === 0) {
             list($extKey, $local) = explode('/', substr($filename, 4), 2);
@@ -3508,9 +3033,9 @@ class GeneralUtility
                 $filename = ExtensionManagementUtility::extPath($extKey) . $local;
             }
         } elseif (!static::isAbsPath($filename)) {
-            // relative. Prepended with $relPathPrefix
-            $filename = $relPathPrefix . $filename;
-        } elseif ($onlyRelative && !static::isFirstPartOfStr($filename, $relPathPrefix)) {
+            // is relative. Prepended with PATH_site
+            $filename = PATH_site . $filename;
+        } elseif (!static::isFirstPartOfStr($filename, PATH_site)) {
             // absolute, but set to blank if not allowed
             $filename = '';
         }
@@ -3531,12 +3056,11 @@ class GeneralUtility
      * @param string $theFile File path to evaluate
      * @return bool TRUE, $theFile is allowed path string, FALSE otherwise
      * @see http://php.net/manual/en/security.filesystem.nullbytes.php
-     * @todo Possible improvement: Should it rawurldecode the string first to check if any of these characters is encoded?
      */
     public static function validPathStr($theFile)
     {
         return strpos($theFile, '//') === false && strpos($theFile, '\\') === false
-            && !preg_match('#(?:^\\.\\.|/\\.\\./|[[:cntrl:]])#u', $theFile);
+            && preg_match('#(?:^\\.\\.|/\\.\\./|[[:cntrl:]])#u', $theFile) === 0;
     }
 
     /**
@@ -3597,6 +3121,7 @@ class GeneralUtility
             $destination = PATH_site . $destination;
         }
         if (static::isAllowedAbsPath($source) && static::isAllowedAbsPath($destination)) {
+            static::mkdir_deep($destination);
             $iterator = new \RecursiveIteratorIterator(
                 new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS),
                 \RecursiveIteratorIterator::SELF_FIRST
@@ -3616,14 +3141,17 @@ class GeneralUtility
      * Checks if a given string is a valid frame URL to be loaded in the
      * backend.
      *
+     * If the given url is empty or considered to be harmless, it is returned
+     * as is, else the event is logged and an empty string is returned.
+     *
      * @param string $url potential URL to check
-     * @return string either $url if $url is considered to be harmless, or an
+     * @return string $url or empty string
      */
     public static function sanitizeLocalUrl($url = '')
     {
         $sanitizedUrl = '';
-        $decodedUrl = rawurldecode($url);
-        if (!empty($url) && self::removeXSS($decodedUrl) === $decodedUrl) {
+        if (!empty($url)) {
+            $decodedUrl = rawurldecode($url);
             $parsedUrl = parse_url($decodedUrl);
             $testAbsoluteUrl = self::resolveBackPath($decodedUrl);
             $testRelativeUrl = self::resolveBackPath(self::dirname(self::getIndpEnv('SCRIPT_NAME')) . '/' . $decodedUrl);
@@ -3636,12 +3164,14 @@ class GeneralUtility
                 $sanitizedUrl = $url;
             } elseif (strpos($testAbsoluteUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && $decodedUrl[0] === '/') {
                 $sanitizedUrl = $url;
-            } elseif (empty($parsedUrl['scheme']) && strpos($testRelativeUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0 && $decodedUrl[0] !== '/') {
+            } elseif (empty($parsedUrl['scheme']) && strpos($testRelativeUrl, self::getIndpEnv('TYPO3_SITE_PATH')) === 0
+                && $decodedUrl[0] !== '/' && strpbrk($decodedUrl, '*:|"<>') === false && strpos($decodedUrl, '\\\\') === false
+            ) {
                 $sanitizedUrl = $url;
             }
         }
         if (!empty($url) && empty($sanitizedUrl)) {
-            self::sysLog('The URL "' . $url . '" is not considered to be local and was denied.', 'core', self::SYSLOG_SEVERITY_NOTICE);
+            static::getLogger()->notice('The URL "' . $url . '" is not considered to be local and was denied.');
         }
         return $sanitizedUrl;
     }
@@ -3656,18 +3186,19 @@ class GeneralUtility
      */
     public static function upload_copy_move($source, $destination)
     {
+        $result = false;
         if (is_uploaded_file($source)) {
-            $uploaded = true;
-            // 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:
-            $uploadedResult = move_uploaded_file($source, $destination);
+            // 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:
+            $result = move_uploaded_file($source, $destination);
         } else {
-            $uploaded = false;
             @copy($source, $destination);
         }
         // Change the permissions of the file
         self::fixPermissions($destination);
-        // 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
-        return $uploaded ? $uploadedResult : false;
+        // 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
+        return $result;
     }
 
     /**
@@ -3725,9 +3256,12 @@ class GeneralUtility
      */
     public static function tempnam($filePrefix, $fileSuffix = '')
     {
-        $temporaryPath = PATH_site . 'typo3temp/';
+        $temporaryPath = PATH_site . 'typo3temp/var/transient/';
+        if (!is_dir($temporaryPath)) {
+            self::mkdir_deep($temporaryPath);
+        }
         if ($fileSuffix === '') {
-            $tempFileName = static::fixWindowsFilePath(tempnam($temporaryPath, $filePrefix));
+            $tempFileName = $temporaryPath . basename(tempnam($temporaryPath, $filePrefix));
         } else {
             do {
                 $tempFileName = $temporaryPath . $filePrefix . mt_rand(1, PHP_INT_MAX) . $fileSuffix;
@@ -3749,7 +3283,7 @@ class GeneralUtility
     public static function stdAuthCode($uid_or_record, $fields = '', $codeLength = 8)
     {
         if (is_array($uid_or_record)) {
-            $recCopy_temp = array();
+            $recCopy_temp = [];
             if ($fields) {
                 $fieldArr = self::trimExplode(',', $fields, true);
                 foreach ($fieldArr as $k => $v) {
@@ -3797,9 +3331,11 @@ class GeneralUtility
      * @param string $language Language key
      * @param bool $sameLocation If TRUE, then locallang localization file name will be returned with same directory as $fileRef
      * @return string Returns the filename reference for the language unless error occurred in which case it will be NULL
+     * @deprecated in TYPO3 v9.0, will be removed in TYPO3 v10.0, as the functionality has been moved into AbstractXmlParser.
      */
     public static function llXmlAutoFileName($fileRef, $language, $sameLocation = false)
     {
+        trigger_error('This method will be removed in TYPO3 v10.0, the functionality has been moved into AbstractXmlParser', E_USER_DEPRECATED);
         // If $fileRef is already prefixed with "[language key]" then we should return it as is
         $fileName = basename($fileRef);
         if (self::isFirstPartOfStr($fileName, $language . '.')) {
@@ -3840,208 +3376,69 @@ class GeneralUtility
     }
 
     /**
-     * Looks for a sheet-definition in the input data structure array. If found it will return the data structure for the sheet given as $sheet (if found).
-     * If the sheet definition is in an external file that file is parsed and the data structure inside of that is returned.
-     *
-     * @param array $dataStructArray Input data structure, possibly with a sheet-definition and references to external data source files.
-     * @param string $sheet The sheet to return, preferably.
-     * @return array An array with two num. keys: key0: The data structure is returned in this key (array) UNLESS an error occurred in which case an error string is returned (string). key1: The used sheet key value!
-     */
-    public static function resolveSheetDefInDS($dataStructArray, $sheet = 'sDEF')
-    {
-        if (!is_array($dataStructArray)) {
-            return 'Data structure must be an array';
-        }
-        if (is_array($dataStructArray['sheets'])) {
-            $singleSheet = false;
-            if (!isset($dataStructArray['sheets'][$sheet])) {
-                $sheet = 'sDEF';
-            }
-            $dataStruct = $dataStructArray['sheets'][$sheet];
-            // If not an array, but still set, then regard it as a relative reference to a file:
-            if ($dataStruct && !is_array($dataStruct)) {
-                $file = self::getFileAbsFileName($dataStruct);
-                if ($file && @is_file($file)) {
-                    $dataStruct = self::xml2array(self::getUrl($file));
-                }
-            }
-        } else {
-            $singleSheet = true;
-            $dataStruct = $dataStructArray;
-            if (isset($dataStruct['meta'])) {
-                unset($dataStruct['meta']);
-            }
-            // Meta data should not appear there.
-            // Default sheet
-            $sheet = 'sDEF';
-        }
-        return array($dataStruct, $sheet, $singleSheet);
-    }
-
-    /**
-     * Resolves ALL sheet definitions in dataStructArray
-     * If no sheet is found, then the default "sDEF" will be created with the dataStructure inside.
-     *
-     * @param array $dataStructArray Input data structure, possibly with a sheet-definition and references to external data source files.
-     * @return array Output data structure with all sheets resolved as arrays.
-     */
-    public static function resolveAllSheetsInDS(array $dataStructArray)
-    {
-        if (is_array($dataStructArray['sheets'])) {
-            $out = array('sheets' => array());
-            foreach ($dataStructArray['sheets'] as $sheetId => $sDat) {
-                list($ds, $aS) = self::resolveSheetDefInDS($dataStructArray, $sheetId);
-                if ($sheetId == $aS) {
-                    $out['sheets'][$aS] = $ds;
-                }
-            }
-        } else {
-            list($ds) = self::resolveSheetDefInDS($dataStructArray);
-            $out = array('sheets' => array('sDEF' => $ds));
-        }
-        return $out;
-    }
-
-    /**
      * Calls a user-defined function/method in class
      * Such a function/method should look like this: "function proc(&$params, &$ref) {...}"
      *
-     * @param string $funcName Function/Method reference or Closure, '[file-reference":"]["&"]class/function["->"method-name]'. You can prefix this reference with "[file-reference]:" and \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName() will then be used to resolve the filename and subsequently include it by "require_once()" which means you don't have to worry about including the class file either! Example: "EXT:realurl/class.tx_realurl.php:&tx_realurl->encodeSpURL". Finally; you can prefix the class name with "&" if you want to reuse a former instance of the same object call ("singleton").
+     * @param string $funcName Function/Method reference or Closure.
      * @param mixed $params Parameters to be pass along (typically an array) (REFERENCE!)
      * @param mixed $ref Reference to be passed along (typically "$this" - being a reference to the calling object) (REFERENCE!)
-     * @param string $checkPrefix Not used anymore since 6.0
-     * @param int $errorMode Error mode (when class/function could not be found): 0 - call debug(), 1 - do nothing, 2 - raise an exception (allows to call a user function that may return FALSE)
-     * @return mixed Content from method/function call or FALSE if the class/method/function was not found
-     * @see getUserObj()
+     * @return mixed Content from method/function call
+     * @throws \InvalidArgumentException
      */
-    public static function callUserFunction($funcName, &$params, &$ref, $checkPrefix = '', $errorMode = 0)
+    public static function callUserFunction($funcName, &$params, &$ref)
     {
-        $content = false;
         // Check if we're using a closure and invoke it directly.
         if (is_object($funcName) && is_a($funcName, 'Closure')) {
-            return call_user_func_array($funcName, array(&$params, &$ref));
-        }
-        // Check persistent object and if found, call directly and exit.
-        if (isset($GLOBALS['T3_VAR']['callUserFunction'][$funcName]) && is_array($GLOBALS['T3_VAR']['callUserFunction'][$funcName])) {
-            return call_user_func_array(array(
-                &$GLOBALS['T3_VAR']['callUserFunction'][$funcName]['obj'],
-                $GLOBALS['T3_VAR']['callUserFunction'][$funcName]['method']
-            ), array(&$params, &$ref));
-        }
-        // Check file-reference prefix; if found, require_once() the file (should be library of code)
-        if (strpos($funcName, ':') !== false) {
-            list($file, $funcRef) = self::revExplode(':', $funcName, 2);
-            $requireFile = self::getFileAbsFileName($file);
-            if ($requireFile) {
-                self::requireOnce($requireFile);
-            }
-        } else {
-            $funcRef = $funcName;
-        }
-        // Check for persistent object token, "&"
-        if ($funcRef[0] === '&') {
-            $funcRef = substr($funcRef, 1);
-            $storePersistentObject = true;
-        } else {
-            $storePersistentObject = false;
+            return call_user_func_array($funcName, [&$params, &$ref]);
         }
-        // Call function or method:
-        $parts = explode('->', $funcRef);
+        $funcName = trim($funcName);
+        $parts = explode('->', $funcName);
+        // Call function or method
         if (count($parts) === 2) {
-            // Class
+            // It's a class/method
             // Check if class/method exists:
             if (class_exists($parts[0])) {
-                // Get/Create object of class:
-                if ($storePersistentObject) {
-                    // Get reference to current instance of class:
-                    if (!is_object($GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]])) {
-                        $GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]] = self::makeInstance($parts[0]);
-                    }
-                    $classObj = $GLOBALS['T3_VAR']['callUserFunction_classPool'][$parts[0]];
-                } else {
-                    // Create new object:
-                    $classObj = self::makeInstance($parts[0]);
-                }
+                // Create object
+                $classObj = self::makeInstance($parts[0]);
                 if (method_exists($classObj, $parts[1])) {
-                    // If persistent object should be created, set reference:
-                    if ($storePersistentObject) {
-                        $GLOBALS['T3_VAR']['callUserFunction'][$funcName] = array(
-                            'method' => $parts[1],
-                            'obj' => &$classObj
-                        );
-                    }
                     // Call method:
-                    $content = call_user_func_array(array(&$classObj, $parts[1]), array(&$params, &$ref));
+                    $content = call_user_func_array([&$classObj, $parts[1]], [&$params, &$ref]);
                 } else {
                     $errorMsg = 'No method name \'' . $parts[1] . '\' in class ' . $parts[0];
-                    if ($errorMode == 2) {
-                        throw new \InvalidArgumentException($errorMsg, 1294585865);
-                    } elseif (!$errorMode) {
-                        debug($errorMsg, \TYPO3\CMS\Core\Utility\GeneralUtility::class . '::callUserFunction');
-                    }
+                    throw new \InvalidArgumentException($errorMsg, 1294585865);
                 }
             } else {
                 $errorMsg = 'No class named ' . $parts[0];
-                if ($errorMode == 2) {
-                    throw new \InvalidArgumentException($errorMsg, 1294585866);
-                } elseif (!$errorMode) {
-                    debug($errorMsg, \TYPO3\CMS\Core\Utility\GeneralUtility::class . '::callUserFunction');
-                }
+                throw new \InvalidArgumentException($errorMsg, 1294585866);
             }
+        } elseif (function_exists($funcName)) {
+            // It's a function
+            $content = call_user_func_array($funcName, [&$params, &$ref]);
         } else {
-            // Function
-            if (function_exists($funcRef)) {
-                $content = call_user_func_array($funcRef, array(&$params, &$ref));
-            } else {
-                $errorMsg = 'No function named: ' . $funcRef;
-                if ($errorMode == 2) {
-                    throw new \InvalidArgumentException($errorMsg, 1294585867);
-                } elseif (!$errorMode) {
-                    debug($errorMsg, \TYPO3\CMS\Core\Utility\GeneralUtility::class . '::callUserFunction');
-                }
-            }
+            $errorMsg = 'No function named: ' . $funcName;
+            throw new \InvalidArgumentException($errorMsg, 1294585867);
         }
         return $content;
     }
 
     /**
+     * This method should be avoided, as it will be deprecated completely in TYPO3 v9, and will be removed in TYPO3 v10.
+     * Instead use makeInstance() directly.
+     *
      * Creates and returns reference to a user defined object.
      * This function can return an object reference if you like.
-     * Just prefix the function call with "&": "$objRef = &\TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj('EXT:myext/class.tx_myext_myclass.php:&tx_myext_myclass');".
-     * This will work ONLY if you prefix the class name with "&" as well. See description of function arguments.
      *
-     * @todo Deprecate the whole method in several steps:
-     *      1. Deprecated singleton pattern (was removed in TYPO3 CMS 8)
-     *      2. Deprecate file prefix/ require file,
-     *      3. Deprecate usage without valid class name.
-     *      4. The last step should be to deprecate the method itself.
-     *
-     * @param string $classRef Class reference, '[file-reference":"]["&"]class-name'. You can prefix the class name with "[file-reference]:" and \TYPO3\CMS\Core\Utility\GeneralUtility::getFileAbsFileName() will then be used to resolve the filename and subsequently include it by "require_once()" which means you don't have to worry about including the class file either! Example: "EXT:realurl/class.tx_realurl.php:&tx_realurl". Finally; for the class name you can prefix it with "&" and you will reuse the previous instance of the object identified by the full reference string (meaning; if you ask for the same $classRef later in another place in the code you will get a reference to the first created one!).
-     * @return object The instance of the class asked for. Instance is created with \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance
+     * @param string $className Class name
+     * @return object The instance of the class asked for. Instance is created with GeneralUtility::makeInstance
      * @see callUserFunction()
+     * @deprecated
      */
-    public static function getUserObj($classRef)
+    public static function getUserObj($className)
     {
-        // Check persistent object and if found, call directly and exit.
-        if (is_object($GLOBALS['T3_VAR']['getUserObj'][$classRef])) {
-            return $GLOBALS['T3_VAR']['getUserObj'][$classRef];
-        } else {
-            // Check file-reference prefix; if found, require_once() the file (should be library of code)
-            if (strpos($classRef, ':') !== false) {
-                list($file, $class) = self::revExplode(':', $classRef, 2);
-                $requireFile = self::getFileAbsFileName($file);
-                if ($requireFile) {
-                    self::requireOnce($requireFile);
-                }
-            } else {
-                $class = $classRef;
-            }
-
-            // Check if class exists:
-            if (class_exists($class)) {
-                $classObj = self::makeInstance($class);
-                return $classObj;
-            }
+        trigger_error('This method will be removed in TYPO3 v10.0, use GeneralUtility::makeInstance() directly instead', E_USER_DEPRECATED);
+        // Check if class exists:
+        if (class_exists($className)) {
+            return self::makeInstance($className);
         }
     }
 
@@ -4060,12 +3457,11 @@ class GeneralUtility
      * the instance of a specific class.
      *
      * @param string $className name of the class to instantiate, must not be empty and not start with a backslash
-     *
+     * @param array<int, mixed> $constructorArguments Arguments for the constructor
      * @return object the created instance
-     *
      * @throws \InvalidArgumentException if $className is empty or starts with a backslash
      */
-    public static function makeInstance($className)
+    public static function makeInstance($className, ...$constructorArguments)
     {
         if (!is_string($className) || empty($className)) {
             throw new \InvalidArgumentException('$className must be a non empty string.', 1288965219);
@@ -4073,7 +3469,8 @@ class GeneralUtility
         // Never instantiate with a beginning backslash, otherwise things like singletons won't work.
         if ($className[0] === '\\') {
             throw new \InvalidArgumentException(
-                '$className "' . $className . '" must not start with a backslash.', 1420281366
+                '$className "' . $className . '" must not start with a backslash.',
+                1420281366
             );
         }
         if (isset(static::$finalClassNameCache[$className])) {
@@ -4094,58 +3491,13 @@ class GeneralUtility
             return array_shift(self::$nonSingletonInstances[$finalClassName]);
         }
         // Create new instance and call constructor with parameters
-        $instance = static::instantiateClass($finalClassName, func_get_args());
+        $instance = new $finalClassName(...$constructorArguments);
         // Register new singleton instance
         if ($instance instanceof SingletonInterface) {
             self::$singletonInstances[$finalClassName] = $instance;
         }
-        return $instance;
-    }
-
-    /**
-     * Speed optimized alternative to ReflectionClass::newInstanceArgs()
-     *
-     * @param string $className Name of the class to instantiate
-     * @param array $arguments Arguments passed to self::makeInstance() thus the first one with index 0 holds the requested class name
-     * @return mixed
-     */
-    protected static function instantiateClass($className, $arguments)
-    {
-        switch (count($arguments)) {
-            case 1:
-                $instance = new $className();
-                break;
-            case 2:
-                $instance = new $className($arguments[1]);
-                break;
-            case 3:
-                $instance = new $className($arguments[1], $arguments[2]);
-                break;
-            case 4:
-                $instance = new $className($arguments[1], $arguments[2], $arguments[3]);
-                break;
-            case 5:
-                $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4]);
-                break;
-            case 6:
-                $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5]);
-                break;
-            case 7:
-                $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6]);
-                break;
-            case 8:
-                $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7]);
-                break;
-            case 9:
-                $instance = new $className($arguments[1], $arguments[2], $arguments[3], $arguments[4], $arguments[5], $arguments[6], $arguments[7], $arguments[8]);
-                break;
-            default:
-                // The default case for classes with constructors that have more than 8 arguments.
-                // This will fail when one of the arguments shall be passed by reference.
-                // In case we really need to support this edge case, we can implement the solution from here: https://review.typo3.org/26344
-                $class = new \ReflectionClass($className);
-                array_shift($arguments);
-                $instance = $class->newInstanceArgs($arguments);
+        if ($instance instanceof LoggerAwareInterface) {
+            $instance->setLogger(static::makeInstance(LogManager::class)->getLogger($className));
         }
         return $instance;
     }
@@ -4186,14 +3538,7 @@ class GeneralUtility
      */
     protected static function classHasImplementation($className)
     {
-        // If we are early in the bootstrap, the configuration might not yet be present
-        if (!isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'])) {
-            return false;
-        }
-
-        return isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className])
-                && is_array($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className])
-                && !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className]['className']);
+        return !empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['Objects'][$className]['className']);
     }
 
     /**
@@ -4211,7 +3556,6 @@ class GeneralUtility
      * @see makeInstance
      * @param string $className
      * @param \TYPO3\CMS\Core\SingletonInterface $instance
-     * @return void
      * @internal
      */
     public static function setSingletonInstance($className, SingletonInterface $instance)
@@ -4233,7 +3577,6 @@ class GeneralUtility
      * @throws \InvalidArgumentException
      * @param string $className
      * @param \TYPO3\CMS\Core\SingletonInterface $instance
-     * @return void
      * @internal
      */
     public static function removeSingletonInstance($className, SingletonInterface $instance)
@@ -4260,11 +3603,10 @@ class GeneralUtility
      *
      * @internal
      * @param array $newSingletonInstances $className => $object
-     * @return void
      */
     public static function resetSingletonInstances(array $newSingletonInstances)
     {
-        static::$singletonInstances = array();
+        static::$singletonInstances = [];
         foreach ($newSingletonInstances as $className => $instance) {
             static::setSingletonInstance($className, $instance);
         }
@@ -4300,7 +3642,6 @@ class GeneralUtility
      * @throws \InvalidArgumentException if class extends \TYPO3\CMS\Core\SingletonInterface
      * @param string $className
      * @param object $instance
-     * @return void
      */
     public static function addInstance($className, $instance)
     {
@@ -4309,7 +3650,7 @@ class GeneralUtility
             throw new \InvalidArgumentException('$instance must not be an instance of TYPO3\\CMS\\Core\\SingletonInterface. ' . 'For setting singletons, please use setSingletonInstance.', 1288969325);
         }
         if (!isset(self::$nonSingletonInstances[$className])) {
-            self::$nonSingletonInstances[$className] = array();
+            self::$nonSingletonInstances[$className] = [];
         }
         self::$nonSingletonInstances[$className][] = $instance;
     }
@@ -4321,7 +3662,6 @@ class GeneralUtility
      * @throws \InvalidArgumentException if $className is empty or if $instance is no instance of $className
      * @param string $className a class name
      * @param object $instance an object
-     * @return void
      */
     protected static function checkInstanceClassName($className, $instance)
     {
@@ -4342,12 +3682,11 @@ class GeneralUtility
      * Warning: This is a helper method for unit tests. Do not call this directly in production code!
      *
      * @see makeInstance
-     * @return void
      */
     public static function purgeInstances()
     {
-        self::$singletonInstances = array();
-        self::$nonSingletonInstances = array();
+        self::$singletonInstances = [];
+        self::$nonSingletonInstances = [];
     }
 
     /**
@@ -4355,7 +3694,6 @@ class GeneralUtility
      *
      * Used in unit tests only.
      *
-     * @return void
      * @internal
      */
     public static function flushInternalRuntimeCaches()
@@ -4373,17 +3711,17 @@ class GeneralUtility
      * @param mixed $excludeServiceKeys List of service keys which should be excluded in the search for a service. Array or comma list.
      * @return object|string[] The service object or an array with error infos.
      */
-    public static function makeInstanceService($serviceType, $serviceSubType = '', $excludeServiceKeys = array())
+    public static function makeInstanceService($serviceType, $serviceSubType = '', $excludeServiceKeys = [])
     {
         $error = false;
         if (!is_array($excludeServiceKeys)) {
             $excludeServiceKeys = self::trimExplode(',', $excludeServiceKeys, true);
         }
-        $requestInfo = array(
+        $requestInfo = [
             'requestedServiceType' => $serviceType,
             'requestedServiceSubType' => $serviceSubType,
             'requestedExcludeServiceKeys' => $excludeServiceKeys
-        );
+        ];
         while ($info = ExtensionManagementUtility::findService($serviceType, $serviceSubType, $excludeServiceKeys)) {
             // provide information about requested service to service object
             $info = array_merge($info, $requestInfo);
@@ -4394,24 +3732,24 @@ class GeneralUtility
                 // reset service and return object
                 $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']]->reset();
                 return $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']];
-            } else {
-                $obj = self::makeInstance($info['className']);
-                if (is_object($obj)) {
-                    if (!@is_callable(array($obj, 'init'))) {
-                        // use silent logging??? I don't think so.
-                        die('Broken service:' . DebugUtility::viewArray($info));
-                    }
-                    $obj->info = $info;
-                    // service available?
-                    if ($obj->init()) {
-                        // create persistent object
-                        $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']] = $obj;
-                        return $obj;
-                    }
-                    $error = $obj->getLastErrorArray();
-                    unset($obj);
+            }
+            $obj = self::makeInstance($info['className']);
+            if (is_object($obj)) {
+                if (!@is_callable([$obj, 'init'])) {
+                    // use silent logging??? I don't think so.
+                    die('Broken service:' . DebugUtility::viewArray($info));
                 }
+                $obj->info = $info;
+                // service available?
+                if ($obj->init()) {
+                    // create persistent object
+                    $GLOBALS['T3_VAR']['makeInstanceService'][$info['className']] = $obj;
+                    return $obj;
+                }
+                $error = $obj->getLastErrorArray();
+                unset($obj);
             }
+
             // deactivate the service
             ExtensionManagementUtility::deactivateService($info['serviceType'], $info['serviceKey']);
         }
@@ -4419,127 +3757,39 @@ class GeneralUtility
     }
 
     /**
-     * Require a class for TYPO3
-     * Useful to require classes from inside other classes (not global scope). A limited set of global variables are available (see function)
-     *
-     * @param string $requireFile: Path of the file to be included
-     * @return void
-     */
-    public static function requireOnce($requireFile)
-    {
-        // Needed for require_once
-        global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
-        require_once $requireFile;
-    }
-
-    /**
-     * Requires a class for TYPO3
-     * Useful to require classes from inside other classes (not global scope).
-     * A limited set of global variables are available (see function)
-     *
-     * @param string $requireFile: Path of the file to be included
-     * @return void
-     */
-    public static function requireFile($requireFile)
-    {
-        // Needed for require
-        global $T3_SERVICES, $T3_VAR, $TYPO3_CONF_VARS;
-        require $requireFile;
-    }
-
-    /**
-     * Create a shortened "redirect" URL with specified length from an incoming URL
-     *
-     * @param string $inUrl Input URL
-     * @param int $l URL string length limit
-     * @param string $index_script_url URL of "index script" - the prefix of the "?RDCT=..." parameter. If not supplied it will default to \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_REQUEST_DIR').'index.php'
-     * @return string Processed URL
-     */
-    public static function makeRedirectUrl($inUrl, $l = 0, $index_script_url = '')
-    {
-        if (strlen($inUrl) > $l) {
-            $md5 = substr(md5($inUrl), 0, 20);
-            $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('*', 'cache_md5params', 'md5hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($md5, 'cache_md5params'));
-            if (!$count) {
-                $insertFields = array(
-                    'md5hash' => $md5,
-                    'tstamp' => $GLOBALS['EXEC_TIME'],
-                    'type' => 2,
-                    'params' => $inUrl
-                );
-                $GLOBALS['TYPO3_DB']->exec_INSERTquery('cache_md5params', $insertFields);
-            }
-            $inUrl = ($index_script_url ? $index_script_url : self::getIndpEnv('TYPO3_REQUEST_DIR') . 'index.php') . '?RDCT=' . $md5;
-        }
-        return $inUrl;
-    }
-
-    /**
-     * Function to compensate for DPI resolution.
-     *
-     * @param float $fontSize font size for freetype function call
-     *
-     * @return float compensated font size based on 96 dpi
-     */
-    public static function freetypeDpiComp($fontSize)
-    {
-        // FreeType 2 always has 96 dpi.
-        $dpi = 96.0;
-        return $fontSize / $dpi * 72;
-    }
-
-    /**
      * Initialize the system log.
      *
-     * @return void
      * @see sysLog()
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
      */
     public static function initSysLog()
     {
-        // For CLI logging name is <fqdn-hostname>:<TYPO3-path>
-        // Note that TYPO3_REQUESTTYPE is not used here as it may not yet be defined
-        if (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI) {
-            $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] = self::getHostname(($requestHost = false)) . ':' . PATH_site;
-        } else {
-            $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] = self::getIndpEnv('TYPO3_SITE_URL');
-        }
         // Init custom logging
-        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'])) {
-            $params = array('initLog' => true);
-            $fakeThis = false;
-            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] as $hookMethod) {
-                self::callUserFunction($hookMethod, $params, $fakeThis);
-            }
-        }
-        // Init TYPO3 logging
-        foreach (explode(';', $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog'], 2) as $log) {
-            list($type, $destination) = explode(',', $log, 3);
-            if ($type == 'syslog') {
-                if (TYPO3_OS == 'WIN') {
-                    $facility = LOG_USER;
-                } else {
-                    $facility = constant('LOG_' . strtoupper($destination));
-                }
-                openlog($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'], LOG_ODELAY, $facility);
-            }
+        $params = ['initLog' => true];
+        $fakeThis = false;
+        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] ?? [] as $hookMethod) {
+            self::callUserFunction($hookMethod, $params, $fakeThis);
         }
         $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] = MathUtility::forceIntegerInRange($GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'], 0, 4);
         $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit'] = true;
     }
 
     /**
-     * Logs message to the system log.
+     * Logs message to custom "systemLog" handlers and logging API
+     *
      * This should be implemented around the source code, including the Core and both frontend and backend, logging serious errors.
      * If you want to implement the sysLog in your applications, simply add lines like:
      * \TYPO3\CMS\Core\Utility\GeneralUtility::sysLog('[write message in English here]', 'extension_key', 'severity');
      *
      * @param string $msg Message (in English).
-     * @param string $extKey Extension key (from which extension you are calling the log) or "Core
+     * @param string $extKey Extension key (from which extension you are calling the log) or "Core"
      * @param int $severity \TYPO3\CMS\Core\Utility\GeneralUtility::SYSLOG_SEVERITY_* constant
-     * @return void
+     * @deprecated
      */
     public static function sysLog($msg, $extKey, $severity = 0)
     {
+        trigger_error('Method sysLog() is deprecated since v9 and will be removed with v10', E_USER_DEPRECATED);
+
         $severity = MathUtility::forceIntegerInRange($severity, 0, 4);
         // Is message worth logging?
         if ((int)$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLogLevel'] > $severity) {
@@ -4549,9 +3799,9 @@ class GeneralUtility
         if (!$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogInit']) {
             self::initSysLog();
         }
-        // Do custom logging
-        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'])) {
-            $params = array('msg' => $msg, 'extKey' => $extKey, 'backTrace' => debug_backtrace(), 'severity' => $severity);
+        // Do custom logging; avoid calling debug_backtrace if there are no custom loggers.
+        if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'])) {
+            $params = ['msg' => $msg, 'extKey' => $extKey, 'backTrace' => debug_backtrace(), 'severity' => $severity];
             $fakeThis = false;
             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLog'] as $hookMethod) {
                 self::callUserFunction($hookMethod, $params, $fakeThis);
@@ -4561,40 +3811,8 @@ class GeneralUtility
         if (!$GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog']) {
             return;
         }
-        $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
-        $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
-        // Use all configured logging options
-        foreach (explode(';', $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemLog'], 2) as $log) {
-            list($type, $destination, $level) = explode(',', $log, 4);
-            // Is message worth logging for this log type?
-            if ((int)$level > $severity) {
-                continue;
-            }
-            $msgLine = ' - ' . $extKey . ': ' . $msg;
-            // Write message to a file
-            if ($type == 'file') {
-                $file = fopen($destination, 'a');
-                if ($file) {
-                    fwrite($file, date(($dateFormat . ' ' . $timeFormat)) . $msgLine . LF);
-                    fclose($file);
-                    self::fixPermissions($destination);
-                }
-            } elseif ($type == 'mail') {
-                list($to, $from) = explode('/', $destination);
-                if (!self::validEmail($from)) {
-                    $from = MailUtility::getSystemFrom();
-                }
-                /** @var $mail \TYPO3\CMS\Core\Mail\MailMessage */
-                $mail = self::makeInstance(\TYPO3\CMS\Core\Mail\MailMessage::class);
-                $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);
-                $mail->send();
-            } elseif ($type == 'error_log') {
-                error_log($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['systemLogHost'] . $msgLine, 0);
-            } elseif ($type == 'syslog') {
-                $priority = array(LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT);
-                syslog($priority[(int)$severity], $msgLine);
-            }
-        }
+
+        static::getLogger()->log(LogLevel::INFO - $severity, $msg, ['extension' => $extKey]);
     }
 
     /**
@@ -4602,19 +3820,20 @@ class GeneralUtility
      * This should be implemented around the source code, both frontend and backend, logging everything from the flow through an application, messages, results from comparisons to fatal errors.
      * The result is meant to make sense to developers during development or debugging of a site.
      * The idea is that this function is only a wrapper for external extensions which can set a hook which will be allowed to handle the logging of the information to any format they might wish and with any kind of filter they would like.
-     * If you want to implement the devLog in your applications, simply add lines like:
-     * if (TYPO3_DLOG) \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[write message in english here]', 'extension key');
+     * If you want to implement the devLog in your applications, simply add a line like:
+     * \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('[write message in english here]', 'extension key');
      *
      * @param string $msg Message (in english).
      * @param string $extKey Extension key (from which extension you are calling the log)
      * @param int $severity Severity: 0 is info, 1 is notice, 2 is warning, 3 is fatal error, -1 is "OK" message
      * @param mixed $dataVar Additional data you want to pass to the logger.
-     * @return void
+     * @deprecated
      */
     public static function devLog($msg, $extKey, $severity = 0, $dataVar = false)
     {
+        trigger_error('Method devLog() is deprecated since v9 and will be removed with v10', E_USER_DEPRECATED);
         if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog'])) {
-            $params = array('msg' => $msg, 'extKey' => $extKey, 'severity' => $severity, 'dataVar' => $dataVar);
+            $params = ['msg' => $msg, 'extKey' => $extKey, 'severity' => $severity, 'dataVar' => $dataVar];
             $fakeThis = false;
             foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['devLog'] as $hookMethod) {
                 self::callUserFunction($hookMethod, $params, $fakeThis);
@@ -4626,37 +3845,90 @@ class GeneralUtility
      * Writes a message to the deprecation log.
      *
      * @param string $msg Message (in English).
-     * @return void
-     * @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9
+     * @deprecated
      */
     public static function deprecationLog($msg)
     {
-        DeprecationUtility::logFunction();
-        DeprecationUtility::logMessage($msg);
+        static::writeDeprecationLogFileEntry(__METHOD__ . ' is deprecated since TYPO3 v9.0, will be removed in TYPO3 v10.0, use "trigger_error("Given reason", E_USER_DEPRECATED);" to log deprecations.');
+        trigger_error($msg, E_USER_DEPRECATED);
+    }
+
+    /**
+     * Logs the usage of a deprecated fluid ViewHelper argument.
+     * The log message will be generated automatically and contains the template path.
+     * With the third argument of this method it is possible to append some text to the log message.
+     *
+     * example usage:
+     *  if ($htmlEscape !== null) {
+     *      GeneralUtility::logDeprecatedViewHelperAttribute(
+     *          'htmlEscape',
+     *          $renderingContext,
+     *          'Please wrap the view helper in <f:format.raw> if you want to disable HTML escaping, which is enabled by default now.'
+     *      );
+     *  }
+     *
+     * The example above will create this deprecation log message:
+     * 15-02-17 23:12: [typo3/sysext/backend/Resources/Private/Templates/ToolbarItems/HelpToolbarItemDropDown.html]
+     *   The property "htmlEscape" has been deprecated.
+     *   Please wrap the view helper in <f:format.raw> if you want to disable HTML escaping,
+     *   which is enabled by default now.
+     *
+     * @param string $property
+     * @param RenderingContextInterface $renderingContext
+     * @param string $additionalMessage
+     * @deprecated
+     */
+    public static function logDeprecatedViewHelperAttribute(string $property, RenderingContextInterface $renderingContext, string $additionalMessage = '')
+    {
+        static::writeDeprecationLogFileEntry(__METHOD__ . ' is deprecated since TYPO3 v9.0, will be removed in TYPO3 v10.0');
+        $template = $renderingContext->getTemplatePaths()->resolveTemplateFileForControllerAndActionAndFormat(
+            $renderingContext->getControllerName(),
+            $renderingContext->getControllerAction()
+        );
+        $template = str_replace(PATH_site, '', $template);
+        $message = [];
+        $message[] = '[' . $template . ']';
+        $message[] = 'The property "' . $property . '" has been marked as deprecated.';
+        $message[] = $additionalMessage;
+        $message[] = 'Please check also your partial and layout files of this template';
+        trigger_error(implode(' ', $message), E_USER_DEPRECATED);
     }
 
     /**
      * Gets the absolute path to the deprecation log file.
      *
      * @return string Absolute path to the deprecation log file
-     * @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9
+     * @deprecated
      */
     public static function getDeprecationLogFileName()
     {
-        DeprecationUtility::logFunction();
-        DeprecationUtility::getDeprecationLogFileName();
+        static::writeDeprecationLogFileEntry(__METHOD__ . ' is deprecated since TYPO3 v9.0, will be removed in TYPO3 v10.0');
+        return PATH_typo3conf . 'deprecation_' . self::shortMD5((PATH_site . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) . '.log';
     }
 
     /**
      * Logs a call to a deprecated function.
      * The log message will be taken from the annotation.
-     *
-     * @return void
-     * @deprecated since TYPO3 CMS 8, will be removed in TYPO3 CMS 9
+     * @deprecated
      */
     public static function logDeprecatedFunction()
     {
-        DeprecationUtility::logFunction();
+        static::writeDeprecationLogFileEntry(__METHOD__ . ' is deprecated since TYPO3 v9.0, will be removed in TYPO3 v10.0');
+        $trail = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
+        if ($trail[1]['type']) {
+            $function = new \ReflectionMethod($trail[1]['class'], $trail[1]['function']);
+        } else {
+            $function = new \ReflectionFunction($trail[1]['function']);
+        }
+        $msg = '';
+        if (preg_match('/@deprecated\\s+(.*)/', $function->getDocComment(), $match)) {
+            $msg = $match[1];
+        }
+        // Write a longer message to the deprecation log: <function> <annotion> - <trace> (<source>)
+        $logMsg = $trail[1]['class'] . $trail[1]['type'] . $trail[1]['function'];
+        $logMsg .= '() - ' . $msg . ' - ' . DebugUtility::debugTrail();
+        $logMsg .= ' (' . PathUtility::stripPathSitePrefix($function->getFileName()) . '#' . $function->getStartLine() . ')';
+        trigger_error($logMsg, E_USER_DEPRECATED);
     }
 
     /**
@@ -4668,7 +3940,7 @@ class GeneralUtility
      * @param int $valueLength Long string values are shortened to this length. Default: 20
      * @return string Output string with key names and their value as string
      */
-    public static function arrayToLogString(array $arr, $valueList = array(), $valueLength = 20)
+    public static function arrayToLogString(array $arr, $valueList = [], $valueLength = 20)
     {
         $str = '';
         if (!is_array($valueList)) {
@@ -4684,23 +3956,8 @@ class GeneralUtility
     }
 
     /**
-     * Compile the command for running ImageMagick/GraphicsMagick.
-     *
-     * @param string $command Command to be run: identify, convert or combine/composite
-     * @param string $parameters The parameters string
-     * @param string $path Override the default path (e.g. used by the install tool)
-     * @return string Compiled command that deals with ImageMagick & GraphicsMagick
-     */
-    public static function imageMagickCommand($command, $parameters, $path = '')
-    {
-        return CommandUtility::imageMagickCommand($command, $parameters, $path);
-    }
-
-    /**
      * Explode a string (normally a list of filenames) with whitespaces by considering quotes in that string.
      *
-     * This is mostly needed by the imageMagickCommand function above.
-     *
      * @param string $parameters The whole parameters string
      * @param bool $unQuote If set, the elements of the resulting array are unquoted.
      * @return array Exploded parameters
@@ -4744,8 +4001,8 @@ class GeneralUtility
     public static function quoteJSvalue($value)
     {
         return strtr(
-            json_encode((string)$value, JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_TAG),
-            array(
+            json_encode((string)$value, JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_TAG),
+            [
                 '"' => '\'',
                 '\\\\' => '\\u005C',
                 ' ' => '\\u0020',
@@ -4753,45 +4010,18 @@ class GeneralUtility
                 '\\t' => '\\u0009',
                 '\\n' => '\\u000A',
                 '\\r' => '\\u000D'
-            )
+            ]
         );
     }
 
     /**
-     * Ends and flushes all output buffers
-     *
-     * @return void
-     */
-    public static function flushOutputBuffers()
-    {
-        $obContent = '';
-        while ($content = ob_get_clean()) {
-            $obContent .= $content;
-        }
-        // If previously a "Content-Encoding: whatever" has been set, we have to unset it
-        if (!headers_sent()) {
-            $headersList = headers_list();
-            foreach ($headersList as $header) {
-                // Split it up at the :
-                list($key, $value) = self::trimExplode(':', $header, true);
-                // Check if we have a Content-Encoding other than 'None'
-                if (strtolower($key) === 'content-encoding' && strtolower($value) !== 'none') {
-                    header('Content-Encoding: None');
-                    break;
-                }
-            }
-        }
-        echo $obContent;
-    }
-
-    /**
      * Set the ApplicationContext
      *
      * This function is used by the Bootstrap to hand over the application context. It must not be used anywhere else,
      * because the context shall never be changed on runtime!
      *
      * @param \TYPO3\CMS\Core\Core\ApplicationContext $applicationContext
-     * @throws \RuntimeException if applicationContext is overriden
+     * @throws \RuntimeException if applicationContext is overridden
      * @internal This is not a public API method, do not use in own extensions
      */
     public static function presetApplicationContext(ApplicationContext $applicationContext)
@@ -4821,4 +4051,29 @@ class GeneralUtility
     {
         return in_array(PHP_SAPI, self::$supportedCgiServerApis, true);
     }
+
+    /**
+     * @return LoggerInterface
+     */
+    protected static function getLogger()
+    {
+        return static::makeInstance(LogManager::class)->getLogger(__CLASS__);
+    }
+
+    /**
+     * @param string $msg
+     * @deprecated
+     */
+    private static function writeDeprecationLogFileEntry($msg)
+    {
+        $date = date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'] . ' ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'] . ': ');
+        // Write a longer message to the deprecation log
+        $destination = PATH_typo3conf . 'deprecation_' . self::shortMD5(PATH_site . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']) . '.log';
+        $file = @fopen($destination, 'a');
+        if ($file) {
+            @fwrite($file, $date . $msg . LF);
+            @fclose($file);
+            self::fixPermissions($destination);
+        }
+    }
 }