[BUGFIX] Do not force content_fallback to default page language
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Controller / TypoScriptFrontendController.php
index 022af72..edba1ff 100644 (file)
@@ -14,30 +14,37 @@ namespace TYPO3\CMS\Frontend\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
+use Doctrine\DBAL\Exception\ConnectionException;
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerAwareTrait;
 use TYPO3\CMS\Backend\FrontendBackendUserAuthentication;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Cache\CacheManager;
 use TYPO3\CMS\Core\Charset\CharsetConverter;
+use TYPO3\CMS\Core\Controller\ErrorPageController;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\QueryHelper;
+use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
+use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction;
+use TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction;
 use TYPO3\CMS\Core\Error\Http\PageNotFoundException;
 use TYPO3\CMS\Core\Error\Http\ServiceUnavailableException;
-use TYPO3\CMS\Core\Localization\Locales;
-use TYPO3\CMS\Core\Localization\LocalizationFactory;
+use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Locking\Exception\LockAcquireWouldBlockException;
-use TYPO3\CMS\Core\Locking\Locker;
 use TYPO3\CMS\Core\Locking\LockFactory;
 use TYPO3\CMS\Core\Locking\LockingStrategyInterface;
-use TYPO3\CMS\Core\Messaging\ErrorpageMessage;
+use TYPO3\CMS\Core\Log\LogManager;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Resource\StorageRepository;
 use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\CMS\Core\TimeTracker\TimeTracker;
 use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser;
 use TYPO3\CMS\Core\TypoScript\TemplateService;
 use TYPO3\CMS\Core\Utility\ArrayUtility;
-use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
-use TYPO3\CMS\Core\Utility\StringUtility;
 use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
 use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
 use TYPO3\CMS\Frontend\Http\UrlHandlerInterface;
@@ -48,21 +55,23 @@ use TYPO3\CMS\Frontend\View\AdminPanelView;
 
 /**
  * Class for the built TypoScript based frontend. Instantiated in
- * index_ts.php script as the global object TSFE.
+ * \TYPO3\CMS\Frontend\Http\RequestHandler as the global object TSFE.
  *
- * Main frontend class, instantiated in the index_ts.php script as the global
- * object TSFE.
+ * Main frontend class, instantiated in \TYPO3\CMS\Frontend\Http\RequestHandler
+ * as the global object TSFE.
  *
  * This class has a lot of functions and internal variable which are used from
- * index_ts.php.
+ * \TYPO3\CMS\Frontend\Http\RequestHandler
  *
- * The class is instantiated as $GLOBALS['TSFE'] in index_ts.php.
+ * The class is instantiated as $GLOBALS['TSFE'] in \TYPO3\CMS\Frontend\Http\RequestHandler.
  *
  * The use of this class should be inspired by the order of function calls as
- * found in index_ts.php.
+ * found in \TYPO3\CMS\Frontend\Http\RequestHandler.
  */
-class TypoScriptFrontendController
+class TypoScriptFrontendController implements LoggerAwareInterface
 {
+    use LoggerAwareTrait;
+
     /**
      * The page id (int)
      * @var string
@@ -134,12 +143,6 @@ class TypoScriptFrontendController
     public $sys_page = '';
 
     /**
-     * @var string
-     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. JumpURL handling is moved to extensions.
-     */
-    public $jumpurl = '';
-
-    /**
      * Contains all URL handler instances that are active for the current request.
      *
      * The methods isGeneratePage(), isOutputting() and isINTincScript() depend on this property.
@@ -165,7 +168,7 @@ class TypoScriptFrontendController
      * Array containing a history of why a requested page was not accessible.
      * @var array
      */
-    public $pageAccessFailureHistory = array();
+    public $pageAccessFailureHistory = [];
 
     /**
      * @var string
@@ -173,11 +176,6 @@ class TypoScriptFrontendController
     public $MP = '';
 
     /**
-     * @var string
-     */
-    public $RDCT = '';
-
-    /**
      * This can be set from applications as a way to tag cached versions of a page
      * and later perform some external cache management, like clearing only a part
      * of the cache of a page...
@@ -277,18 +275,11 @@ class TypoScriptFrontendController
     public $simUserGroup = 0;
 
     /**
-     * Copy of $GLOBALS['TYPO3_CONF_VARS']
-     *
-     * @var array
-     */
-    public $TYPO3_CONF_VARS = array();
-
-    /**
      * "CONFIG" object from TypoScript. Array generated based on the TypoScript
      * configuration of the current page. Saved with the cached pages.
      * @var array
      */
-    public $config = '';
+    public $config = [];
 
     /**
      * The TypoScript template object. Used to parse the TypoScript template
@@ -329,7 +320,7 @@ class TypoScriptFrontendController
      * cached, which it must be.
      * @var array
      */
-    public $all = array();
+    public $all = [];
 
     /**
      * Toplevel - objArrayName, eg 'page'
@@ -386,7 +377,7 @@ class TypoScriptFrontendController
      * The array which cHash_calc is based on, see ->makeCacheHash().
      * @var array
      */
-    public $cHash_array = array();
+    public $cHash_array = [];
 
     /**
      * May be set to the pagesTSconfig
@@ -400,10 +391,6 @@ class TypoScriptFrontendController
      *
      * Keys in use:
      *
-     * JSFormValidate: <script type="text/javascript" src="'.$GLOBALS["TSFE"]->absRefPrefix.'typo3/sysext/frontend/Resources/Public/JavaScript/jsfunc.validateform.js"></script>
-     * JSMenuCode, JSMenuCode_menu: JavaScript for the JavaScript menu
-     * JSCode: reserved
-     *
      * used to accumulate additional HTML-code for the header-section,
      * <head>...</head>. Insert either associative keys (like
      * additionalHeaderData['myStyleSheet'], see reserved keys above) or num-keys
@@ -411,13 +398,13 @@ class TypoScriptFrontendController
      *
      * @var array
      */
-    public $additionalHeaderData = array();
+    public $additionalHeaderData = [];
 
     /**
      * Used to accumulate additional HTML-code for the footer-section of the template
      * @var array
      */
-    public $additionalFooterData = array();
+    public $additionalFooterData = [];
 
     /**
      * Used to accumulate additional JavaScript-code. Works like
@@ -425,32 +412,14 @@ class TypoScriptFrontendController
      *
      * @var array
      */
-    public $additionalJavaScript = array();
+    public $additionalJavaScript = [];
 
     /**
      * Used to accumulate additional Style code. Works like additionalHeaderData.
      *
      * @var array
      */
-    public $additionalCSS = array();
-
-    /**
-     * You can add JavaScript functions to each entry in these arrays. Please see
-     * how this is done in the GMENU_LAYERS script. The point is that many
-     * applications on a page can set handlers for onload, onmouseover and onmouseup
-     *
-     * @var array
-     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
-     */
-    public $JSeventFuncCalls = array(
-        'onmousemove' => array(),
-        'onmouseup' => array(),
-        'onkeydown' => array(),
-        'onkeyup' => array(),
-        'onkeypress' => array(),
-        'onload' => array(),
-        'onunload' => array()
-    );
+    public $additionalCSS = [];
 
     /**
      * @var  string
@@ -469,17 +438,10 @@ class TypoScriptFrontendController
     public $divSection = '';
 
     /**
-     * Default bodytag, if nothing else is set. This can be overridden by
-     * applications like TemplaVoila.
-     * @var string
-     */
-    public $defaultBodyTag = '<body>';
-
-    /**
-     * Debug flag, may output special debug html-code.
-     * @var string
+     * Debug flag. If TRUE special debug-output maybe be shown (which includes html-formatting).
+     * @var bool
      */
-    public $debug = '';
+    public $debug = false;
 
     /**
      * Default internal target
@@ -504,7 +466,7 @@ class TypoScriptFrontendController
      * when using the linking features...)
      * @var array
      */
-    public $MP_defaults = array();
+    public $MP_defaults = [];
 
     /**
      * If set, typolink() function encrypts email addresses. Is set in pagegen-class.
@@ -519,12 +481,6 @@ class TypoScriptFrontendController
     public $absRefPrefix = '';
 
     /**
-     * Factor for form-field widths compensation
-     * @var string
-     */
-    public $compensateFieldWidth = '';
-
-    /**
      * Lock file path
      * @var string
      */
@@ -560,14 +516,6 @@ class TypoScriptFrontendController
     public $linkVars = '';
 
     /**
-     * A string set with a comma list of additional GET vars which should NOT be
-     * included in the cHash calculation. These vars should otherwise be detected
-     * and involved in caching, eg. through a condition in TypoScript.
-     * @var string
-     */
-    public $excludeCHashVars = '';
-
-    /**
      * If set, edit icons are rendered aside content records. Must be set only if
      * the ->beUserLogin flag is set and set_no_cache() must be called as well.
      * @var string
@@ -608,7 +556,10 @@ class TypoScriptFrontendController
      * Site content overlay flag; If set - and sys_language_content is > 0 - ,
      * records selected will try to look for a translation pointing to their uid. (If
      * configured in [ctrl][languageField] / [ctrl][transOrigP...]
-     * @var int
+     * Possible values: [0,1,hideNonTranslated]
+     * This flag is set based on TypoScript config.sys_language_overlay setting
+     *
+     * @var int|string
      */
     public $sys_language_contentOL = 0;
 
@@ -624,19 +575,19 @@ class TypoScriptFrontendController
      * extensions.
      * @var array
      */
-    public $applicationData = array();
+    public $applicationData = [];
 
     /**
      * @var array
      */
-    public $register = array();
+    public $register = [];
 
     /**
      * Stack used for storing array and retrieving register arrays (see
      * LOAD_REGISTER and RESTORE_REGISTER)
      * @var array
      */
-    public $registerStack = array();
+    public $registerStack = [];
 
     /**
      * Checking that the function is not called eternally. This is done by
@@ -650,7 +601,7 @@ class TypoScriptFrontendController
      * rendered twice through it!
      * @var array
      */
-    public $recordRegister = array();
+    public $recordRegister = [];
 
     /**
      * This is set to the [table]:[uid] of the latest record rendered. Note that
@@ -666,21 +617,21 @@ class TypoScriptFrontendController
      * to keep track of access-keys.
      * @var array
      */
-    public $accessKey = array();
+    public $accessKey = [];
 
     /**
      * Numerical array where image filenames are added if they are referenced in the
      * rendered document. This includes only TYPO3 generated/inserted images.
      * @var array
      */
-    public $imagesOnPage = array();
+    public $imagesOnPage = [];
 
     /**
      * Is set in ContentObjectRenderer->cImage() function to the info-array of the
      * most recent rendered image. The information is used in ImageTextContentObject
      * @var array
      */
-    public $lastImageInfo = array();
+    public $lastImageInfo = [];
 
     /**
      * Used to generate page-unique keys. Point is that uniqid() functions is very
@@ -715,18 +666,10 @@ class TypoScriptFrontendController
     public $baseUrl = '';
 
     /**
-     * The proper anchor prefix needed when using speaking urls. (only set if
-     * baseUrl is set)
-     * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8, use substr(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), strlen(GeneralUtility::getIndpEnv('TYPO3_SITE_URL'))) directly
-     * @var string
-     */
-    public $anchorPrefix = '';
-
-    /**
      * IDs we already rendered for this page (to make sure they are unique)
      * @var array
      */
-    private $usedUniqueIds = array();
+    private $usedUniqueIds = [];
 
     /**
      * Page content render object
@@ -742,74 +685,25 @@ class TypoScriptFrontendController
     public $content = '';
 
     /**
-     * Set to the browser: net / msie if 4+ browsers
-     * @var string
-     */
-    public $clientInfo = '';
-
-    /**
-     * @var int
-     */
-    public $scriptParseTime = 0;
-
-    /**
-     * Character set (charset) conversion object:
-     * charset conversion class. May be used by any application.
-     *
-     * @var CharsetConverter
-     */
-    public $csConvObj;
-
-    /**
-     * The default charset used in the frontend if nothing else is set.
-     * @var string
-     */
-    public $defaultCharSet = 'utf-8';
-
-    /**
-     * Internal charset of the frontend during rendering. (Default: UTF-8)
-     * @var string
-     */
-    public $renderCharset = 'utf-8';
-
-    /**
      * Output charset of the websites content. This is the charset found in the
-     * header, meta tag etc. If different from $renderCharset a conversion
-     * happens before output to browser. Defaults to ->renderCharset if not set.
+     * header, meta tag etc. If different than utf-8 a conversion
+     * happens before output to browser. Defaults to utf-8.
      * @var string
      */
     public $metaCharset = 'utf-8';
 
     /**
-     * Assumed charset of locale strings.
-     * @var string
-     */
-    public $localeCharset = '';
-
-    /**
      * Set to the system language key (used on the site)
      * @var string
      */
     public $lang = '';
 
     /**
-     * @var array
-     */
-    public $LL_labels_cache = array();
-
-    /**
-     * @var array
-     */
-    public $LL_files_cache = array();
-
-    /**
-     * List of language dependencies for actual language. This is used for local
-     * variants of a language that depend on their "main" language, like Brazilian,
-     * Portuguese or Canadian French.
+     * Internal calculations for labels
      *
-     * @var array
+     * @var LanguageService
      */
-    protected $languageDependencies = array();
+    protected $languageService;
 
     /**
      * @var LockingStrategyInterface[][]
@@ -832,7 +726,7 @@ class TypoScriptFrontendController
     /**
      * @var array
      */
-    protected $pageCacheTags = array();
+    protected $pageCacheTags = [];
 
     /**
      * The cHash Service class used for cHash related functionality
@@ -846,7 +740,7 @@ class TypoScriptFrontendController
      *
      * @var array
      */
-    protected $domainDataCache = array();
+    protected $domainDataCache = [];
 
     /**
      * Content type HTTP header being sent in the request.
@@ -860,8 +754,6 @@ class TypoScriptFrontendController
     /**
      * Doctype to use
      *
-     * Currently set via PageGenerator
-     *
      * @var string
      */
     public $xhtmlDoctype = '';
@@ -879,54 +771,44 @@ class TypoScriptFrontendController
     protected $requestedId;
 
     /**
-     * @var bool
-     */
-    public $dtdAllowsFrames;
-
-    /**
      * Class constructor
      * Takes a number of GET/POST input variable as arguments and stores them internally.
      * The processing of these variables goes on later in this class.
-     * Also sets internal clientInfo array (browser information) and a unique string (->uniqueString) for this script instance; A md5 hash of the microtime()
+     * Also sets a unique string (->uniqueString) for this script instance; A md5 hash of the microtime()
      *
-     * @param array $TYPO3_CONF_VARS The global $TYPO3_CONF_VARS array. Will be set internally in ->TYPO3_CONF_VARS
+     * @param array $_ unused, previously defined to set TYPO3_CONF_VARS
      * @param mixed $id The value of GeneralUtility::_GP('id')
      * @param int $type The value of GeneralUtility::_GP('type')
      * @param bool|string $no_cache The value of GeneralUtility::_GP('no_cache'), evaluated to 1/0
      * @param string $cHash The value of GeneralUtility::_GP('cHash')
-     * @param string $jumpurl The value of GeneralUtility::_GP('jumpurl'), unused since TYPO3 CMS 7. Will have no effect in TYPO3 CMS 8 anymore
+     * @param string $_2 previously was used to define the jumpURL
      * @param string $MP The value of GeneralUtility::_GP('MP')
-     * @param string $RDCT The value of GeneralUtility::_GP('RDCT')
-     * @see index_ts.php
+     * @see \TYPO3\CMS\Frontend\Http\RequestHandler
      */
-    public function __construct($TYPO3_CONF_VARS, $id, $type, $no_cache = '', $cHash = '', $jumpurl = '', $MP = '', $RDCT = '')
+    public function __construct($_ = null, $id, $type, $no_cache = '', $cHash = '', $_2 = null, $MP = '')
     {
         // Setting some variables:
-        $this->TYPO3_CONF_VARS = $TYPO3_CONF_VARS;
         $this->id = $id;
         $this->type = $type;
         if ($no_cache) {
-            if ($this->TYPO3_CONF_VARS['FE']['disableNoCacheParameter']) {
+            if ($GLOBALS['TYPO3_CONF_VARS']['FE']['disableNoCacheParameter']) {
                 $warning = '&no_cache=1 has been ignored because $TYPO3_CONF_VARS[\'FE\'][\'disableNoCacheParameter\'] is set!';
                 $this->getTimeTracker()->setTSlogMessage($warning, 2);
             } else {
                 $warning = '&no_cache=1 has been supplied, so caching is disabled! URL: "' . GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL') . '"';
                 $this->disableCache();
             }
-            GeneralUtility::sysLog($warning, 'cms', GeneralUtility::SYSLOG_SEVERITY_WARNING);
+            // note: we need to instantiate the logger manually here since the injection happens after the constructor
+            GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__)->warning($warning);
         }
         $this->cHash = $cHash;
-        $this->jumpurl = $jumpurl;
-        $this->MP = $this->TYPO3_CONF_VARS['FE']['enable_mount_pids'] ? (string)$MP : '';
-        $this->RDCT = $RDCT;
-        $this->clientInfo = GeneralUtility::clientInfo();
+        $this->MP = $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] ? (string)$MP : '';
         $this->uniqueString = md5(microtime());
-        $this->csConvObj = GeneralUtility::makeInstance(CharsetConverter::class);
         $this->initPageRenderer();
         // Call post processing function for constructor:
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -944,7 +826,6 @@ class TypoScriptFrontendController
         }
         $this->pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
         $this->pageRenderer->setTemplateFile('EXT:frontend/Resources/Private/Templates/MainPage.html');
-        $this->pageRenderer->setBackPath(TYPO3_mainDir);
     }
 
     /**
@@ -962,82 +843,31 @@ class TypoScriptFrontendController
      *
      * @throws \RuntimeException
      * @throws ServiceUnavailableException
-     * @return void
      */
     public function connectToDB()
     {
+        $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages');
         try {
-            $this->getDatabaseConnection()->connectDB();
-        } catch (\RuntimeException $exception) {
-            switch ($exception->getCode()) {
-                case 1270853883:
-                    // Cannot connect to current database
-                    $message = 'Cannot connect to the configured database "' . TYPO3_db . '"';
-                    if ($this->checkPageUnavailableHandler()) {
-                        $this->pageUnavailableAndExit($message);
-                    } else {
-                        GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
-                        throw new ServiceUnavailableException($message, 1301648782);
-                    }
-                    break;
-                case 1270853884:
-                    // Username / password not accepted
-                    $message = 'The current username, password or host was not accepted when' . ' the connection to the database was attempted to be established!';
-                    if ($this->checkPageUnavailableHandler()) {
-                        $this->pageUnavailableAndExit($message);
-                    } else {
-                        GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
-                        throw new ServiceUnavailableException('Database Error: ' . $message, 1301648945);
-                    }
-                    break;
-                default:
-                    throw $exception;
+            $connection->connect();
+        } catch (ConnectionException $exception) {
+            // Cannot connect to current database
+            $message = 'Cannot connect to the configured database "' . $connection->getDatabase() . '"';
+            if ($this->checkPageUnavailableHandler()) {
+                $this->pageUnavailableAndExit($message);
+            } else {
+                $this->logger->emergency($message, ['exception' => $exception]);
+                throw new ServiceUnavailableException($message, 1301648782);
             }
         }
         // Call post processing function for DB connection:
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
     }
 
-    /**
-     * Looks up the value of $this->RDCT in the database and if it is
-     * found to be associated with a redirect URL then the redirection
-     * is carried out with a 'Location:' header
-     * May exit after sending a location-header.
-     *
-     * @return void
-     */
-    public function sendRedirect()
-    {
-        if ($this->RDCT) {
-            $db = $this->getDatabaseConnection();
-            $row = $db->exec_SELECTgetSingleRow('params', 'cache_md5params', 'md5hash=' . $db->fullQuoteStr($this->RDCT, 'cache_md5params'));
-            if ($row) {
-                $this->updateMD5paramsRecord($this->RDCT);
-                header('Location: ' . $row['params']);
-                die;
-            }
-        }
-    }
-
-    /**
-     * Gets instance of PageRenderer
-     *
-     * @return PageRenderer
-     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8.
-     */
-    public function getPageRenderer()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        $this->initPageRenderer();
-
-        return $this->pageRenderer;
-    }
-
     /********************************************
      *
      * Initializing, resolving page id
@@ -1045,8 +875,6 @@ class TypoScriptFrontendController
      ********************************************/
     /**
      * Initializes the caching system.
-     *
-     * @return void
      */
     protected function initCaches()
     {
@@ -1055,23 +883,18 @@ class TypoScriptFrontendController
 
     /**
      * Initializes the front-end login user.
-     *
-     * @return void
      */
     public function initFEuser()
     {
         $this->fe_user = GeneralUtility::makeInstance(FrontendUserAuthentication::class);
-        $this->fe_user->lockIP = $this->TYPO3_CONF_VARS['FE']['lockIP'];
-        $this->fe_user->checkPid = $this->TYPO3_CONF_VARS['FE']['checkFeUserPid'];
-        $this->fe_user->lifetime = (int)$this->TYPO3_CONF_VARS['FE']['lifetime'];
         // List of pid's acceptable
         $pid = GeneralUtility::_GP('pid');
-        $this->fe_user->checkPid_value = $pid ? $this->getDatabaseConnection()->cleanIntList($pid) : 0;
+        $this->fe_user->checkPid_value = $pid ? implode(',', GeneralUtility::intExplode(',', $pid)) : 0;
         // Check if a session is transferred:
         if (GeneralUtility::_GP('FE_SESSION_KEY')) {
             $fe_sParts = explode('-', GeneralUtility::_GP('FE_SESSION_KEY'));
             // If the session key hash check is OK:
-            if (md5(($fe_sParts[0] . '/' . $this->TYPO3_CONF_VARS['SYS']['encryptionKey'])) === (string)$fe_sParts[1]) {
+            if (md5(($fe_sParts[0] . '/' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'])) === (string)$fe_sParts[1]) {
                 $cookieName = FrontendUserAuthentication::getCookieName();
                 $_COOKIE[$cookieName] = $fe_sParts[0];
                 if (isset($_SERVER['HTTP_COOKIE'])) {
@@ -1084,32 +907,34 @@ class TypoScriptFrontendController
             }
         }
         $this->fe_user->start();
-        $this->fe_user->unpack_uc('');
-        // Gets session data
-        $this->fe_user->fetchSessionData();
-        $recs = GeneralUtility::_GP('recs');
-        // If any record registration is submitted, register the record.
-        if (is_array($recs)) {
-            $this->fe_user->record_registration($recs, $this->TYPO3_CONF_VARS['FE']['maxSessionDataSize']);
-        }
+        $this->fe_user->unpack_uc();
+
         // Call hook for possible manipulation of frontend user object
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
         // For every 60 seconds the is_online timestamp is updated.
         if (is_array($this->fe_user->user) && $this->fe_user->user['uid'] && $this->fe_user->user['is_online'] < $GLOBALS['EXEC_TIME'] - 60) {
-            $this->getDatabaseConnection()->exec_UPDATEquery('fe_users', 'uid=' . (int)$this->fe_user->user['uid'], array('is_online' => $GLOBALS['EXEC_TIME']));
+            $dbConnection = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getConnectionForTable('fe_users');
+            $dbConnection->update(
+                'fe_users',
+                [
+                    'is_online' => $GLOBALS['EXEC_TIME']
+                ],
+                [
+                    'uid' => (int)$this->fe_user->user['uid']
+                ]
+            );
         }
     }
 
     /**
      * Initializes the front-end user groups.
      * Sets ->loginUser and ->gr_list based on front-end user status.
-     *
-     * @return void
      */
     public function initUserGroups()
     {
@@ -1132,7 +957,7 @@ class TypoScriptFrontendController
                 $gr_array = $this->fe_user->groupData['uid'];
             } else {
                 // Set to blank since we will NOT risk any groups being set when no logins are allowed!
-                $gr_array = array();
+                $gr_array = [];
             }
         }
         // Clean up.
@@ -1143,9 +968,7 @@ class TypoScriptFrontendController
         if (!empty($gr_array) && !$this->loginAllowedInBranch_mode) {
             $this->gr_list .= ',' . implode(',', $gr_array);
         }
-        if ($this->fe_user->writeDevLog) {
-            GeneralUtility::devLog('Valid usergroups for TSFE: ' . $this->gr_list, __CLASS__);
-        }
+        $this->logger->debug('Valid usergroups for TSFE: ' . $this->gr_list);
     }
 
     /**
@@ -1164,16 +987,14 @@ class TypoScriptFrontendController
      * Two options:
      * 1) Use PATH_INFO (also Apache) to extract id and type from that var. Does not require any special modules compiled with apache. (less typical)
      * 2) Using hook which enables features like those provided from "realurl" extension (AKA "Speaking URLs")
-     *
-     * @return void
      */
     public function checkAlternativeIdMethods()
     {
         $this->siteScript = GeneralUtility::getIndpEnv('TYPO3_SITE_SCRIPT');
         // Call post processing function for custom URL methods.
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -1183,8 +1004,6 @@ class TypoScriptFrontendController
      * Clears the preview-flags, sets sim_exec_time to current time.
      * Hidden pages must be hidden as default, $GLOBALS['SIM_EXEC_TIME'] is set to $GLOBALS['EXEC_TIME']
      * in bootstrap initializeGlobalTimeVariables(). Alter it by adding or subtracting seconds.
-     *
-     * @return void
      */
     public function clear_preview()
     {
@@ -1213,53 +1032,48 @@ class TypoScriptFrontendController
     public function initializeBackendUser()
     {
         // PRE BE_USER HOOK
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['preBeUser'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['preBeUser'] as $_funcRef) {
-                $_params = array();
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preBeUser'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preBeUser'] as $_funcRef) {
+                $_params = [];
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
-        /** @var $BE_USER FrontendBackendUserAuthentication */
-        $BE_USER = null;
+        $backendUserObject = null;
         // If the backend cookie is set,
         // we proceed and check if a backend user is logged in.
         if ($_COOKIE[BackendUserAuthentication::getCookieName()]) {
             $GLOBALS['TYPO3_MISC']['microtime_BE_USER_start'] = microtime(true);
             $this->getTimeTracker()->push('Back End user initialized', '');
-            // @todo validate the comment below: is this necessary? if so,
-            //   formfield_status should be set to "" in \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
-            //   which is a subclass of \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
-            // ----
-            // the value this->formfield_status is set to empty in order to
-            // disable login-attempts to the backend account through this script
+            $this->beUserLogin = false;
             // New backend user object
-            $BE_USER = GeneralUtility::makeInstance(FrontendBackendUserAuthentication::class);
-            $BE_USER->lockIP = $this->TYPO3_CONF_VARS['BE']['lockIP'];
-            // Object is initialized
-            $BE_USER->start();
-            $BE_USER->unpack_uc('');
-            if (!empty($BE_USER->user['uid'])) {
-                $BE_USER->fetchGroupData();
+            $backendUserObject = GeneralUtility::makeInstance(FrontendBackendUserAuthentication::class);
+            $backendUserObject->start();
+            $backendUserObject->unpack_uc();
+            if (!empty($backendUserObject->user['uid'])) {
+                $backendUserObject->fetchGroupData();
+            }
+            // Unset the user initialization if any setting / restriction applies
+            if (!$backendUserObject->checkBackendAccessSettingsFromInitPhp()) {
+                $backendUserObject = null;
+            } elseif (!empty($backendUserObject->user['uid'])) {
+                // If the user is active now, let the controller know
                 $this->beUserLogin = true;
-            }
-            // Unset the user initialization.
-            if (!$BE_USER->checkLockToIP() || !$BE_USER->checkBackendAccessSettingsFromInitPhp() || empty($BE_USER->user['uid'])) {
-                $BE_USER = null;
-                $this->beUserLogin = false;
+            } else {
+                $backendUserObject = null;
             }
             $this->getTimeTracker()->pull();
             $GLOBALS['TYPO3_MISC']['microtime_BE_USER_end'] = microtime(true);
         }
         // POST BE_USER HOOK
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['postBeUser'])) {
-            $_params = array(
-                'BE_USER' => &$BE_USER
-            );
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['postBeUser'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['postBeUser'])) {
+            $_params = [
+                'BE_USER' => &$backendUserObject
+            ];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['postBeUser'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
-        return $BE_USER;
+        return $backendUserObject;
     }
 
     /**
@@ -1267,20 +1081,16 @@ class TypoScriptFrontendController
      * Basically this function is about determining whether a backend user is logged in,
      * if he has read access to the page and if he's previewing the page.
      * That all determines which id to show and how to initialize the id.
-     *
-     * @return void
      */
     public function determineId()
     {
         // Call pre processing function for id determination
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PreProcessing'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PreProcessing'] as $functionReference) {
-                $parameters = array('parentObject' => $this);
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PreProcessing'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PreProcessing'] as $functionReference) {
+                $parameters = ['parentObject' => $this];
                 GeneralUtility::callUserFunction($functionReference, $parameters, $this);
             }
         }
-        // Getting ARG-v values if some
-        $this->setIDfromArgV();
         // If there is a Backend login we are going to check for any preview settings:
         $this->getTimeTracker()->push('beUserLogin', '');
         $originalFrontendUser = null;
@@ -1288,7 +1098,7 @@ class TypoScriptFrontendController
         if ($this->beUserLogin || $this->doWorkspacePreview()) {
             // Backend user preview features:
             if ($this->beUserLogin && $backendUser->adminPanel instanceof AdminPanelView) {
-                $this->fePreview = (bool)$backendUser->adminPanel->extGetFeAdminValue('preview');
+                $this->fePreview = (int)$backendUser->adminPanel->extGetFeAdminValue('preview');
                 // If admin panel preview is enabled...
                 if ($this->fePreview) {
                     if ($this->fe_user->user) {
@@ -1309,9 +1119,9 @@ class TypoScriptFrontendController
                         if ($this->fe_user->user) {
                             $this->fe_user->user[$this->fe_user->usergroup_column] = $simUserGroup;
                         } else {
-                            $this->fe_user->user = array(
+                            $this->fe_user->user = [
                                 $this->fe_user->usergroup_column => $simUserGroup
-                            );
+                            ];
                         }
                     }
                     if (!$simUserGroup && !$simTime && !$this->showHiddenPage && !$this->showHiddenRecords) {
@@ -1319,27 +1129,10 @@ class TypoScriptFrontendController
                     }
                 }
             }
-            if ($this->id) {
-                if ($this->determineIdIsHiddenPage()) {
-                    // The preview flag is set only if the current page turns out to actually be hidden!
-                    $this->fePreview = 1;
-                    $this->showHiddenPage = true;
-                }
-                // For Live workspace: Check root line for proper connection to tree root (done because of possible preview of page / branch versions)
-                if (!$this->fePreview && $this->whichWorkspace() === 0) {
-                    // Initialize the page-select functions to check rootline:
-                    $temp_sys_page = GeneralUtility::makeInstance(PageRepository::class);
-                    $temp_sys_page->init($this->showHiddenPage);
-                    // If root line contained NO records and ->error_getRootLine_failPid tells us that it was because of a pid=-1 (indicating a "version" record)...:
-                    if (empty($temp_sys_page->getRootLine($this->id, $this->MP)) && $temp_sys_page->error_getRootLine_failPid == -1) {
-                        // Setting versioningPreview flag and try again:
-                        $temp_sys_page->versioningPreview = true;
-                        if (!empty($temp_sys_page->getRootLine($this->id, $this->MP))) {
-                            // Finally, we got a root line (meaning that it WAS due to versioning preview of a page somewhere) and we set the fePreview flag which in itself will allow sys_page class to display previews of versionized records.
-                            $this->fePreview = 1;
-                        }
-                    }
-                }
+            if ($this->id && $this->determineIdIsHiddenPage()) {
+                // The preview flag is set only if the current page turns out to actually be hidden!
+                $this->fePreview = 1;
+                $this->showHiddenPage = true;
             }
             // The preview flag will be set if a backend user is in an offline workspace
             if (
@@ -1381,7 +1174,7 @@ class TypoScriptFrontendController
         if (!$this->loginAllowedInBranch) {
             // Only if there is a login will we run this...
             if ($this->isUserOrGroupSet()) {
-                if ($this->loginAllowedInBranch_mode == 'all') {
+                if ($this->loginAllowedInBranch_mode === 'all') {
                     // Clear out user and group:
                     $this->fe_user->hideActiveLogin();
                     $this->gr_list = '0,-1';
@@ -1398,9 +1191,9 @@ class TypoScriptFrontendController
         // Make sure it's an integer
         $this->type = (int)$this->type;
         // Call post processing function for id determination:
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PostProc'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PostProc'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PostProc'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PostProc'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -1415,8 +1208,25 @@ class TypoScriptFrontendController
     protected function determineIdIsHiddenPage()
     {
         $field = MathUtility::canBeInterpretedAsInteger($this->id) ? 'uid' : 'alias';
-        $pageSelectCondition = $field . '=' . $this->getDatabaseConnection()->fullQuoteStr($this->id, 'pages');
-        $page = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid,hidden,starttime,endtime', 'pages', $pageSelectCondition . ' AND pid>=0 AND deleted=0');
+
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable('pages');
+        $queryBuilder
+            ->getRestrictions()
+            ->removeAll()
+            ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
+
+        $page = $queryBuilder
+            ->select('uid', 'hidden', 'starttime', 'endtime')
+            ->from('pages')
+            ->where(
+                $queryBuilder->expr()->eq($field, $queryBuilder->createNamedParameter($this->id)),
+                $queryBuilder->expr()->gte('pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
+            )
+            ->setMaxResults(1)
+            ->execute()
+            ->fetch();
+
         $workspace = $this->whichWorkspace();
         if ($workspace !== 0 && $workspace !== false) {
             // Fetch overlay of page if in workspace and check if it is hidden
@@ -1432,12 +1242,65 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Get The Page ID
-     * This gets the id of the page, checks if the page is in the domain and if the page is accessible
-     * Sets variables such as $this->sys_page, $this->loginUser, $this->gr_list, $this->id, $this->type, $this->domainStartPage
+     * Resolves the page id and sets up several related properties.
+     *
+     * If $this->id is not set at all or is not a plain integer, the method
+     * does it's best to set the value to an integer. Resolving is based on
+     * this options:
+     *
+     * - Splitting $this->id if it contains an additional type parameter.
+     * - Getting the id for an alias in $this->id
+     * - Finding the domain record start page
+     * - First visible page
+     * - Relocating the id below the domain record if outside
+     *
+     * The following properties may be set up or updated:
+     *
+     * - id
+     * - requestedId
+     * - type
+     * - domainStartPage
+     * - sys_page
+     * - sys_page->where_groupAccess
+     * - sys_page->where_hid_del
+     * - loginUser
+     * - gr_list
+     * - no_cache
+     * - register['SYS_LASTCHANGED']
+     * - pageNotFound
+     *
+     * Via getPageAndRootlineWithDomain()
+     *
+     * - rootLine
+     * - page
+     * - MP
+     * - originalShortcutPage
+     * - originalMountPointPage
+     * - pageAccessFailureHistory['direct_access']
+     * - pageNotFound
+     *
+     * @todo:
+     *
+     * On the first impression the method does to much. This is increased by
+     * the fact, that is is called repeated times by the method determineId.
+     * The reasons are manifold.
+     *
+     * 1.) The first part, the creation of sys_page, the type and alias
+     * resolution don't need to be repeated. They could be separated to be
+     * called only once.
+     *
+     * 2.) The user group setup could be done once on a higher level.
+     *
+     * 3.) The workflow of the resolution could be elaborated to be less
+     * tangled. Maybe the check of the page id to be below the domain via the
+     * root line doesn't need to be done each time, but for the final result
+     * only.
+     *
+     * 4.) The root line does not need to be directly addressed by this class.
+     * A root line is always related to one page. The rootline could be handled
+     * indirectly by page objects. Page objects still don't exist.
      *
      * @throws ServiceUnavailableException
-     * @return void
      * @access private
      */
     public function fetch_the_id()
@@ -1470,7 +1333,7 @@ class TypoScriptFrontendController
         // We find the first page belonging to the current domain
         $timeTracker->push('fetch_the_id domain/', '');
         // The page_id of the current domain
-        $this->domainStartPage = $this->findDomainRecord($this->TYPO3_CONF_VARS['SYS']['recursiveDomainSearch']);
+        $this->domainStartPage = $this->findDomainRecord($GLOBALS['TYPO3_CONF_VARS']['SYS']['recursiveDomainSearch']);
         if (!$this->id) {
             if ($this->domainStartPage) {
                 // If the id was not previously set, set it to the id of the domain.
@@ -1485,7 +1348,7 @@ class TypoScriptFrontendController
                     if ($this->checkPageUnavailableHandler()) {
                         $this->pageUnavailableAndExit($message);
                     } else {
-                        GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                        $this->logger->alert($message);
                         throw new ServiceUnavailableException($message, 1301648975);
                     }
                 }
@@ -1497,32 +1360,15 @@ class TypoScriptFrontendController
         $this->requestedId = $this->id;
         $this->getPageAndRootlineWithDomain($this->domainStartPage);
         $timeTracker->pull();
-        if ($this->pageNotFound && $this->TYPO3_CONF_VARS['FE']['pageNotFound_handling']) {
-            $pNotFoundMsg = array(
+        if ($this->pageNotFound && $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling']) {
+            $pNotFoundMsg = [
                 1 => 'ID was not an accessible page',
                 2 => 'Subsection was found and not accessible',
                 3 => 'ID was outside the domain',
                 4 => 'The requested page alias does not exist'
-            );
+            ];
             $this->pageNotFoundAndExit($pNotFoundMsg[$this->pageNotFound]);
         }
-        if ($this->page['url_scheme'] > 0) {
-            $newUrl = '';
-            $requestUrlScheme = parse_url(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), PHP_URL_SCHEME);
-            if ((int)$this->page['url_scheme'] === HttpUtility::SCHEME_HTTP && $requestUrlScheme == 'https') {
-                $newUrl = 'http://' . substr(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), 8);
-            } elseif ((int)$this->page['url_scheme'] === HttpUtility::SCHEME_HTTPS && $requestUrlScheme == 'http') {
-                $newUrl = 'https://' . substr(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), 7);
-            }
-            if ($newUrl !== '') {
-                if ($_SERVER['REQUEST_METHOD'] === 'POST') {
-                    $headerCode = HttpUtility::HTTP_STATUS_303;
-                } else {
-                    $headerCode = HttpUtility::HTTP_STATUS_301;
-                }
-                HttpUtility::redirect($newUrl, $headerCode);
-            }
-        }
         // Set no_cache if set
         if ($this->page['no_cache']) {
             $this->set_no_cache('no_cache is set in page properties');
@@ -1532,27 +1378,61 @@ class TypoScriptFrontendController
         if ($this->register['SYS_LASTCHANGED'] < (int)$this->page['SYS_LASTCHANGED']) {
             $this->register['SYS_LASTCHANGED'] = (int)$this->page['SYS_LASTCHANGED'];
         }
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['fetchPageId-PostProcessing'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['fetchPageId-PostProcessing'] as $functionReference) {
-                $parameters = array('parentObject' => $this);
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['fetchPageId-PostProcessing'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['fetchPageId-PostProcessing'] as $functionReference) {
+                $parameters = ['parentObject' => $this];
                 GeneralUtility::callUserFunction($functionReference, $parameters, $this);
             }
         }
     }
 
     /**
-     * Gets the page and rootline arrays based on the id, $this->id
+     * Loads the page and root line records based on $this->id
+     *
+     * A final page and the matching root line are determined and loaded by
+     * the algorithm defined by this method.
      *
-     * If the id does not correspond to a proper page, the 'previous' valid page in the rootline is found
-     * If the page is a shortcut (doktype=4), the ->id is loaded with that id
+     * First it loads the initial page from the page repository for $this->id.
+     * If that can't be loaded directly, it gets the root line for $this->id.
+     * It walks up the root line towards the root page until the page
+     * repository can deliver a page record. (The loading restrictions of
+     * the root line records are more liberal than that of the page record.)
      *
-     * Whether or not the ->id is changed to the shortcut id or the previous id in rootline (eg if a page is hidden), the ->page-array and ->rootline is found and must also be valid.
+     * Now the page type is evaluated and handled if necessary. If the page is
+     * a short cut, it is replaced by the target page. If the page is a mount
+     * point in overlay mode, the page is replaced by the mounted page.
      *
-     * Sets or manipulates internal variables such as: $this->id, $this->page, $this->rootLine, $this->MP, $this->pageNotFound
+     * After this potential replacements are done, the root line is loaded
+     * (again) for this page record. It walks up the root line up to
+     * the first viewable record.
+     *
+     * (While upon the first accessibility check of the root line it was done
+     * by loading page by page from the page repository, this time the method
+     * checkRootlineForIncludeSection() is used to find the most distant
+     * accessible page within the root line.)
+     *
+     * Having found the final page id, the page record and the root line are
+     * loaded for last time by this method.
+     *
+     * Exceptions may be thrown for DOKTYPE_SPACER and not loadable page records
+     * or root lines.
+     *
+     * If $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'] is set,
+     * instead of throwing an exception it's handled by a page unavailable
+     * handler.
+     *
+     * May set or update this properties:
+     *
+     * @see TypoScriptFrontendController::$id
+     * @see TypoScriptFrontendController::$MP
+     * @see TypoScriptFrontendController::$page
+     * @see TypoScriptFrontendController::$pageNotFound
+     * @see TypoScriptFrontendController::$pageAccessFailureHistory
+     * @see TypoScriptFrontendController::$originalMountPointPage
+     * @see TypoScriptFrontendController::$originalShortcutPage
      *
      * @throws ServiceUnavailableException
      * @throws PageNotFoundException
-     * @return void
      * @access private
      */
     public function getPageAndRootline()
@@ -1580,10 +1460,10 @@ class TypoScriptFrontendController
             // If still no page...
             if (empty($this->page)) {
                 $message = 'The requested page does not exist!';
-                if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling']) {
+                if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling']) {
                     $this->pageNotFoundAndExit($message);
                 } else {
-                    GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                    $this->logger->error($message);
                     throw new PageNotFoundException($message, 1301648780);
                 }
             }
@@ -1591,10 +1471,10 @@ class TypoScriptFrontendController
         // Spacer is not accessible in frontend
         if ($this->page['doktype'] == PageRepository::DOKTYPE_SPACER) {
             $message = 'The requested page does not exist!';
-            if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling']) {
+            if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling']) {
                 $this->pageNotFoundAndExit($message);
             } else {
-                GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                $this->logger->error($message);
                 throw new PageNotFoundException($message, 1301648781);
             }
         }
@@ -1628,23 +1508,13 @@ class TypoScriptFrontendController
         $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
         // If not rootline we're off...
         if (empty($this->rootLine)) {
-            $ws = $this->whichWorkspace();
-            if ($this->sys_page->error_getRootLine_failPid == -1 && $ws) {
-                $this->sys_page->versioningPreview = true;
-                $this->sys_page->versioningWorkspaceId = $ws;
-                $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
-            }
-            if (empty($this->rootLine)) {
-                $message = 'The requested page didn\'t have a proper connection to the tree-root!';
-                if ($this->checkPageUnavailableHandler()) {
-                    $this->pageUnavailableAndExit($message);
-                } else {
-                    $rootline = '(' . $this->sys_page->error_getRootLine . ')';
-                    GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
-                    throw new ServiceUnavailableException($message . '<br /><br />' . $rootline, 1301648167);
-                }
+            $message = 'The requested page didn\'t have a proper connection to the tree-root!';
+            if ($this->checkPageUnavailableHandler()) {
+                $this->pageUnavailableAndExit($message);
+            } else {
+                $this->logger->error($message);
+                throw new ServiceUnavailableException($message, 1301648167);
             }
-            $this->fePreview = 1;
         }
         // Checking for include section regarding the hidden/starttime/endtime/fe_user (that is access control of a whole subbranch!)
         if ($this->checkRootlineForIncludeSection()) {
@@ -1653,7 +1523,7 @@ class TypoScriptFrontendController
                 if ($this->checkPageUnavailableHandler()) {
                     $this->pageUnavailableAndExit($message);
                 } else {
-                    GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                    $this->logger->warning($message);
                     throw new ServiceUnavailableException($message, 1301648234);
                 }
             } else {
@@ -1680,7 +1550,7 @@ class TypoScriptFrontendController
      * @access private
      * @see getPageAndRootline()
      */
-    public function getPageShortcut($SC, $mode, $thisUid, $itera = 20, $pageLog = array(), $disableGroupCheck = false)
+    public function getPageShortcut($SC, $mode, $thisUid, $itera = 20, $pageLog = [], $disableGroupCheck = false)
     {
         $idArray = GeneralUtility::intExplode(',', $SC);
         // Find $page record depending on shortcut mode:
@@ -1695,9 +1565,9 @@ class TypoScriptFrontendController
                     $pO = $randval;
                 }
                 $c = 0;
-                $page = array();
+                $page = [];
                 foreach ($pageArray as $pV) {
-                    if ($c == $pO) {
+                    if ($c === $pO) {
                         $page = $pV;
                         break;
                     }
@@ -1731,7 +1601,7 @@ class TypoScriptFrontendController
             } else {
                 $pageLog[] = $page['uid'];
                 $message = 'Page shortcuts were looping in uids ' . implode(',', $pageLog) . '...!';
-                GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                $this->logger->error($message);
                 throw new \RuntimeException($message, 1294587212);
             }
         }
@@ -1755,17 +1625,37 @@ class TypoScriptFrontendController
                 $this->pageAccessFailureHistory['sub_section'][] = $this->rootLine[$a];
                 $removeTheRestFlag = 1;
             }
+
             if ($this->rootLine[$a]['doktype'] == PageRepository::DOKTYPE_BE_USER_SECTION) {
                 // If there is a backend user logged in, check if he has read access to the page:
                 if ($this->beUserLogin) {
-                    $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid', 'pages', 'uid=' . (int)$this->id . ' AND ' . $this->getBackendUser()->getPagePermsClause(1));
+                    $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+                        ->getQueryBuilderForTable('pages');
+
+                    $queryBuilder
+                        ->getRestrictions()
+                        ->removeAll();
+
+                    $row = $queryBuilder
+                        ->select('uid')
+                        ->from('pages')
+                        ->where(
+                            $queryBuilder->expr()->eq(
+                                'uid',
+                                $queryBuilder->createNamedParameter($this->id, \PDO::PARAM_INT)
+                            ),
+                            $this->getBackendUser()->getPagePermsClause(1)
+                        )
+                        ->execute()
+                        ->fetch();
+
                     // versionOL()?
                     if (!$row) {
                         // If there was no page selected, the user apparently did not have read access to the current PAGE (not position in rootline) and we set the remove-flag...
                         $removeTheRestFlag = 1;
                     }
                 } else {
-                    // Dont go here, if there is no backend user logged in.
+                    // Don't go here, if there is no backend user logged in.
                     $removeTheRestFlag = 1;
                 }
             }
@@ -1786,13 +1676,13 @@ class TypoScriptFrontendController
      * @param array $row The page record to evaluate (needs fields: hidden, starttime, endtime, fe_group)
      * @param bool $bypassGroupCheck Bypass group-check
      * @return bool TRUE, if record is viewable.
-     * @see TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer::getTreeList(), checkPagerecordForIncludeSection()
+     * @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getTreeList(), checkPagerecordForIncludeSection()
      */
     public function checkEnableFields($row, $bypassGroupCheck = false)
     {
-        if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields'])) {
-            $_params = array('pObj' => $this, 'row' => &$row, 'bypassGroupCheck' => &$bypassGroupCheck);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields'] as $_funcRef) {
+        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields'])) {
+            $_params = ['pObj' => $this, 'row' => &$row, 'bypassGroupCheck' => &$bypassGroupCheck];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields'] as $_funcRef) {
                 // Call hooks: If one returns FALSE, method execution is aborted with result "This record is not available"
                 $return = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
                 if ($return === false) {
@@ -1832,7 +1722,7 @@ class TypoScriptFrontendController
      * @param array $row The page record to evaluate (needs fields: extendToSubpages + hidden, starttime, endtime, fe_group)
      * @return bool Returns TRUE if either extendToSubpages is not checked or if the enableFields does not disable the page record.
      * @access private
-     * @see checkEnableFields(), TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer::getTreeList(), checkRootlineForIncludeSection()
+     * @see checkEnableFields(), \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::getTreeList(), checkRootlineForIncludeSection()
      */
     public function checkPagerecordForIncludeSection($row)
     {
@@ -1848,24 +1738,24 @@ class TypoScriptFrontendController
     {
         // Initialize:
         $c = count($this->rootLine);
-        $disable = false;
+        $loginAllowed = true;
         // Traverse root line from root and outwards:
         for ($a = 0; $a < $c; $a++) {
             // If a value is set for login state:
             if ($this->rootLine[$a]['fe_login_mode'] > 0) {
                 // Determine state from value:
                 if ((int)$this->rootLine[$a]['fe_login_mode'] === 1) {
-                    $disable = true;
+                    $loginAllowed = false;
                     $this->loginAllowedInBranch_mode = 'all';
                 } elseif ((int)$this->rootLine[$a]['fe_login_mode'] === 3) {
-                    $disable = true;
+                    $loginAllowed = false;
                     $this->loginAllowedInBranch_mode = 'groups';
                 } else {
-                    $disable = false;
+                    $loginAllowed = true;
                 }
             }
         }
-        return !$disable;
+        return $loginAllowed;
     }
 
     /**
@@ -1875,8 +1765,8 @@ class TypoScriptFrontendController
      */
     public function getPageAccessFailureReasons()
     {
-        $output = array();
-        $combinedRecords = array_merge(is_array($this->pageAccessFailureHistory['direct_access']) ? $this->pageAccessFailureHistory['direct_access'] : array(array('fe_group' => 0)), is_array($this->pageAccessFailureHistory['sub_section']) ? $this->pageAccessFailureHistory['sub_section'] : array());
+        $output = [];
+        $combinedRecords = array_merge(is_array($this->pageAccessFailureHistory['direct_access']) ? $this->pageAccessFailureHistory['direct_access'] : [['fe_group' => 0]], is_array($this->pageAccessFailureHistory['sub_section']) ? $this->pageAccessFailureHistory['sub_section'] : []);
         if (!empty($combinedRecords)) {
             foreach ($combinedRecords as $k => $pagerec) {
                 // If $k=0 then it is the very first page the original ID was pointing at and that will get a full check of course
@@ -1901,28 +1791,10 @@ class TypoScriptFrontendController
     }
 
     /**
-     * This checks if there are ARGV-parameters in the QUERY_STRING and if so, those are used for the id
-     * $this->id must be 'FALSE' in order for any processing to happen in here
-     * If an id/alias value is extracted from the QUERY_STRING it is set in $this->id
-     *
-     * @return void
-     * @access private
-     */
-    public function setIDfromArgV()
-    {
-        if (!$this->id) {
-            list($theAlias) = explode('&', GeneralUtility::getIndpEnv('QUERY_STRING'));
-            $theAlias = trim($theAlias);
-            $this->id = $theAlias != '' && strpos($theAlias, '=') === false ? $theAlias : 0;
-        }
-    }
-
-    /**
      * Gets ->page and ->rootline information based on ->id. ->id may change during this operation.
      * If not inside domain, then default to first page in domain.
      *
      * @param int $domainStartPage Page uid of the page where the found domain record is (pid of the domain record)
-     * @return void
      * @access private
      */
     public function getPageAndRootlineWithDomain($domainStartPage)
@@ -1950,12 +1822,17 @@ class TypoScriptFrontendController
     /**
      * Sets sys_page where-clause
      *
-     * @return void
      * @access private
      */
     public function setSysPageWhereClause()
     {
-        $this->sys_page->where_hid_del .= ' AND pages.doktype<200';
+        $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getConnectionForTable('pages')
+            ->getExpressionBuilder();
+        $this->sys_page->where_hid_del = ' AND ' . (string)$expressionBuilder->andX(
+            QueryHelper::stripLogicalOperatorPrefix($this->sys_page->where_hid_del),
+            $expressionBuilder->lt('pages.doktype', 200)
+        );
         $this->sys_page->where_groupAccess = $this->sys_page->getMultipleGroupsWhereClause('pages.fe_group', 'pages');
     }
 
@@ -1975,14 +1852,12 @@ class TypoScriptFrontendController
                 $pageUid = $this->sys_page->getDomainStartPage(implode('.', $host), GeneralUtility::getIndpEnv('SCRIPT_NAME'), GeneralUtility::getIndpEnv('REQUEST_URI'));
                 if ($pageUid) {
                     return $pageUid;
-                } else {
-                    array_shift($host);
                 }
+                array_shift($host);
             }
             return $pageUid;
-        } else {
-            return $this->sys_page->getDomainStartPage(GeneralUtility::getIndpEnv('HTTP_HOST'), GeneralUtility::getIndpEnv('SCRIPT_NAME'), GeneralUtility::getIndpEnv('REQUEST_URI'));
         }
+        return $this->sys_page->getDomainStartPage(GeneralUtility::getIndpEnv('HTTP_HOST'), GeneralUtility::getIndpEnv('SCRIPT_NAME'), GeneralUtility::getIndpEnv('REQUEST_URI'));
     }
 
     /**
@@ -1990,12 +1865,11 @@ class TypoScriptFrontendController
      *
      * @param string $reason Reason text
      * @param string $header HTTP header to send
-     * @return void Function exits.
      */
     public function pageUnavailableAndExit($reason = '', $header = '')
     {
-        $header = $header ?: $this->TYPO3_CONF_VARS['FE']['pageUnavailable_handling_statheader'];
-        $this->pageUnavailableHandler($this->TYPO3_CONF_VARS['FE']['pageUnavailable_handling'], $header, $reason);
+        $header = $header ?: $GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling_statheader'];
+        $this->pageUnavailableHandler($GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling'], $header, $reason);
         die;
     }
 
@@ -2004,12 +1878,11 @@ class TypoScriptFrontendController
      *
      * @param string $reason Reason text
      * @param string $header HTTP header to send
-     * @return void Function exits.
      */
     public function pageNotFoundAndExit($reason = '', $header = '')
     {
-        $header = $header ?: $this->TYPO3_CONF_VARS['FE']['pageNotFound_handling_statheader'];
-        $this->pageNotFoundHandler($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling'], $header, $reason);
+        $header = $header ?: $GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling_statheader'];
+        $this->pageNotFoundHandler($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFound_handling'], $header, $reason);
         die;
     }
 
@@ -2022,10 +1895,10 @@ class TypoScriptFrontendController
     public function checkPageUnavailableHandler()
     {
         if (
-            $this->TYPO3_CONF_VARS['FE']['pageUnavailable_handling']
+            $GLOBALS['TYPO3_CONF_VARS']['FE']['pageUnavailable_handling']
             && !GeneralUtility::cmpIP(
                 GeneralUtility::getIndpEnv('REMOTE_ADDR'),
-                $this->TYPO3_CONF_VARS['SYS']['devIPmask']
+                $GLOBALS['TYPO3_CONF_VARS']['SYS']['devIPmask']
             )
         ) {
             $checkPageUnavailableHandler = true;
@@ -2041,7 +1914,6 @@ class TypoScriptFrontendController
      * @param mixed $code Which type of handling; If a true PHP-boolean or TRUE then a \TYPO3\CMS\Core\Messaging\ErrorpageMessage is outputted. If integer an error message with that number is shown. Otherwise the $code value is expected to be a "Location:" header value.
      * @param string $header If set, this is passed directly to the PHP function, header()
      * @param string $reason If set, error messages will also mention this as the reason for the page-not-found.
-     * @return void (The function exits!)
      */
     public function pageUnavailableHandler($code, $header, $reason)
     {
@@ -2054,7 +1926,6 @@ class TypoScriptFrontendController
      * @param mixed $code Which type of handling; If a true PHP-boolean or TRUE then a \TYPO3\CMS\Core\Messaging\ErrorpageMessage is outputted. If integer an error message with that number is shown. Otherwise the $code value is expected to be a "Location:" header value.
      * @param string $header If set, this is passed directly to the PHP function, header()
      * @param string $reason If set, error messages will also mention this as the reason for the page-not-found.
-     * @return void (The function exits!)
      */
     public function pageNotFoundHandler($code, $header = '', $reason = '')
     {
@@ -2069,7 +1940,6 @@ class TypoScriptFrontendController
      * @param string $header If set, this is passed directly to the PHP function, header()
      * @param string $reason If set, error messages will also mention this as the reason for the page-not-found.
      * @throws \RuntimeException
-     * @return void (The function exits!)
      */
     public function pageErrorHandler($code, $header = '', $reason = '')
     {
@@ -2082,33 +1952,32 @@ class TypoScriptFrontendController
         }
         // Create response:
         // Simply boolean; Just shows TYPO3 error page with reason:
-        if (gettype($code) == 'boolean' || (string)$code === '1') {
-            $title = 'Page Not Found';
-            $message = 'The page did not exist or was inaccessible.' . ($reason ? ' Reason: ' . htmlspecialchars($reason) : '');
-            $messagePage = GeneralUtility::makeInstance(ErrorpageMessage::class, $message, $title);
-            $messagePage->output();
-            die;
+        if (strtolower($code) === 'true' || (string)$code === '1' || gettype($code) === 'boolean') {
+            echo GeneralUtility::makeInstance(ErrorPageController::class)->errorAction(
+                'Page Not Found',
+                'The page did not exist or was inaccessible.' . ($reason ? ' Reason: ' . $reason : '')
+            );
         } elseif (GeneralUtility::isFirstPartOfStr($code, 'USER_FUNCTION:')) {
             $funcRef = trim(substr($code, 14));
-            $params = array(
+            $params = [
                 'currentUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
                 'reasonText' => $reason,
                 'pageAccessFailureReasons' => $this->getPageAccessFailureReasons()
-            );
+            ];
             echo GeneralUtility::callUserFunction($funcRef, $params, $this);
         } elseif (GeneralUtility::isFirstPartOfStr($code, 'READFILE:')) {
             $readFile = GeneralUtility::getFileAbsFileName(trim(substr($code, 9)));
             if (@is_file($readFile)) {
                 echo str_replace(
-                    array(
+                    [
                         '###CURRENT_URL###',
                         '###REASON###'
-                    ),
-                    array(
+                    ],
+                    [
                         GeneralUtility::getIndpEnv('REQUEST_URI'),
                         htmlspecialchars($reason)
-                    ),
-                    GeneralUtility::getUrl($readFile)
+                    ],
+                    file_get_contents($readFile)
                 );
             } else {
                 throw new \RuntimeException('Configuration Error: 404 page "' . $readFile . '" could not be found.', 1294587214);
@@ -2118,7 +1987,8 @@ class TypoScriptFrontendController
         } elseif ($code !== '') {
             // Check if URL is relative
             $url_parts = parse_url($code);
-            if ($url_parts['host'] == '') {
+            // parse_url could return an array without the key "host", the empty check works better than strict check
+            if (empty($url_parts['host'])) {
                 $url_parts['host'] = GeneralUtility::getIndpEnv('HTTP_HOST');
                 if ($code[0] === '/') {
                     $code = GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST') . $code;
@@ -2138,10 +2008,10 @@ class TypoScriptFrontendController
                 throw new \RuntimeException(nl2br(htmlspecialchars($reason)), 1294587215);
             }
             // Prepare headers
-            $headerArr = array(
+            $headerArr = [
                 'User-agent: ' . GeneralUtility::getIndpEnv('HTTP_USER_AGENT'),
                 'Referer: ' . GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL')
-            );
+            ];
             $res = GeneralUtility::getUrl($code, 1, $headerArr);
             // Header and content are separated by an empty line
             list($header, $content) = explode(CRLF . CRLF, $res, 2);
@@ -2151,9 +2021,9 @@ class TypoScriptFrontendController
                 HttpUtility::redirect($code);
             } else {
                 // Forward these response headers to the client
-                $forwardHeaders = array(
+                $forwardHeaders = [
                     'Content-Type:'
-                );
+                ];
                 $headerArr = preg_split('/\\r|\\n/', $header, -1, PREG_SPLIT_NO_EMPTY);
                 foreach ($headerArr as $header) {
                     foreach ($forwardHeaders as $h) {
@@ -2162,7 +2032,7 @@ class TypoScriptFrontendController
                         }
                     }
                 }
-                // Put <base> if necesary
+                // Put <base> if necessary
                 if ($checkBaseTag) {
                     // If content already has <base> tag, we do not need to do anything
                     if (false === stristr($content, '<base ')) {
@@ -2191,10 +2061,10 @@ class TypoScriptFrontendController
                 echo $content;
             }
         } else {
-            $title = 'Page Not Found';
-            $message = $reason ? 'Reason: ' . htmlspecialchars($reason) : 'Page cannot be found.';
-            $messagePage = GeneralUtility::makeInstance(ErrorpageMessage::class, $message, $title);
-            $messagePage->output();
+            echo GeneralUtility::makeInstance(ErrorPageController::class)->errorAction(
+                'Page Not Found',
+                $reason ? 'Reason: ' . $reason : 'Page cannot be found.'
+            );
         }
         die;
     }
@@ -2203,7 +2073,6 @@ class TypoScriptFrontendController
      * Fetches the integer page id for a page alias.
      * Looks if ->id is not an integer and if so it will search for a page alias and if found the page uid of that page is stored in $this->id
      *
-     * @return void
      * @access private
      */
     public function checkAndSetAlias()
@@ -2222,7 +2091,6 @@ class TypoScriptFrontendController
      * Merging values into the global $_GET
      *
      * @param array $GET_VARS Array of key/value pairs that will be merged into the current GET-vars. (Non-escaped values)
-     * @return void
      */
     public function mergingWithGetVars($GET_VARS)
     {
@@ -2230,7 +2098,7 @@ class TypoScriptFrontendController
             // Getting $_GET var, unescaped.
             $realGet = GeneralUtility::_GET();
             if (!is_array($realGet)) {
-                $realGet = array();
+                $realGet = [];
             }
             // Merge new values on top:
             ArrayUtility::mergeRecursiveWithOverrule($realGet, $GET_VARS);
@@ -2243,12 +2111,8 @@ class TypoScriptFrontendController
             if (isset($GET_VARS['cHash'])) {
                 $this->cHash = $GET_VARS['cHash'];
             }
-            // @deprecated since TYPO3 7, remove in TYPO3 8 together with jumpurl property.
-            if (isset($GET_VARS['jumpurl'])) {
-                $this->jumpurl = $GET_VARS['jumpurl'];
-            }
             if (isset($GET_VARS['MP'])) {
-                $this->MP = $this->TYPO3_CONF_VARS['FE']['enable_mount_pids'] ? $GET_VARS['MP'] : '';
+                $this->MP = $GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids'] ? $GET_VARS['MP'] : '';
             }
             if (isset($GET_VARS['no_cache']) && $GET_VARS['no_cache']) {
                 $this->set_no_cache('no_cache is requested via GET parameter');
@@ -2267,21 +2131,22 @@ class TypoScriptFrontendController
      * Calculated hash is stored in $this->cHash_array.
      * This is used to cache pages with more parameters than just id and type.
      *
-     * @return void
      * @see reqCHash()
      */
     public function makeCacheHash()
     {
         // No need to test anything if caching was already disabled.
-        if ($this->no_cache && !$this->TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError']) {
+        if ($this->no_cache && !$GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFoundOnCHashError']) {
             return;
         }
         $GET = GeneralUtility::_GET();
         if ($this->cHash && is_array($GET)) {
+            // Make sure we use the page uid and not the page alias
+            $GET['id'] = $this->id;
             $this->cHash_array = $this->cacheHash->getRelevantParameters(GeneralUtility::implodeArrayForUrl('', $GET));
             $cHash_calc = $this->cacheHash->calculateCacheHash($this->cHash_array);
             if ($cHash_calc != $this->cHash) {
-                if ($this->TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError']) {
+                if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFoundOnCHashError']) {
                     $this->pageNotFoundAndExit('Request parameters could not be validated (&cHash comparison failed)');
                 } else {
                     $this->disableCache();
@@ -2300,13 +2165,12 @@ class TypoScriptFrontendController
      * Will disable caching if the cHash value was not set.
      * This function should be called to check the _existence_ of "&cHash" whenever a plugin generating cacheable output is using extra GET variables. If there _is_ a cHash value the validation of it automatically takes place in makeCacheHash() (see above)
      *
-     * @return void
      * @see makeCacheHash(), \TYPO3\CMS\Frontend\Plugin\AbstractPlugin::pi_cHashCheck()
      */
     public function reqCHash()
     {
         if (!$this->cHash) {
-            if ($this->TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError']) {
+            if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFoundOnCHashError']) {
                 if ($this->tempContent) {
                     $this->clearPageCacheContent();
                 }
@@ -2320,8 +2184,6 @@ class TypoScriptFrontendController
 
     /**
      * Initialize the TypoScript template parser
-     *
-     * @return void
      */
     public function initTemplate()
     {
@@ -2343,7 +2205,7 @@ class TypoScriptFrontendController
         // clearing the content-variable, which will hold the pagecontent
         $this->content = '';
         // Unsetting the lowlevel config
-        unset($this->config);
+        $this->config = [];
         $this->cacheContentFlag = false;
 
         if ($this->no_cache) {
@@ -2366,11 +2228,10 @@ class TypoScriptFrontendController
             if (is_array($pageSectionCacheContent)) {
                 // we have the content, nice that some other process did the work for us already
                 $this->releaseLock('pagesection');
-            } else {
-                // We keep the lock set, because we are the ones generating the page now
+            }
+            // We keep the lock set, because we are the ones generating the page now
                 // and filling the cache.
                 // This indicates that we have to release the lock in the Registry later in releaseLocks()
-            }
         }
 
         if (is_array($pageSectionCacheContent)) {
@@ -2404,19 +2265,18 @@ class TypoScriptFrontendController
                     if (is_array($row)) {
                         // we have the content, nice that some other process did the work for us
                         $this->releaseLock('pages');
-                    } else {
-                        // We keep the lock set, because we are the ones generating the page now
+                    }
+                    // We keep the lock set, because we are the ones generating the page now
                         // and filling the cache.
                         // This indicates that we have to release the lock in the Registry later in releaseLocks()
-                    }
                 }
                 if (is_array($row)) {
                     // we have data from cache
 
                     // Call hook when a page is retrieved from cache:
-                    if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'])) {
-                        $_params = array('pObj' => &$this, 'cache_pages_row' => &$row);
-                        foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'] as $_funcRef) {
+                    if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'])) {
+                        $_params = ['pObj' => &$this, 'cache_pages_row' => &$row];
+                        foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'] as $_funcRef) {
                             GeneralUtility::callUserFunction($_funcRef, $_params, $this);
                         }
                     }
@@ -2439,12 +2299,12 @@ class TypoScriptFrontendController
                     if (isset($this->config['config']['debug'])) {
                         $debugCacheTime = (bool)$this->config['config']['debug'];
                     } else {
-                        $debugCacheTime = !empty($this->TYPO3_CONF_VARS['FE']['debug']);
+                        $debugCacheTime = !empty($GLOBALS['TYPO3_CONF_VARS']['FE']['debug']);
                     }
                     if ($debugCacheTime) {
                         $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
                         $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
-                        $this->content .= LF . '<!-- Cached page generated ' . date(($dateFormat . ' ' . $timeFormat), $row['tstamp']) . '. Expires ' . Date(($dateFormat . ' ' . $timeFormat), $row['expires']) . ' -->';
+                        $this->content .= LF . '<!-- Cached page generated ' . date(($dateFormat . ' ' . $timeFormat), $row['tstamp']) . '. Expires ' . date(($dateFormat . ' ' . $timeFormat), $row['expires']) . ' -->';
                     }
                 }
                 $this->getTimeTracker()->pull();
@@ -2486,9 +2346,9 @@ class TypoScriptFrontendController
             }
         }
         // Call hook for possible by-pass of requiring of page cache (for recaching purpose)
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache'])) {
-            $_params = array('pObj' => &$this, 'disableAcquireCacheData' => &$disableAcquireCacheData);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache'])) {
+            $_params = ['pObj' => &$this, 'disableAcquireCacheData' => &$disableAcquireCacheData];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -2535,25 +2395,25 @@ class TypoScriptFrontendController
      */
     protected function createHashBase($createLockHashBase = false)
     {
-        $hashParameters = array(
+        $hashParameters = [
             'id' => (int)$this->id,
             'type' => (int)$this->type,
             'gr_list' => (string)$this->gr_list,
             'MP' => (string)$this->MP,
             'cHash' => $this->cHash_array,
             'domainStartPage' => $this->domainStartPage
-        );
+        ];
         // Include the template information if we shouldn't create a lock hash
         if (!$createLockHashBase) {
             $hashParameters['all'] = $this->all;
         }
         // Call hook to influence the hash calculation
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'])) {
-            $_params = array(
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'])) {
+            $_params = [
                 'hashParameters' => &$hashParameters,
                 'createLockHashBase' => $createLockHashBase
-            );
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'] as $_funcRef) {
+            ];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -2564,12 +2424,11 @@ class TypoScriptFrontendController
      * Checks if config-array exists already but if not, gets it
      *
      * @throws ServiceUnavailableException
-     * @return void
      */
     public function getConfigArray()
     {
         // If config is not set by the cache (which would be a major mistake somewhere) OR if INTincScripts-include-scripts have been registered, then we must parse the template in order to get it
-        if (!is_array($this->config) || is_array($this->config['INTincScript']) || $this->forceTemplateParsing) {
+        if (empty($this->config) || is_array($this->config['INTincScript']) || $this->forceTemplateParsing) {
             $timeTracker = $this->getTimeTracker();
             $timeTracker->push('Parse template', '');
             // Force parsing, if set?:
@@ -2588,12 +2447,12 @@ class TypoScriptFrontendController
                         $this->pageUnavailableAndExit($message);
                     } else {
                         $explanation = 'This means that there is no TypoScript object of type PAGE with typeNum=' . $this->type . ' configured.';
-                        GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                        $this->logger->alert($message);
                         throw new ServiceUnavailableException($message . ' ' . $explanation, 1294587217);
                     }
                 } else {
                     if (!isset($this->config['config'])) {
-                        $this->config['config'] = array();
+                        $this->config['config'] = [];
                     }
                     // Filling the config-array, first with the main "config." part
                     if (is_array($this->tmpl->setup['config.'])) {
@@ -2620,7 +2479,6 @@ class TypoScriptFrontendController
                     }
                     // Processing for the config_array:
                     $this->config['rootLine'] = $this->tmpl->rootLine;
-                    $this->config['mainScript'] = trim($this->config['config']['mainScript']) ?: 'index.php';
                     // Class for render Header and Footer parts
                     if ($this->pSetup['pageHeaderFooterTemplateFile']) {
                         $file = $this->tmpl->getFileName($this->pSetup['pageHeaderFooterTemplateFile']);
@@ -2635,7 +2493,7 @@ class TypoScriptFrontendController
                     $this->pageUnavailableAndExit('No TypoScript template found!');
                 } else {
                     $message = 'No TypoScript template found!';
-                    GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+                    $this->logger->alert($message);
                     throw new ServiceUnavailableException($message, 1294587218);
                 }
             }
@@ -2653,9 +2511,9 @@ class TypoScriptFrontendController
             GeneralUtility::_GETset($modifiedGetVars);
         }
         // Hook for postProcessing the configuration array
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'])) {
-            $params = array('config' => &$this->config['config']);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'] as $funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'])) {
+            $params = ['config' => &$this->config['config']];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'] as $funcRef) {
                 GeneralUtility::callUserFunction($funcRef, $params, $this);
             }
         }
@@ -2664,7 +2522,6 @@ class TypoScriptFrontendController
     /********************************************
      *
      * Further initialization and data processing
-     * (jumpurl/submission of forms)
      *
      *******************************************/
 
@@ -2672,20 +2529,26 @@ class TypoScriptFrontendController
      * Setting the language key that will be used by the current page.
      * In this function it should be checked, 1) that this language exists, 2) that a page_overlay_record exists, .. and if not the default language, 0 (zero), should be set.
      *
-     * @return void
      * @access private
      */
     public function settingLanguage()
     {
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_preProcess'])) {
-            $_params = array();
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_preProcess'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_preProcess'])) {
+            $_params = [];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_preProcess'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
 
         // Initialize charset settings etc.
-        $this->initLLvars();
+        $languageKey = $this->config['config']['language'] ?? 'default';
+        $this->lang = $languageKey;
+        $this->setOutputLanguage($languageKey);
+
+        // Rendering charset of HTML page.
+        if (isset($this->config['config']['metaCharset']) && $this->config['config']['metaCharset'] !== 'utf-8') {
+            $this->metaCharset = $this->config['config']['metaCharset'];
+        }
 
         // Get values from TypoScript:
         $this->sys_language_uid = ($this->sys_language_content = (int)$this->config['config']['sys_language_uid']);
@@ -2711,13 +2574,24 @@ class TypoScriptFrontendController
                                 $this->pageNotFoundAndExit('Page is not available in the requested language (strict).');
                                 break;
                             case 'content_fallback':
-                                $fallBackOrder = GeneralUtility::intExplode(',', $sys_language_content);
+                                // Setting content uid (but leaving the sys_language_uid) when a content_fallback
+                                // value was found.
+                                $fallBackOrder = GeneralUtility::trimExplode(',', $sys_language_content);
                                 foreach ($fallBackOrder as $orderValue) {
-                                    if ((string)$orderValue === '0' || !empty($this->sys_page->getPageOverlay($this->id, $orderValue))) {
-                                        $this->sys_language_content = $orderValue;
-                                        // Setting content uid (but leaving the sys_language_uid)
+                                    if ($orderValue === '0' || $orderValue === '') {
+                                        $this->sys_language_content = 0;
+                                        break;
+                                    }
+                                    if (MathUtility::canBeInterpretedAsInteger($orderValue) && !empty($this->sys_page->getPageOverlay($this->id, (int)$orderValue))) {
+                                        $this->sys_language_content = (int)$orderValue;
                                         break;
                                     }
+                                    if ($orderValue === 'pageNotFound') {
+                                        // The existing fallbacks have not been found, but instead of continuing
+                                        // page rendering with default language, a "page not found" message should be shown
+                                        // instead.
+                                        $this->pageNotFoundAndExit('Page is not available in the requested language (fallbacks did not apply).');
+                                    }
                                 }
                                 break;
                             case 'ignore':
@@ -2737,9 +2611,9 @@ class TypoScriptFrontendController
         // Setting sys_language_uid inside sys-page:
         $this->sys_page->sys_language_uid = $this->sys_language_uid;
         // If default translation is not available:
-        if ((!$this->sys_language_uid || !$this->sys_language_content) && $this->page['l18n_cfg'] & 1) {
+        if ((!$this->sys_language_uid || !$this->sys_language_content) && GeneralUtility::hideIfDefaultLanguage($this->page['l18n_cfg'])) {
             $message = 'Page is not available in default language.';
-            GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
+            $this->logger->error($message);
             $this->pageNotFoundAndExit($message);
         }
         $this->updateRootLinesWithTranslations();
@@ -2750,17 +2624,11 @@ class TypoScriptFrontendController
             // using sys_language_content because the ISO code only (currently) affect content selection from FlexForms - which should follow "sys_language_content"
             // Set the fourth parameter to TRUE in the next two getRawRecord() calls to
             // avoid versioning overlay to be applied as it generates an SQL error
-            $sys_language_row = $this->sys_page->getRawRecord('sys_language', $this->sys_language_content, 'language_isocode,static_lang_isocode', true);
-            if (is_array($sys_language_row)) {
-                if (!empty($sys_language_row['language_isocode'])) {
-                    $this->sys_language_isocode = $sys_language_row['language_isocode'];
-                } elseif ($sys_language_row['static_lang_isocode'] && ExtensionManagementUtility::isLoaded('static_info_tables')) {
-                    GeneralUtility::deprecationLog('Usage of the field "static_lang_isocode" is discouraged, and will stop working with CMS 8. Use the built-in language field "language_isocode" in your sys_language records.');
-                    $stLrow = $this->sys_page->getRawRecord('static_languages', $sys_language_row['static_lang_isocode'], 'lg_iso_2', true);
-                    $this->sys_language_isocode = $stLrow['lg_iso_2'];
-                }
+            $sys_language_row = $this->sys_page->getRawRecord('sys_language', $this->sys_language_content, 'language_isocode,static_lang_isocode');
+            if (is_array($sys_language_row) && !empty($sys_language_row['language_isocode'])) {
+                $this->sys_language_isocode = $sys_language_row['language_isocode'];
             }
-            // the DB value is overriden by TypoScript
+            // the DB value is overridden by TypoScript
             if (!empty($this->config['config']['sys_language_isocode'])) {
                 $this->sys_language_isocode = $this->config['config']['sys_language_isocode'];
             }
@@ -2770,26 +2638,13 @@ class TypoScriptFrontendController
             if (!empty($this->config['config']['sys_language_isocode_default'])) {
                 $this->sys_language_isocode = $this->config['config']['sys_language_isocode_default'];
             } else {
-                $this->sys_language_isocode = $this->lang != 'default' ? $this->lang : 'en';
+                $this->sys_language_isocode = $languageKey !== 'default' ? $languageKey : 'en';
             }
         }
 
-
-        // Setting softMergeIfNotBlank:
-        $table_fields = GeneralUtility::trimExplode(',', $this->config['config']['sys_language_softMergeIfNotBlank'], true);
-        foreach ($table_fields as $TF) {
-            list($tN, $fN) = explode(':', $TF);
-            $GLOBALS['TCA'][$tN]['columns'][$fN]['l10n_mode'] = 'mergeIfNotBlank';
-        }
-        // Setting softExclude:
-        $table_fields = GeneralUtility::trimExplode(',', $this->config['config']['sys_language_softExclude'], true);
-        foreach ($table_fields as $TF) {
-            list($tN, $fN) = explode(':', $TF);
-            $GLOBALS['TCA'][$tN]['columns'][$fN]['l10n_mode'] = 'exclude';
-        }
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'])) {
-            $_params = array();
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'])) {
+            $_params = [];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -2808,22 +2663,25 @@ class TypoScriptFrontendController
 
     /**
      * Setting locale for frontend rendering
-     *
-     * @return void
      */
     public function settingLocale()
     {
         // Setting locale
         if ($this->config['config']['locale_all']) {
-            // There's a problem that PHP parses float values in scripts wrong if the
-            // locale LC_NUMERIC is set to something with a comma as decimal point
-            // Do we set all except LC_NUMERIC
-            $locale = setlocale(LC_COLLATE, $this->config['config']['locale_all']);
+            $availableLocales = GeneralUtility::trimExplode(',', $this->config['config']['locale_all'], true);
+            // If LC_NUMERIC is set e.g. to 'de_DE' PHP parses float values locale-aware resulting in strings with comma
+            // as decimal point which causes problems with value conversions - so we set all locale types except LC_NUMERIC
+            // @see https://bugs.php.net/bug.php?id=53711
+            $locale = setlocale(LC_COLLATE, ...$availableLocales);
             if ($locale) {
-                setlocale(LC_CTYPE, $this->config['config']['locale_all']);
-                setlocale(LC_MONETARY, $this->config['config']['locale_all']);
-                setlocale(LC_TIME, $this->config['config']['locale_all']);
-                $this->localeCharset = $this->csConvObj->get_locale_charset($this->config['config']['locale_all']);
+                // As str_* methods are locale aware and turkish has no upper case I
+                // Class autoloading and other checks depending on case changing break with turkish locale LC_CTYPE
+                // @see http://bugs.php.net/bug.php?id=35050
+                if (substr($this->config['config']['locale_all'], 0, 2) !== 'tr') {
+                    setlocale(LC_CTYPE, ...$availableLocales);
+                }
+                setlocale(LC_MONETARY, ...$availableLocales);
+                setlocale(LC_TIME, ...$availableLocales);
             } else {
                 $this->getTimeTracker()->setTSlogMessage('Locale "' . htmlspecialchars($this->config['config']['locale_all']) . '" not found.', 3);
             }
@@ -2835,8 +2693,6 @@ class TypoScriptFrontendController
      * target than the original language page.
      * If that is the case, things get corrected to follow that alternative
      * shortcut
-     *
-     * @return void
      */
     protected function checkTranslatedShortcut()
     {
@@ -2858,15 +2714,13 @@ class TypoScriptFrontendController
     /**
      * Handle data submission
      * This is done at this point, because we need the config values
-     *
-     * @return void
      */
     public function handleDataSubmission()
     {
         // Hook for processing data submission to extensions
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'] as $_classRef) {
-                $_procObj = GeneralUtility::getUserObj($_classRef);
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'] as $className) {
+                $_procObj = GeneralUtility::makeInstance($className);
                 $_procObj->checkDataSubmission($this);
             }
         }
@@ -2908,35 +2762,6 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Checks if the current page points to an external URL and stores this value in the redirectUrl variable.
-     * The redirection will then be handled by the redirectToExternalUrl() method.
-     *
-     * @return void
-     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. See handleExternalUrlPage()
-     */
-    public function setExternalJumpUrl()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        $this->initializeRedirectUrlHandlers();
-    }
-
-    /**
-     * Sends a header "Location" to jumpUrl, if jumpurl is set.
-     * Will exit if a location header is sent (for instance if jumpUrl was triggered)
-     *
-     * "jumpUrl" is a concept where external links are redirected from the TYPO3 Frontend, but first logs the URL.
-     *
-     * @throws \Exception
-     * @return void
-     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8. JumpURL handling is moved to extensions.
-     */
-    public function jumpUrl()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        $this->redirectToExternalUrl();
-    }
-
-    /**
      * Loops over all registered URL handlers and lets them process the current URL.
      *
      * If no handler has stopped the current process (e.g. by redirecting) and a
@@ -2959,13 +2784,12 @@ class TypoScriptFrontendController
      * Sets the URL_ID_TOKEN in the internal var, $this->getMethodUrlIdToken
      * This feature allows sessions to use a GET-parameter instead of a cookie.
      *
-     * @return void
      * @access private
      */
     public function setUrlIdToken()
     {
         if ($this->config['config']['ftu']) {
-            $this->getMethodUrlIdToken = $this->TYPO3_CONF_VARS['FE']['get_url_id_token'];
+            $this->getMethodUrlIdToken = $GLOBALS['TYPO3_CONF_VARS']['FE']['get_url_id_token'];
         } else {
             $this->getMethodUrlIdToken = '';
         }
@@ -2974,13 +2798,16 @@ class TypoScriptFrontendController
     /**
      * Calculates and sets the internal linkVars based upon the current
      * $_GET parameters and the setting "config.linkVars".
-     *
-     * @return void
      */
     public function calculateLinkVars()
     {
         $this->linkVars = '';
-        $linkVars = GeneralUtility::trimExplode(',', (string)$this->config['config']['linkVars']);
+        if (empty($this->config['config']['linkVars'])) {
+            return;
+        }
+
+        $linkVars = $this->splitLinkVarsString((string)$this->config['config']['linkVars']);
+
         if (empty($linkVars)) {
             return;
         }
@@ -3013,12 +2840,32 @@ class TypoScriptFrontendController
     }
 
     /**
+     * Split the link vars string by "," but not if the "," is inside of braces
+     *
+     * @param $string
+     *
+     * @return array
+     */
+    protected function splitLinkVarsString(string $string): array
+    {
+        $tempCommaReplacementString = '###KASPER###';
+
+        // replace every "," wrapped in "()" by a "unique" string
+        $string = preg_replace_callback('/\((?>[^()]|(?R))*\)/', function ($result) use ($tempCommaReplacementString) {
+            return str_replace(',', $tempCommaReplacementString, $result[0]);
+        }, $string);
+
+        $string = GeneralUtility::trimExplode(',', $string);
+
+        // replace all "unique" strings back to ","
+        return str_replace($tempCommaReplacementString, ',', $string);
+    }
+
+    /**
      * Redirect to target page if the current page is an overlaid mountpoint.
      *
      * If the current page is of type mountpoint and should be overlaid with the contents of the mountpoint page
      * and is accessed directly, the user will be redirected to the mountpoint context.
-     *
-     * @return void
      */
     public function checkPageForMountpointRedirect()
     {
@@ -3032,8 +2879,6 @@ class TypoScriptFrontendController
      *
      * If the current page is of type shortcut and accessed directly via its URL, this function redirects to the
      * Shortcut target using a Location header.
-     *
-     * @return void If page is not a Shortcut, redirects and exits otherwise
      */
     public function checkPageForShortcutRedirect()
     {
@@ -3045,8 +2890,6 @@ class TypoScriptFrontendController
     /**
      * Builds a typolink to the current page, appends the type paremeter if required
      * and redirects the user to the generated URL using a Location header.
-     *
-     * @return void
      */
     protected function redirectToCurrentPage()
     {
@@ -3059,7 +2902,8 @@ class TypoScriptFrontendController
         if ($type && MathUtility::canBeInterpretedAsInteger($type)) {
             $parameter .= ',' . $type;
         }
-        $redirectUrl = $cObj->typoLink_URL(array('parameter' => $parameter));
+        $redirectUrl = $cObj->typoLink_URL(['parameter' => $parameter, 'addQueryString' => true,
+            'addQueryString.' => ['exclude' => 'id']]);
 
         // Prevent redirection loop
         if (!empty($redirectUrl)) {
@@ -3087,8 +2931,6 @@ class TypoScriptFrontendController
     /**
      * Temp cache content
      * The temporary cache will expire after a few seconds (typ. 30) or will be cleared by the rendered page, which will also clear and rewrite the cache.
-     *
-     * @return void
      */
     public function tempPageCacheContent()
     {
@@ -3102,8 +2944,6 @@ class TypoScriptFrontendController
                If this message does not disappear within ' . $seconds . ' seconds, please reload.';
             $message = $this->config['config']['message_page_is_being_generated'];
             if ((string)$message !== '') {
-                // This page is always encoded as UTF-8
-                $message = $this->csConvObj->utf8_encode($message, $this->renderCharset);
                 $message = str_replace('###TITLE###', $title, $message);
                 $message = str_replace('###REQUEST_URI###', $request_uri, $message);
             } else {
@@ -3145,8 +2985,6 @@ class TypoScriptFrontendController
 
     /**
      * Set cache content to $this->content
-     *
-     * @return void
      */
     public function realPageCacheContent()
     {
@@ -3158,9 +2996,9 @@ class TypoScriptFrontendController
         // Hook for deciding whether page cache should be written to the cache backend or not
         // NOTE: as hooks are called in a loop, the last hook will have the final word (however each
         // hook receives the current status of the $usePageCache flag)
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'] as $_classRef) {
-                $_procObj = GeneralUtility::getUserObj($_classRef);
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'] as $className) {
+                $_procObj = GeneralUtility::makeInstance($className);
                 $usePageCache = $_procObj->usePageCache($this, $usePageCache);
             }
         }
@@ -3169,9 +3007,9 @@ class TypoScriptFrontendController
             $this->setPageCacheContent($this->content, $this->config, $timeOutTime);
         }
         // Hook for cache post processing (eg. writing static files!)
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['insertPageIncache'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['insertPageIncache'] as $_classRef) {
-                $_procObj = GeneralUtility::getUserObj($_classRef);
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['insertPageIncache'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['insertPageIncache'] as $className) {
+                $_procObj = GeneralUtility::makeInstance($className);
                 $_procObj->insertPageIncache($this, $timeOutTime);
             }
         }
@@ -3183,12 +3021,11 @@ class TypoScriptFrontendController
      * @param string $content The content to store in the HTML field of the cache table
      * @param mixed $data The additional cache_data array, fx. $this->config
      * @param int $expirationTstamp Expiration timestamp
-     * @return void
      * @see realPageCacheContent(), tempPageCacheContent()
      */
     public function setPageCacheContent($content, $data, $expirationTstamp)
     {
-        $cacheData = array(
+        $cacheData = [
             'identifier' => $this->newHash,
             'page_id' => $this->id,
             'content' => $content,
@@ -3196,12 +3033,12 @@ class TypoScriptFrontendController
             'cache_data' => $data,
             'expires' => $expirationTstamp,
             'tstamp' => $GLOBALS['EXEC_TIME'],
-            'pageTitleInfo' => array(
+            'pageTitleInfo' => [
                 'title' => $this->page['title'],
                 'altPageTitle' => $this->altPageTitle,
                 'indexedDocTitle' => $this->indexedDocTitle
-            )
-        );
+            ]
+        ];
         $this->cacheExpires = $expirationTstamp;
         $this->pageCacheTags[] = 'pageId_' . $cacheData['page_id'];
         if ($this->page_cache_reg1) {
@@ -3218,8 +3055,6 @@ class TypoScriptFrontendController
 
     /**
      * Clears cache content (for $this->newHash)
-     *
-     * @return void
      */
     public function clearPageCacheContent()
     {
@@ -3230,7 +3065,6 @@ class TypoScriptFrontendController
      * Clears cache content for a list of page ids
      *
      * @param string $pidList A list of INTEGER numbers which points to page uids for which to clear entries in the cache_pages cache (page content cache)
-     * @return void
      */
     public function clearPageCacheContent_pidList($pidList)
     {
@@ -3244,84 +3078,30 @@ class TypoScriptFrontendController
      * Sets sys last changed
      * Setting the SYS_LASTCHANGED value in the pagerecord: This value will thus be set to the highest tstamp of records rendered on the page. This includes all records with no regard to hidden records, userprotection and so on.
      *
-     * @return void
      * @see ContentObjectRenderer::lastChanged()
      */
     public function setSysLastChanged()
     {
         // Draft workspaces are always uid 1 or more. We do not update SYS_LASTCHANGED if we are browsing page from one of theses workspaces
         if ((int)$this->whichWorkspace() < 1 && $this->page['SYS_LASTCHANGED'] < (int)$this->register['SYS_LASTCHANGED']) {
-            $this->getDatabaseConnection()->exec_UPDATEquery('pages', 'uid=' . (int)$this->id, array('SYS_LASTCHANGED' => (int)$this->register['SYS_LASTCHANGED']));
-        }
-    }
-
-    /**
-     * Lock the page generation process
-     * The lock is used to queue page requests until this page is successfully stored in the cache.
-     *
-     * @param Locker $lockObj Reference to a locking object
-     * @param string $key String to identify the lock in the system
-     * @return bool Returns TRUE if the lock could be obtained, FALSE otherwise (= process had to wait for existing lock to be released)
-     * @see releasePageGenerationLock()
-     * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
-     */
-    public function acquirePageGenerationLock(&$lockObj, $key)
-    {
-        GeneralUtility::logDeprecatedFunction();
-        if ($this->no_cache || $this->headerNoCache()) {
-            GeneralUtility::sysLog('Locking: Page is not cached, no locking required', 'cms', GeneralUtility::SYSLOG_SEVERITY_INFO);
-            // No locking is needed if caching is disabled
-            return true;
-        }
-        try {
-            if (!is_object($lockObj)) {
-                $lockObj = GeneralUtility::makeInstance(Locker::class, $key, $this->TYPO3_CONF_VARS['SYS']['lockingMode']);
-            }
-            $success = false;
-            if ($key !== '') {
-                // TRUE = Page could get locked without blocking
-                // FALSE = Page could get locked but process was blocked before
-                $success = $lockObj->acquire();
-                if ($lockObj->getLockStatus()) {
-                    $lockObj->sysLog('Acquired lock');
-                }
-            }
-        } catch (\Exception $e) {
-            GeneralUtility::sysLog('Locking: Failed to acquire lock: ' . $e->getMessage(), 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
-            // If locking fails, return with FALSE and continue without locking
-            $success = false;
+            $connection = GeneralUtility::makeInstance(ConnectionPool::class)
+                ->getConnectionForTable('pages');
+            $connection->update(
+                'pages',
+                [
+                    'SYS_LASTCHANGED' => (int)$this->register['SYS_LASTCHANGED']
+                ],
+                [
+                    'uid' => (int)$this->id
+                ]
+            );
         }
-        return $success;
-    }
-
-    /**
-     * Release the page generation lock
-     *
-     * @param Locker $lockObj Reference to a locking object
-     * @return bool Returns TRUE on success, FALSE otherwise
-     * @see acquirePageGenerationLock()
-     * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
-     */
-    public function releasePageGenerationLock(&$lockObj)
-    {
-        GeneralUtility::logDeprecatedFunction();
-        $success = false;
-        // If lock object is set and was acquired (may also happen if no_cache was enabled during runtime), release it:
-        if (is_object($lockObj) && $lockObj instanceof Locker && $lockObj->getLockStatus()) {
-            $success = $lockObj->release();
-            $lockObj->sysLog('Released lock');
-            $lockObj = null;
-        } elseif ($this->no_cache || $this->headerNoCache()) {
-            $success = true;
-        }
-        return $success;
     }
 
     /**
      * Release pending locks
      *
      * @internal
-     * @return void
      */
     public function releaseLocks()
     {
@@ -3334,7 +3114,6 @@ class TypoScriptFrontendController
      * entries by tag
      *
      * @param array $tags An array of tag
-     * @return void
      */
     public function addCacheTags(array $tags)
     {
@@ -3348,8 +3127,6 @@ class TypoScriptFrontendController
      *******************************************/
     /**
      * Does some processing BEFORE the pagegen script is included.
-     *
-     * @return void
      */
     public function generatePage_preProcessing()
     {
@@ -3375,24 +3152,121 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Determines to include custom or pagegen.php script
-     * returns script-filename if a TypoScript (config) script is defined and should be included instead of pagegen.php
+     * Previously located in static method in PageGenerator::init. Is solely used to set up TypoScript
+     * config. options and set properties in $TSFE for that.
+     */
+    public function preparePageContentGeneration()
+    {
+        if ($this->page['content_from_pid'] > 0) {
+            // make REAL copy of TSFE object - not reference!
+            $temp_copy_TSFE = clone $this;
+            // Set ->id to the content_from_pid value - we are going to evaluate this pid as was it a given id for a page-display!
+            $temp_copy_TSFE->id = $this->page['content_from_pid'];
+            $temp_copy_TSFE->MP = '';
+            $temp_copy_TSFE->getPageAndRootlineWithDomain($this->config['config']['content_from_pid_allowOutsideDomain'] ? 0 : $this->domainStartPage);
+            $this->contentPid = (int)$temp_copy_TSFE->id;
+            unset($temp_copy_TSFE);
+        }
+        if ($this->config['config']['MP_defaults']) {
+            $temp_parts = GeneralUtility::trimExplode('|', $this->config['config']['MP_defaults'], true);
+            foreach ($temp_parts as $temp_p) {
+                list($temp_idP, $temp_MPp) = explode(':', $temp_p, 2);
+                $temp_ids = GeneralUtility::intExplode(',', $temp_idP);
+                foreach ($temp_ids as $temp_id) {
+                    $this->MP_defaults[$temp_id] = $temp_MPp;
+                }
+            }
+        }
+        // Global vars...
+        $this->indexedDocTitle = $this->page['title'];
+        $this->debug = !empty($this->config['config']['debug']);
+        // Base url:
+        if (isset($this->config['config']['baseURL'])) {
+            $this->baseUrl = $this->config['config']['baseURL'];
+        }
+        // Internal and External target defaults
+        $this->intTarget = '' . $this->config['config']['intTarget'];
+        $this->extTarget = '' . $this->config['config']['extTarget'];
+        $this->fileTarget = '' . $this->config['config']['fileTarget'];
+        if ($this->config['config']['spamProtectEmailAddresses'] === 'ascii') {
+            $this->spamProtectEmailAddresses = 'ascii';
+        } else {
+            $this->spamProtectEmailAddresses = MathUtility::forceIntegerInRange($this->config['config']['spamProtectEmailAddresses'], -10, 10, 0);
+        }
+        // calculate the absolute path prefix
+        if (!empty($this->config['config']['absRefPrefix'])) {
+            $absRefPrefix = trim($this->config['config']['absRefPrefix']);
+            if ($absRefPrefix === 'auto') {
+                $this->absRefPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
+            } else {
+                $this->absRefPrefix = $absRefPrefix;
+            }
+        } else {
+            $this->absRefPrefix = '';
+        }
+        $this->lockFilePath = '' . $this->config['config']['lockFilePath'];
+        $this->lockFilePath = $this->lockFilePath ?: $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'];
+        $this->ATagParams = trim($this->config['config']['ATagParams']) ? ' ' . trim($this->config['config']['ATagParams']) : '';
+        $this->initializeSearchWordDataInTsfe();
+        // linkVars
+        $this->calculateLinkVars();
+        // Setting XHTML-doctype from doctype
+        if (!$this->config['config']['xhtmlDoctype']) {
+            $this->config['config']['xhtmlDoctype'] = $this->config['config']['doctype'];
+        }
+        if ($this->config['config']['xhtmlDoctype']) {
+            $this->xhtmlDoctype = $this->config['config']['xhtmlDoctype'];
+            // Checking XHTML-docytpe
+            switch ((string)$this->config['config']['xhtmlDoctype']) {
+                case 'xhtml_trans':
+                case 'xhtml_strict':
+                    $this->xhtmlVersion = 100;
+                    break;
+                case 'xhtml_basic':
+                    $this->xhtmlVersion = 105;
+                    break;
+                case 'xhtml_11':
+                case 'xhtml+rdfa_10':
+                    $this->xhtmlVersion = 110;
+                    break;
+                default:
+                    $this->pageRenderer->setRenderXhtml(false);
+                    $this->xhtmlDoctype = '';
+                    $this->xhtmlVersion = 0;
+            }
+        } else {
+            $this->pageRenderer->setRenderXhtml(false);
+        }
+
+        // Global content object
+        $this->newCObj();
+    }
+
+    /**
+     * Fills the sWordList property and builds the regular expression in TSFE that can be used to split
+     * strings by the submitted search words.
      *
-     * @return string|NULL The relative filepath of "config.pageGenScript" if found and allowed
+     * @see sWordList
+     * @see sWordRegEx
      */
-    public function generatePage_whichScript()
+    protected function initializeSearchWordDataInTsfe()
     {
-        if (!$this->TYPO3_CONF_VARS['FE']['noPHPscriptInclude'] && $this->config['config']['pageGenScript']) {
-            return $this->tmpl->getFileName($this->config['config']['pageGenScript']);
+        $this->sWordRegEx = '';
+        $this->sWordList = GeneralUtility::_GP('sword_list');
+        if (is_array($this->sWordList)) {
+            $space = !empty($this->config['config']['sword_standAlone']) ? '[[:space:]]' : '';
+            foreach ($this->sWordList as $val) {
+                if (trim($val) !== '') {
+                    $this->sWordRegEx .= $space . preg_quote($val, '/') . $space . '|';
+                }
+            }
+            $this->sWordRegEx = rtrim($this->sWordRegEx, '|');
         }
-        return null;
     }
 
     /**
      * Does some processing AFTER the pagegen script is included.
-     * This includes calling XHTML cleaning (if configured), caching the page, indexing the page (if configured) and setting sysLastChanged
-     *
-     * @return void
+     * This includes caching the page, indexing the page (if configured) and setting sysLastChanged
      */
     public function generatePage_postProcessing()
     {
@@ -3401,18 +3275,18 @@ class TypoScriptFrontendController
             $this->set_no_cache('no_cache has been set before the page was generated - safety check', true);
         }
         // Hook for post-processing of page content cached/non-cached:
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'] as $_funcRef) {
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
         // Processing if caching is enabled:
         if (!$this->no_cache) {
             // Hook for post-processing of page content before being cached:
-            if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached'])) {
-                $_params = array('pObj' => &$this);
-                foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached'] as $_funcRef) {
+            if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached'])) {
+                $_params = ['pObj' => &$this];
+                foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached'] as $_funcRef) {
                     GeneralUtility::callUserFunction($_funcRef, $_params, $this);
                 }
             }
@@ -3420,13 +3294,13 @@ class TypoScriptFrontendController
         // Convert char-set for output: (should be BEFORE indexing of the content (changed 22/4 2005)),
         // because otherwise indexed search might convert from the wrong charset!
         // One thing is that the charset mentioned in the HTML header would be wrong since the output charset (metaCharset)
-        // has not been converted to from renderCharset. And indexed search will internally convert from metaCharset
-        // to renderCharset so the content MUST be in metaCharset already!
-        $this->content = $this->convOutputCharset($this->content, 'mainpage');
+        // has not been converted to from utf-8. And indexed search will internally convert from metaCharset
+        // to utf-8 so the content MUST be in metaCharset already!
+        $this->content = $this->convOutputCharset($this->content);
         // Hook for indexing pages
-        if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'])) {
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'] as $_classRef) {
-                $_procObj = GeneralUtility::getUserObj($_classRef);
+        if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'])) {
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'] as $className) {
+                $_procObj = GeneralUtility::makeInstance($className);
                 $_procObj->hook_indexContent($this);
             }
         }
@@ -3444,8 +3318,6 @@ class TypoScriptFrontendController
 
     /**
      * Generate the page title again as TSFE->altPageTitle might have been modified by an inc script
-     *
-     * @return void
      */
     protected function regeneratePageTitle()
     {
@@ -3454,15 +3326,13 @@ class TypoScriptFrontendController
 
     /**
      * Processes the INTinclude-scripts
-     *
-     * @return void
      */
     public function INTincScript()
     {
         // Deprecated stuff:
         // @deprecated: annotation added TYPO3 4.6
-        $this->additionalHeaderData = is_array($this->config['INTincScript_ext']['additionalHeaderData']) ? $this->config['INTincScript_ext']['additionalHeaderData'] : array();
-        $this->additionalFooterData = is_array($this->config['INTincScript_ext']['additionalFooterData']) ? $this->config['INTincScript_ext']['additionalFooterData'] : array();
+        $this->additionalHeaderData = is_array($this->config['INTincScript_ext']['additionalHeaderData']) ? $this->config['INTincScript_ext']['additionalHeaderData'] : [];
+        $this->additionalFooterData = is_array($this->config['INTincScript_ext']['additionalFooterData']) ? $this->config['INTincScript_ext']['additionalFooterData'] : [];
         $this->additionalJavaScript = $this->config['INTincScript_ext']['additionalJavaScript'];
         $this->additionalCSS = $this->config['INTincScript_ext']['additionalCSS'];
         $this->divSection = '';
@@ -3481,16 +3351,16 @@ class TypoScriptFrontendController
         $this->regeneratePageTitle();
 
         $this->content = str_replace(
-            array(
+            [
                 '<!--HD_' . $this->config['INTincScript_ext']['divKey'] . '-->',
                 '<!--FD_' . $this->config['INTincScript_ext']['divKey'] . '-->',
                 '<!--TDS_' . $this->config['INTincScript_ext']['divKey'] . '-->'
-            ),
-            array(
-                $this->convOutputCharset(implode(LF, $this->additionalHeaderData), 'HD'),
-                $this->convOutputCharset(implode(LF, $this->additionalFooterData), 'FD'),
-                $this->convOutputCharset($this->divSection, 'TDS'),
-            ),
+            ],
+            [
+                $this->convOutputCharset(implode(LF, $this->additionalHeaderData)),
+                $this->convOutputCharset(implode(LF, $this->additionalFooterData)),
+                $this->convOutputCharset($this->divSection),
+            ],
             $this->pageRenderer->renderJavaScriptAndCssForProcessingOfUncachedContentObjects($this->content, $this->config['INTincScript_ext']['divKey'])
         );
         // Replace again, because header and footer data and page renderer replacements may introduce additional placeholders (see #44825)
@@ -3508,7 +3378,6 @@ class TypoScriptFrontendController
     {
         do {
             $INTiS_config = $this->config['INTincScript'];
-            $this->INTincScript_includeLibs($INTiS_config);
             $this->INTincScript_process($INTiS_config);
             // Check if there were new items added to INTincScript during the previous execution:
             $INTiS_config = array_diff_assoc($this->config['INTincScript'], $INTiS_config);
@@ -3517,27 +3386,9 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Include libraries for uncached objects.
-     *
-     * @param array $INTiS_config $GLOBALS['TSFE']->config['INTincScript'] or part of it
-     * @return void
-     * @see INTincScript()
-     */
-    protected function INTincScript_includeLibs($INTiS_config)
-    {
-        foreach ($INTiS_config as $INTiS_cPart) {
-            if (isset($INTiS_cPart['conf']['includeLibs']) && $INTiS_cPart['conf']['includeLibs']) {
-                $INTiS_resourceList = GeneralUtility::trimExplode(',', $INTiS_cPart['conf']['includeLibs'], true);
-                $this->includeLibraries($INTiS_resourceList);
-            }
-        }
-    }
-
-    /**
      * Processes the INTinclude-scripts and substitue in content.
      *
      * @param array $INTiS_config $GLOBALS['TSFE']->config['INTincScript'] or part of it
-     * @return void
      * @see INTincScript()
      */
     protected function INTincScript_process($INTiS_config)
@@ -3554,11 +3405,12 @@ class TypoScriptFrontendController
             if (substr($INTiS_cPart, 32, 3) === '-->') {
                 $INTiS_key = 'INT_SCRIPT.' . substr($INTiS_cPart, 0, 32);
                 if (is_array($INTiS_config[$INTiS_key])) {
-                    $timeTracker->push('Include ' . $INTiS_config[$INTiS_key]['file'], '');
+                    $label = 'Include ' . $INTiS_config[$INTiS_key]['type'];
+                    $label = $label . isset($INTiS_config[$INTiS_key]['file']) ? ' ' . $INTiS_config[$INTiS_key]['file'] : '';
+                    $timeTracker->push($label, '');
                     $incContent = '';
                     $INTiS_cObj = unserialize($INTiS_config[$INTiS_key]['cObj']);
                     /* @var $INTiS_cObj ContentObjectRenderer */
-                    $INTiS_cObj->INT_include = 1;
                     switch ($INTiS_config[$INTiS_key]['type']) {
                         case 'COA':
                             $incContent = $INTiS_cObj->cObjGetSingle('COA', $INTiS_config[$INTiS_key]['conf']);
@@ -3570,7 +3422,7 @@ class TypoScriptFrontendController
                             $incContent = $INTiS_cObj->callUserFunction($INTiS_config[$INTiS_key]['postUserFunc'], $INTiS_config[$INTiS_key]['conf'], $INTiS_config[$INTiS_key]['content']);
                             break;
                     }
-                    $this->content .= $this->convOutputCharset($incContent, 'INC-' . $INTiS_c);
+                    $this->content .= $this->convOutputCharset($incContent);
                     $this->content .= substr($INTiS_cPart, 35);
                     $timeTracker->pull($incContent);
                 } else {
@@ -3584,8 +3436,6 @@ class TypoScriptFrontendController
 
     /**
      * Loads the JavaScript code for INTincScript
-     *
-     * @return void
      */
     public function INTincScript_loadJSCode()
     {
@@ -3627,30 +3477,6 @@ class TypoScriptFrontendController
         return is_array($this->config['INTincScript']) && empty($this->activeUrlHandlers);
     }
 
-    /**
-     * Returns the mode of XHTML cleaning
-     *
-     * @return string Keyword: "all", "cached" or "output
-     * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8; The TypoScript option "config.xhtml_cleaning" has been deprecated
-     */
-    public function doXHTML_cleaning()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        return $this->config['config']['xhtml_cleaning'];
-    }
-
-    /**
-     * Returns the mode of Local Anchor prefixing
-     *
-     * @return string Keyword: "all", "cached" or "output
-     * @deprecated The TypoScript option "config.prefixLocalAnchors" and the according method in TSFE have been deprecated with TYPO3 CMS 7 and will be removed with TYPO3 CMS 8.
-     */
-    public function doLocalAnchorFix()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        return isset($this->config['config']['prefixLocalAnchors']) ? $this->config['config']['prefixLocalAnchors'] : null;
-    }
-
     /********************************************
      *
      * Finished off; outputting, storing session data, statistics...
@@ -3667,9 +3493,9 @@ class TypoScriptFrontendController
         // Initialize by status if there is a Redirect URL
         $enableOutput = empty($this->activeUrlHandlers);
         // Call hook for possible disabling of output:
-        if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'])) {
-            $_params = array('pObj' => &$this, 'enableOutput' => &$enableOutput);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'] as $_funcRef) {
+        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'])) {
+            $_params = ['pObj' => &$this, 'enableOutput' => &$enableOutput];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
@@ -3682,8 +3508,6 @@ class TypoScriptFrontendController
      * This includes substituting the "username" comment, sending additional headers
      * (as defined in the TypoScript "config.additionalheaders" object), XHTML cleaning content (if configured)
      * Works on $this->content.
-     *
-     * @return void
      */
     public function processOutput()
     {
@@ -3702,25 +3526,7 @@ class TypoScriptFrontendController
             $this->sendCacheHeaders();
         }
         // Set headers, if any
-        if (!empty($this->config['config']['additionalHeaders'])) {
-            $headerArray = explode('|', $this->config['config']['additionalHeaders']);
-            GeneralUtility::deprecationLog('The TypoScript option "config.additionalHeaders" has been deprecated with TYPO3 CMS 7, and will be removed with CMS 8, please use the more flexible syntax config.additionalHeaders.10... to separate each header value.');
-            foreach ($headerArray as $headLine) {
-                $headLine = trim($headLine);
-                header($headLine);
-            }
-        }
-        if (is_array($this->config['config']['additionalHeaders.'])) {
-            ksort($this->config['config']['additionalHeaders.']);
-            foreach ($this->config['config']['additionalHeaders.'] as $options) {
-                header(
-                    trim($options['header']),
-                    // "replace existing headers" is turned on by default, unless turned off
-                    ($options['replace'] !== '0'),
-                    ((int)$options['httpResponseCode'] ?: null)
-                );
-            }
-        }
+        $this->sendAdditionalHeaders();
         // Send appropriate status code in case of temporary content
         if ($this->tempContent) {
             $this->addTempContentHttpHeaders();
@@ -3730,30 +3536,18 @@ class TypoScriptFrontendController
             $this->contentStrReplace();
         }
         // Hook for post-processing of page content before output:
-        if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'] as $_funcRef) {
+        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
-        // Send content-length header.
-        // Notice that all HTML content outside the length of the content-length header will be cut off!
-        // Therefore content of unknown length from included PHP-scripts and if admin users are logged
-        // in (admin panel might show...) or if debug mode is turned on, we disable it!
-        if (
-            (!isset($this->config['config']['enableContentLengthHeader']) || $this->config['config']['enableContentLengthHeader'])
-            && !$this->beUserLogin && !$this->TYPO3_CONF_VARS['FE']['debug']
-            && !$this->config['config']['debug'] && !$this->doWorkspacePreview()
-        ) {
-            header('Content-Length: ' . strlen($this->content));
-        }
     }
 
     /**
      * Send cache headers good for client/reverse proxy caching
      * This function should not be called if the page content is temporary (like for "Page is being generated..." message, but in that case it is ok because the config-variables are not yet available and so will not allow to send cache headers)
      *
-     * @return void
      * @co-author Ole Tange, Forbrugernes Hus, Denmark
      */
     public function sendCacheHeaders()
@@ -3765,19 +3559,19 @@ class TypoScriptFrontendController
         // Finally, when backend users are logged in, do not send cache headers at all (Admin Panel might be displayed for instance).
         if ($doCache && !$this->beUserLogin && !$this->doWorkspacePreview() && $loginsDeniedCfg) {
             // Build headers:
-            $headers = array(
+            $headers = [
                 'Expires: ' . gmdate('D, d M Y H:i:s T', $this->cacheExpires),
                 'ETag: "' . md5($this->content) . '"',
                 'Cache-Control: max-age=' . ($this->cacheExpires - $GLOBALS['EXEC_TIME']),
                 // no-cache
                 'Pragma: public'
-            );
+            ];
             $this->isClientCachable = true;
         } else {
             // Build headers:
-            $headers = array(
+            $headers = [
                 'Cache-Control: private'
-            );
+            ];
             $this->isClientCachable = false;
             // Now, if a backend user is logged in, tell him in the Admin Panel log what the caching status would have been:
             if ($this->beUserLogin) {
@@ -3816,13 +3610,11 @@ class TypoScriptFrontendController
 
     /**
      * Substitute various tokens in content. This should happen only if the content is not cached by proxies or client browsers.
-     *
-     * @return void
      */
     public function contentStrReplace()
     {
-        $search = array();
-        $replace = array();
+        $search = [];
+        $replace = [];
         // Substitutes username mark with the username
         if (!empty($this->fe_user->user['uid'])) {
             // User name:
@@ -3842,13 +3634,13 @@ class TypoScriptFrontendController
             $replace[] = $this->fe_user->get_URL_ID;
         }
         // Hook for supplying custom search/replace data
-        if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'])) {
-            $contentStrReplaceHooks = &$this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'];
+        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'])) {
+            $contentStrReplaceHooks = &$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'];
             if (is_array($contentStrReplaceHooks)) {
-                $_params = array(
+                $_params = [
                     'search' => &$search,
                     'replace' => &$replace
-                );
+                ];
                 foreach ($contentStrReplaceHooks as $_funcRef) {
                     GeneralUtility::callUserFunction($_funcRef, $_params, $this);
                 }
@@ -3861,8 +3653,6 @@ class TypoScriptFrontendController
 
     /**
      * Stores session data for the front end user
-     *
-     * @return void
      */
     public function storeSessionData()
     {
@@ -3870,34 +3660,15 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Sets the parsetime of the page.
-     *
-     * @return void
-     * @access private
-     */
-    public function setParseTime()
-    {
-        // Compensates for the time consumed with Back end user initialization.
-        $microtime_start = isset($GLOBALS['TYPO3_MISC']['microtime_start']) ? $GLOBALS['TYPO3_MISC']['microtime_start'] : null;
-        $microtime_end = isset($GLOBALS['TYPO3_MISC']['microtime_end']) ? $GLOBALS['TYPO3_MISC']['microtime_end'] : null;
-        $microtime_BE_USER_start = isset($GLOBALS['TYPO3_MISC']['microtime_BE_USER_start']) ? $GLOBALS['TYPO3_MISC']['microtime_BE_USER_start'] : null;
-        $microtime_BE_USER_end = isset($GLOBALS['TYPO3_MISC']['microtime_BE_USER_end']) ? $GLOBALS['TYPO3_MISC']['microtime_BE_USER_end'] : null;
-        $timeTracker = $this->getTimeTracker();
-        $this->scriptParseTime = $timeTracker->getMilliseconds($microtime_end) - $timeTracker->getMilliseconds($microtime_start) - ($timeTracker->getMilliseconds($microtime_BE_USER_end) - $timeTracker->getMilliseconds($microtime_BE_USER_start));
-    }
-
-    /**
      * Outputs preview info.
-     *
-     * @return void
      */
     public function previewInfo()
     {
         if ($this->fePreview !== 0) {
             $previewInfo = '';
-            if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo'])) {
-                $_params = array('pObj' => &$this);
-                foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo'] as $_funcRef) {
+            if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo'])) {
+                $_params = ['pObj' => &$this];
+                foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo'] as $_funcRef) {
                     $previewInfo .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
                 }
             }
@@ -3907,47 +3678,20 @@ class TypoScriptFrontendController
 
     /**
      * End-Of-Frontend hook
-     *
-     * @return void
      */
     public function hook_eofe()
     {
         // Call hook for end-of-frontend processing:
-        if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'])) {
-            $_params = array('pObj' => &$this);
-            foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'] as $_funcRef) {
+        if (isset($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']) && is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'])) {
+            $_params = ['pObj' => &$this];
+            foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'] as $_funcRef) {
                 GeneralUtility::callUserFunction($_funcRef, $_params, $this);
             }
         }
     }
 
     /**
-     * Returns a link to the BE login screen with redirect to the front-end
-     *
-     * @return string HTML, a tag for a link to the backend.
-     */
-    public function beLoginLinkIPList()
-    {
-        if (!empty($this->config['config']['beLoginLinkIPList'])) {
-            if (GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $this->config['config']['beLoginLinkIPList'])) {
-                $label = !$this->beUserLogin ? $this->config['config']['beLoginLinkIPList_login'] : $this->config['config']['beLoginLinkIPList_logout'];
-                if ($label) {
-                    if (!$this->beUserLogin) {
-                        $link = '<a href="' . htmlspecialchars((TYPO3_mainDir . 'index.php?redirect_url=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI')))) . '">' . $label . '</a>';
-                    } else {
-                        $link = '<a href="' . htmlspecialchars((TYPO3_mainDir . 'index.php?L=OUT&redirect_url=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI')))) . '">' . $label . '</a>';
-                    }
-                    return $link;
-                }
-            }
-        }
-        return '';
-    }
-
-    /**
      * Sends HTTP headers for temporary content. These headers prevent search engines from caching temporary content and asks them to revisit this page again.
-     *
-     * @return void
      */
     public function addTempContentHttpHeaders()
     {
@@ -3963,83 +3707,11 @@ class TypoScriptFrontendController
      * Various internal API functions
      *
      *******************************************/
-    /**
-     * Encryption (or decryption) of a single character.
-     * Within the given range the character is shifted with the supplied offset.
-     *
-     * @param int $n Ordinal of input character
-     * @param int $start Start of range
-     * @param int $end End of range
-     * @param int $offset Offset
-     * @return string encoded/decoded version of character
-     */
-    public function encryptCharcode($n, $start, $end, $offset)
-    {
-        $n = $n + $offset;
-        if ($offset > 0 && $n > $end) {
-            $n = $start + ($n - $end - 1);
-        } elseif ($offset < 0 && $n < $start) {
-            $n = $end - ($start - $n - 1);
-        }
-        return chr($n);
-    }
-
-    /**
-     * Encryption of email addresses for <A>-tags See the spam protection setup in TS 'config.'
-     *
-     * @param string $string Input string to en/decode: "mailto:blabla@bla.com
-     * @param bool $back If set, the process is reversed, effectively decoding, not encoding.
-     * @return string encoded/decoded version of $string
-     */
-    public function encryptEmail($string, $back = false)
-    {
-        $out = '';
-        if ($this->spamProtectEmailAddresses === 'ascii') {
-            $stringLength = strlen($string);
-            for ($a = 0; $a < $stringLength; $a++) {
-                $out .= '&#' . ord(substr($string, $a, 1)) . ';';
-            }
-        } else {
-            // like str_rot13() but with a variable offset and a wider character range
-            $len = strlen($string);
-            $offset = (int)$this->spamProtectEmailAddresses * ($back ? -1 : 1);
-            for ($i = 0; $i < $len; $i++) {
-                $charValue = ord($string[$i]);
-                // 0-9 . , - + / :
-                if ($charValue >= 43 && $charValue <= 58) {
-                    $out .= $this->encryptCharcode($charValue, 43, 58, $offset);
-                } elseif ($charValue >= 64 && $charValue <= 90) {
-                    // A-Z @
-                    $out .= $this->encryptCharcode($charValue, 64, 90, $offset);
-                } elseif ($charValue >= 97 && $charValue <= 122) {
-                    // a-z
-                    $out .= $this->encryptCharcode($charValue, 97, 122, $offset);
-                } else {
-                    $out .= $string[$i];
-                }
-            }
-        }
-        return $out;
-    }
-
-    /**
-     * Checks if a PHPfile may be included.
-     *
-     * @param string $incFile Relative path to php file
-     * @return bool Returns TRUE if $GLOBALS['TYPO3_CONF_VARS']['FE']['noPHPscriptInclude'] is not set OR if the file requested for inclusion is found in one of the allowed paths.
-     * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
-     */
-    public function checkFileInclude($incFile)
-    {
-        GeneralUtility::logDeprecatedFunction();
-        return !$this->TYPO3_CONF_VARS['FE']['noPHPscriptInclude'] || substr($incFile, 0, 4 + strlen(TYPO3_mainDir)) == TYPO3_mainDir . 'ext/' || substr($incFile, 0, 7 + strlen(TYPO3_mainDir)) == TYPO3_mainDir . 'sysext/' || substr($incFile, 0, 14) == 'typo3conf/ext/';
-    }
 
     /**
      * Creates an instance of ContentObjectRenderer in $this->cObj
      * This instance is used to start the rendering of the TypoScript template structure
      *
-     * @return void
      * @see pagegen.php
      */
     public function newCObj()
@@ -4051,7 +3723,6 @@ class TypoScriptFrontendController
     /**
      * Converts relative paths in the HTML source to absolute paths for fileadmin/, typo3conf/ext/ and media/ folders.
      *
-     * @return void
      * @access private
      * @see pagegen.php, INTincScript()
      */
@@ -4060,18 +3731,18 @@ class TypoScriptFrontendController
         if (!$this->absRefPrefix) {
             return;
         }
-        $search = array(
+        $search = [
             '"typo3temp/',
             '"typo3conf/ext/',
             '"' . TYPO3_mainDir . 'ext/',
             '"' . TYPO3_mainDir . 'sysext/'
-        );
-        $replace = array(
+        ];
+        $replace = [
             '"' . $this->absRefPrefix . 'typo3temp/',
             '"' . $this->absRefPrefix . 'typo3conf/ext/',
             '"' . $this->absRefPrefix . TYPO3_mainDir . 'ext/',
             '"' . $this->absRefPrefix . TYPO3_mainDir . 'sysext/'
-        );
+        ];
         /** @var $storageRepository StorageRepository */
         $storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
         $storages = $storageRepository->findAll();
@@ -4106,7 +3777,7 @@ class TypoScriptFrontendController
     {
         if ($this->baseUrl) {
             $urlParts = parse_url($url);
-            if ($urlParts['scheme'] === '' && $url[0] !== '/') {
+            if (empty($urlParts['scheme']) && $url[0] !== '/') {
                 $url = $this->baseUrl . $url;
             }
         }
@@ -4120,54 +3791,12 @@ class TypoScriptFrontendController
      *
      * @param string $typoScriptProperty Deprecated object or property
      * @param string $explanation Message or additional information
-     * @return void
      */
     public function logDeprecatedTyposcript($typoScriptProperty, $explanation = '')
     {
         $explanationText = $explanation !== '' ? ' - ' . $explanation : '';
         $this->getTimeTracker()->setTSlogMessage($typoScriptProperty . ' is deprecated.' . $explanationText, 2);
-        GeneralUtility::deprecationLog('TypoScript ' . $typoScriptProperty . ' is deprecated' . $explanationText);
-    }
-
-    /**
-     * Updates the tstamp field of a cache_md5params record to the current time.
-     *
-     * @param string $hash The hash string identifying the cache_md5params record for which to update the "tstamp" field to the current time.
-     * @return void
-     * @access private
-     */
-    public function updateMD5paramsRecord($hash)
-    {
-        $this->getDatabaseConnection()->exec_UPDATEquery('cache_md5params', 'md5hash=' . $this->getDatabaseConnection()->fullQuoteStr($hash, 'cache_md5params'), array('tstamp' => $GLOBALS['EXEC_TIME']));
-    }
-
-    /**
-     * Substitutes all occurencies of <a href="#"... in $this->content with <a href="[path-to-url]#"...
-     *
-     * @return void Works directly on $this->content
-     * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8
-     */
-    public function prefixLocalAnchorsWithScript()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        if (!$this->beUserLogin) {
-            if (!is_object($this->cObj)) {
-                $this->newCObj();
-            }
-            $scriptPath = $this->cObj->getUrlToCurrentLocation();
-        } else {
-            // To break less existing sites, we allow the REQUEST_URI to be used for the prefix
-            $scriptPath = GeneralUtility::getIndpEnv('REQUEST_URI');
-            // Disable the cache so that these URI will not be the ones to be cached
-            $this->disableCache();
-        }
-        $originalContent = $this->content;
-        $this->content = preg_replace('/(<(?:a|area).*?href=")(#[^"]*")/i', '${1}' . htmlspecialchars($scriptPath) . '${2}', $originalContent);
-        // There was an error in the call to preg_replace, so keep the original content (behavior prior to PHP 5.2)
-        if (preg_last_error() > 0) {
-            GeneralUtility::sysLog('preg_replace returned error-code: ' . preg_last_error() . ' in function prefixLocalAnchorsWithScript. Replacement not done!', 'cms', GeneralUtility::SYSLOG_SEVERITY_FATAL);
-            $this->content = $originalContent;
-        }
+        trigger_error('TypoScript property ' . $typoScriptProperty . ' is deprecated' . $explanationText, E_USER_DEPRECATED);
     }
 
     /********************************************
@@ -4185,12 +3814,11 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Returns the name of the workspace
+     * Returns the uid of the current workspace
      *
-     * @param bool $returnTitle If set, returns title of current workspace being previewed
-     * @return string|int|NULL If $returnTitle is set, returns string (title), otherwise workspace integer for which workspace is being preview. NULL if none.
+     * @return int|NULL returns workspace integer for which workspace is being preview. NULL if none.
      */
-    public function whichWorkspace($returnTitle = false)
+    public function whichWorkspace()
     {
         $ws = null;
         if ($this->doWorkspacePreview()) {
@@ -4198,68 +3826,14 @@ class TypoScriptFrontendController
         } elseif ($this->beUserLogin) {
             $ws = $this->getBackendUser()->workspace;
         }
-        if ($ws && $returnTitle) {
-            if (ExtensionManagementUtility::isLoaded('workspaces')) {
-                $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('title', 'sys_workspace', 'uid=' . (int)$ws);
-                if ($row) {
-                    return $row['title'];
-                }
-            }
-        }
         return $ws;
     }
 
-    /**
-     * Includes a comma-separated list of library files by PHP function include_once.
-     *
-     * @param array $libraries The libraries to be included.
-     * @return void
-     * @todo deprecate this method
-     */
-    public function includeLibraries(array $libraries)
-    {
-        $timeTracker = $this->getTimeTracker();
-        $timeTracker->push('Include libraries');
-        $timeTracker->setTSlogMessage('Files for inclusion: "' . implode(', ', $libraries) . '"');
-        foreach ($libraries as $library) {
-            $file = $this->tmpl->getFileName($library);
-            if ($file) {
-                include_once './' . $file;
-            } else {
-                $timeTracker->setTSlogMessage('Include file "' . $file . '" did not exist!', 2);
-            }
-        }
-        $timeTracker->pull();
-    }
-
     /********************************************
      *
      * Various external API functions - for use in plugins etc.
      *
      *******************************************/
-    /**
-     * Traverses the ->rootLine and returns an array with the first occurrance of storage pid and siteroot pid
-     *
-     * @return array Array with keys '_STORAGE_PID' and '_SITEROOT' set to the first occurrences found.
-     * @deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8. The usage of "storage_pid" is discouraged, the option for "is_siteroot" is handled via the RootlineUtility directly.
-     */
-    public function getStorageSiterootPids()
-    {
-        GeneralUtility::logDeprecatedFunction();
-        $res = array();
-        if (!is_array($this->rootLine)) {
-            return array();
-        }
-        foreach ($this->rootLine as $rC) {
-            if (!$res['_STORAGE_PID']) {
-                $res['_STORAGE_PID'] = (int)$rC['storage_pid'];
-            }
-            if (!$res['_SITEROOT']) {
-                $res['_SITEROOT'] = $rC['is_siteroot'] ? (int)$rC['uid'] : 0;
-            }
-        }
-        return $res;
-    }
 
     /**
      * Returns the pages TSconfig array based on the currect ->rootLine
@@ -4269,26 +3843,25 @@ class TypoScriptFrontendController
     public function getPagesTSconfig()
     {
         if (!is_array($this->pagesTSconfig)) {
-            $TSdataArray = array();
+            $TSdataArray = [];
             foreach ($this->rootLine as $k => $v) {
                 $TSdataArray[] = $v['TSconfig'];
             }
             // Adding the default configuration:
-            $TSdataArray[] = $this->TYPO3_CONF_VARS['BE']['defaultPageTSconfig'];
+            $TSdataArray[] = $GLOBALS['TYPO3_CONF_VARS']['BE']['defaultPageTSconfig'];
             // Bring everything in the right order. Default first, then the Rootline down to the current page
             $TSdataArray = array_reverse($TSdataArray);
             // Parsing the user TS (or getting from cache)
             $TSdataArray = TypoScriptParser::checkIncludeLines_array($TSdataArray);
             $userTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
-            $hash = md5('pageTS:' . $userTS);
-            $cachedContent = $this->sys_page->getHash($hash);
-            if (is_array($cachedContent)) {
-                $this->pagesTSconfig = $cachedContent;
-            } else {
+            $identifier = md5('pageTS:' . $userTS);
+            $contentHashCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash');
+            $this->pagesTSconfig = $contentHashCache->get($identifier);
+            if (!is_array($this->pagesTSconfig)) {
                 $parseObj = GeneralUtility::makeInstance(TypoScriptParser::class);
                 $parseObj->parse($userTS);
                 $this->pagesTSconfig = $parseObj->setup;
-                $this->sys_page->storeHash($hash, $this->pagesTSconfig, 'PAGES_TSconfig');
+                $contentHashCache->set($identifier, $this->pagesTSconfig, ['PAGES_TSconfig'], 0);
             }
         }
         return $this->pagesTSconfig;
@@ -4299,7 +3872,6 @@ class TypoScriptFrontendController
      *
      * @param string $key is the key in the array, for num-key let the value be empty. Note reserved keys 'openPic' and 'mouseOver'
      * @param string $content is the content if you want any
-     * @return void
      * @see \TYPO3\CMS\Frontend\ContentObject\Menu\GraphicalMenuContentObject::writeMenu(), ContentObjectRenderer::imageLinkWrap()
      */
     public function setJS($key, $content = '')
@@ -4309,13 +3881,13 @@ class TypoScriptFrontendController
                 case 'mouseOver':
                     $this->additionalJavaScript[$key] = '              // JS function for mouse-over
                function over(name, imgObj) {   //
-                       if (version == "n3" && document[name]) {document[name].src = eval(name+"_h.src");}
+                       if (document[name]) {document[name].src = eval(name+"_h.src");}
                        else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_h.src");}
                        else if (imgObj)        {imgObj.src = eval(name+"_h.src");}
                }
                        // JS function for mouse-out
                function out(name, imgObj) {    //
-                       if (version == "n3" && document[name]) {document[name].src = eval(name+"_n.src");}
+                       if (document[name]) {document[name].src = eval(name+"_n.src");}
                        else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_n.src");}
                        else if (imgObj)        {imgObj.src = eval(name+"_n.src");}
                }';
@@ -4337,7 +3909,6 @@ class TypoScriptFrontendController
      *
      * @param string $key Is the key in the array, for num-key let the value be empty
      * @param string $content Is the content if you want any
-     * @return void
      * @see setJS()
      */
     public function setCSS($key, $content)
@@ -4362,26 +3933,19 @@ class TypoScriptFrontendController
     /**
      * Sets the cache-flag to 1. Could be called from user-included php-files in order to ensure that a page is not cached.
      *
-     * @param string $reason An optional reason to be written to the syslog.
+     * @param string $reason An optional reason to be written to the log.
      * @param bool $internal Whether the call is done from core itself (should only be used by core).
-     * @return void
      */
     public function set_no_cache($reason = '', $internal = false)
     {
-        if ($internal && isset($GLOBALS['BE_USER'])) {
-            $severity = GeneralUtility::SYSLOG_SEVERITY_NOTICE;
-        } else {
-            $severity = GeneralUtility::SYSLOG_SEVERITY_WARNING;
-        }
-
         if ($reason !== '') {
             $warning = '$TSFE->set_no_cache() was triggered. Reason: ' . $reason . '.';
         } else {
-            $trace = debug_backtrace();
+            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
             // This is a hack to work around ___FILE___ resolving symbolic links
             $PATH_site_real = dirname(realpath(PATH_site . 'typo3')) . '/';
             $file = $trace[0]['file'];
-            if (StringUtility::beginsWith($file, $PATH_site_real)) {
+            if (strpos($file, $PATH_site_real) === 0) {
                 $file = str_replace($PATH_site_real, '', $file);
             } else {
                 $file = str_replace(PATH_site, '', $file);
@@ -4390,20 +3954,23 @@ class TypoScriptFrontendController
             $trigger = $file . ' on line ' . $line;
             $warning = '$GLOBALS[\'TSFE\']->set_no_cache() was triggered by ' . $trigger . '.';
         }
-        if ($this->TYPO3_CONF_VARS['FE']['disableNoCacheParameter']) {
+        if ($GLOBALS['TYPO3_CONF_VARS']['FE']['disableNoCacheParameter']) {
             $warning .= ' However, $TYPO3_CONF_VARS[\'FE\'][\'disableNoCacheParameter\'] is set, so it will be ignored!';
             $this->getTimeTracker()->setTSlogMessage($warning, 2);
         } else {
             $warning .= ' Caching is disabled!';
             $this->disableCache();
         }
-        GeneralUtility::sysLog($warning, 'cms', $severity);
+        if ($internal && isset($GLOBALS['BE_USER'])) {
+            $this->logger->notice($warning);
+        } else {
+            $this->logger->warning($warning);
+        }
     }
 
     /**
      * Disables caching of the current page.
      *
-     * @return void
      * @internal
      */
     protected function disableCache()
@@ -4415,7 +3982,6 @@ class TypoScriptFrontendController
      * Sets the cache-timeout in seconds
      *
      * @param int $seconds Cache-timeout in seconds
-     * @return void
      */
     public function set_cache_timeout_default($seconds)
     {
@@ -4457,9 +4023,9 @@ class TypoScriptFrontendController
             // Calculate the timeout time for records on the page and adjust cache timeout if necessary
             $cacheTimeout = min($this->calculatePageCacheTimeout(), $cacheTimeout);
 
-            if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout'])) {
-                foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout'] as $_funcRef) {
-                    $params = array('cacheTimeout' => $cacheTimeout);
+            if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout'])) {
+                foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout'] as $_funcRef) {
+                    $params = ['cacheTimeout' => $cacheTimeout];
                     $cacheTimeout = GeneralUtility::callUserFunction($_funcRef, $params, $this);
                 }
             }
@@ -4503,27 +4069,7 @@ class TypoScriptFrontendController
      */
     public function sL($input)
     {
-        if (substr($input, 0, 4) !== 'LLL:') {
-            // Not a label, return the key as this
-            return $input;
-        }
-        // If cached label
-        if (!isset($this->LL_labels_cache[$this->lang][$input])) {
-            $restStr = trim(substr($input, 4));
-            $extPrfx = '';
-            if (substr($restStr, 0, 4) === 'EXT:') {
-                $restStr = trim(substr($restStr, 4));
-                $extPrfx = 'EXT:';
-            }
-            $parts = explode(':', $restStr);
-            $parts[0] = $extPrfx . $parts[0];
-            // Getting data if not cached
-            if (!isset($this->LL_files_cache[$parts[0]])) {
-                $this->LL_files_cache[$parts[0]] = $this->readLLfile($parts[0]);
-            }
-            $this->LL_labels_cache[$this->lang][$input] = $this->getLLL($parts[1], $this->LL_files_cache[$parts[0]]);
-        }
-        return $this->LL_labels_cache[$this->lang][$input];
+        return $this->languageService->sL($input);
     }
 
     /**
@@ -4531,37 +4077,12 @@ class TypoScriptFrontendController
      *
      * @param string $fileRef Reference to a relative filename to include.
      * @return array Returns the $LOCAL_LANG array found in the file. If no array found, returns empty array.
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10
      */
     public function readLLfile($fileRef)
     {
-        /** @var $languageFactory LocalizationFactory */
-        $languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
-
-        if ($this->lang !== 'default') {
-            $languages = array_reverse($this->languageDependencies);
-            // At least we need to have English
-            if (empty($languages)) {
-                $languages[] = 'default';
-            }
-        } else {
-            $languages = array('default');
-        }
-
-        $localLanguage = array();
-        foreach ($languages as $language) {
-            $tempLL = $languageFactory->getParsedData($fileRef, $language, $this->renderCharset);
-            $localLanguage['default'] = $tempLL['default'];
-            if (!isset($localLanguage[$this->lang])) {
-                $localLanguage[$this->lang] = $localLanguage['default'];
-            }
-            if ($this->lang !== 'default' && isset($tempLL[$language])) {
-                // Merge current language labels onto labels from previous language
-                // This way we have a label with fall back applied
-                ArrayUtility::mergeRecursiveWithOverrule($localLanguage[$this->lang], $tempLL[$language], true, false);
-            }
-        }
-
-        return $localLanguage;
+        trigger_error('This method will be removed in TYPO3 v10, as the method LanguageService->includeLLFile() can be used directly.', E_USER_DEPRECATED);
+        return $this->languageService->includeLLFile($fileRef, false, true);
     }
 
     /**
@@ -4570,12 +4091,15 @@ class TypoScriptFrontendController
      * @param string $index Local_lang key for which to return label (language is determined by $this->lang)
      * @param array $LOCAL_LANG The locallang array in which to search
      * @return string Label value of $index key.
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10, use LanguageService->getLLL() directly
      */
     public function getLLL($index, $LOCAL_LANG)
     {
+        trigger_error('This method will be removed in TYPO3 v10, as the method LanguageService->getLLL() can be used directly.', E_USER_DEPRECATED);
         if (isset($LOCAL_LANG[$this->lang][$index][0]['target'])) {
             return $LOCAL_LANG[$this->lang][$index][0]['target'];
-        } elseif (isset($LOCAL_LANG['default'][$index][0]['target'])) {
+        }
+        if (isset($LOCAL_LANG['default'][$index][0]['target'])) {
             return $LOCAL_LANG['default'][$index][0]['target'];
         }
         return false;
@@ -4584,85 +4108,81 @@ class TypoScriptFrontendController
     /**
      * Initializing the getLL variables needed.
      *
-     * @return void
+     * @see settingLanguage()
+     * @deprecated since TYPO3 v9, will be removed in TYPO3 v10.
      */
     public function initLLvars()
     {
-        // Init languageDependencies list
-        $this->languageDependencies = array();
-        // Setting language key and split index:
+        trigger_error('This method will be removed in TYPO3 v10, the initialization can be altered via hooks within settingLanguage().', E_USER_DEPRECATED);
         $this->lang = $this->config['config']['language'] ?: 'default';
-        $this->pageRenderer->setLanguage($this->lang);
-
-        // Finding the requested language in this list based
-        // on the $lang key being inputted to this function.
-        /** @var $locales Locales */
-        $locales = GeneralUtility::makeInstance(Locales::class);
-        $locales->initialize();
-
-        // Language is found. Configure it:
-        if (in_array($this->lang, $locales->getLocales())) {
-            $this->languageDependencies[] = $this->lang;
-            foreach ($locales->getLocaleDependencies($this->lang) as $language) {
-                $this->languageDependencies[] = $language;
-            }
-        }
+        $this->setOutputLanguage($this->lang);
 
-        // Setting charsets:
-        $this->renderCharset = $this->csConvObj->parse_charset($this->config['config']['renderCharset'] ? $this->config['config']['renderCharset'] : 'utf-8');
         // Rendering charset of HTML page.
-        $this->metaCharset = $this->csConvObj->parse_charset($this->config['config']['metaCharset'] ? $this->config['config']['metaCharset'] : $this->renderCharset);
+        if ($this->config['config']['metaCharset']) {
+            $this->metaCharset = trim(strtolower($this->config['config']['metaCharset']));
+        }
     }
 
     /**
-     * Converts the charset of the input string if applicable.
-     * The "to" charset is determined by the currently used charset for the page which is "utf-8" by default or set by $GLOBALS['TSFE']->config['config']['renderCharset']
-     * Only if there is a difference between the two charsets will a conversion be made
-     * The conversion is done real-time - no caching for performance at this point!
+     * Sets all internal measures what language the page should be rendered.
+     * This is not for records, but rather the HTML / charset and the locallang labels
      *
-     * @param string $str String to convert charset for
-     * @param string $from Optional "from" charset.
-     * @return string Output string, converted if needed.
-     * @see CharsetConverter
+     * @param string $language - usually set via TypoScript config.language = dk
      */
-    public function csConv($str, $from = '')
+    protected function setOutputLanguage($language = 'default')
     {
-        if ($from) {
-            $output = $this->csConvObj->conv($str, $this->csConvObj->parse_charset($from), $this->renderCharset, 1);
-            return $output ?: $str;
-        } else {
-            return $str;
-        }
+        $this->pageRenderer->setLanguage($language);
+        $this->languageService = GeneralUtility::makeInstance(LanguageService::class);
+        // Always disable debugging for TSFE
+        $this->languageService->debugKey = false;
+        $this->languageService->init($language);
     }
 
     /**
-     * Converts input string from renderCharset to metaCharset IF the two charsets are different.
+     * Converts input string from utf-8 to metaCharset IF the two charsets are different.
      *
      * @param string $content Content to be converted.
      * @return string Converted content string.
      */
     public function convOutputCharset($content)
     {
-        if ($this->renderCharset != $this->metaCharset) {
-            $content = $this->csConvObj->conv($content, $this->renderCharset, $this->metaCharset, true);
+        if ($this->metaCharset !== 'utf-8') {
+            /** @var CharsetConverter $charsetConverter */
+            $charsetConverter = GeneralUtility::makeInstance(CharsetConverter::class);
+            $content = $charsetConverter->conv($content, 'utf-8', $this->metaCharset, true);
         }
         return $content;
     }
 
     /**
-     * Converts the $_POST array from metaCharset (page HTML charset from input form) to renderCharset (internal processing) IF the two charsets are different.
-     *
-     * @return void
+     * Converts the $_POST array from metaCharset (page HTML charset from input form) to utf-8 (internal processing) IF the two charsets are different.
      */
     public function convPOSTCharset()
     {
-        if ($this->renderCharset != $this->metaCharset && is_array($_POST) && !empty($_POST)) {
-            $this->csConvObj->convArray($_POST, $this->metaCharset, $this->renderCharset);
+        if ($this->metaCharset !== 'utf-8' && is_array($_POST) && !empty($_POST)) {
+            $this->convertCharsetRecursivelyToUtf8($_POST, $this->metaCharset);
             $GLOBALS['HTTP_POST_VARS'] = $_POST;
         }
     }
 
     /**
+     * Small helper function to convert charsets for arrays to UTF-8
+     *
+     * @param mixed $data given by reference (string/array usually)
+     * @param string $fromCharset convert FROM this charset
+     */
+    protected function convertCharsetRecursivelyToUtf8(&$data, string $fromCharset)
+    {
+        foreach ($data as $key => $value) {
+            if (is_array($data[$key])) {
+                $this->convertCharsetRecursivelyToUtf8($data[$key], $fromCharset);
+            } elseif (is_string($data[$key])) {
+                $data[$key] = mb_convert_encoding($data[$key], 'utf-8', $fromCharset);
+            }
+        }
+    }
+
+    /**
      * Calculates page cache timeout according to the records with starttime/endtime on the page.
      *
      * @return int Page cache timeout or PHP_INT_MAX if cannot be determined
@@ -4672,9 +4192,9 @@ class TypoScriptFrontendController
         $result = PHP_INT_MAX;
         // Get the configuration
         $tablesToConsider = $this->getCurrentPageCacheConfiguration();
-        // Get the time, rounded to the minute (do not polute MySQL cache!)
+        // Get the time, rounded to the minute (do not pollute MySQL cache!)
         // It is ok that we do not take seconds into account here because this
-        // value will be substracted later. So we never get the time "before"
+        // value will be subtracted later. So we never get the time "before"
         // the cache change.
         $now = $GLOBALS['ACCESS_TIME'];
         // Find timeout by checking every table
@@ -4682,7 +4202,7 @@ class TypoScriptFrontendController
             $result = min($result, $this->getFirstTimeValueForRecord($tableDef, $now));
         }
         // We return + 1 second just to ensure that cache is definitely regenerated
-        return $result == PHP_INT_MAX ? PHP_INT_MAX : $result - $now + 1;
+        return $result === PHP_INT_MAX ? PHP_INT_MAX : $result - $now + 1;
     }
 
     /**
@@ -4701,7 +4221,7 @@ class TypoScriptFrontendController
      */
     protected function getCurrentPageCacheConfiguration()
     {
-        $result = array('tt_content:' . $this->id);
+        $result = ['tt_content:' . $this->id];
         if (isset($this->config['config']['cache.'][$this->id])) {
             $result = array_merge($result, GeneralUtility::trimExplode(',', $this->config['config']['cache.'][$this->id]));
         }
@@ -4722,44 +4242,57 @@ class TypoScriptFrontendController
      */
     protected function getFirstTimeValueForRecord($tableDef, $now)
     {
+        $now = (int)$now;
         $result = PHP_INT_MAX;
         list($tableName, $pid) = GeneralUtility::trimExplode(':', $tableDef);
         if (empty($tableName) || empty($pid)) {
             throw new \InvalidArgumentException('Unexpected value for parameter $tableDef. Expected <tablename>:<pid>, got \'' . htmlspecialchars($tableDef) . '\'.', 1307190365);
         }
-        // Additional fields
-        $showHidden = $tableName === 'pages' ? $this->showHiddenPage : $this->showHiddenRecords;
-        $enableFields = $this->sys_page->enableFields(
-            $tableName,
-            $showHidden,
-            array('starttime' => true, 'endtime' => true)
-        );
 
-        $timeFields = array();
-        $selectFields = array();
-        $whereConditions = array();
-        foreach (array('starttime', 'endtime') as $field) {
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
+            ->getQueryBuilderForTable($tableName);
+        $queryBuilder->getRestrictions()
+            ->removeByType(StartTimeRestriction::class)
+            ->removeByType(EndTimeRestriction::class);
+        $timeFields = [];
+        $timeConditions = $queryBuilder->expr()->orX();
+        foreach (['starttime', 'endtime'] as $field) {
             if (isset($GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field])) {
                 $timeFields[$field] = $GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field];
-                $selectFields[$field]
-                    = 'MIN('
-                        . 'CASE WHEN ' . $timeFields[$field] . ' <= ' . $now
-                        . ' THEN NULL ELSE ' . $timeFields[$field] . ' END'
-                        . ') AS ' . $field;
-                $whereConditions[$field] = $timeFields[$field] . '>' . $now;
+                $queryBuilder->addSelectLiteral(
+                    'MIN('
+                        . 'CASE WHEN '
+                        . $queryBuilder->expr()->lte(
+                            $timeFields[$field],
+                            $queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
+                        )
+                        . ' THEN NULL ELSE ' . $queryBuilder->quoteIdentifier($timeFields[$field]) . ' END'
+                        . ') AS ' . $queryBuilder->quoteIdentifier($timeFields[$field])
+                );
+                $timeConditions->add(
+                    $queryBuilder->expr()->gt(
+                        $timeFields[$field],
+                        $queryBuilder->createNamedParameter($now, \PDO::PARAM_INT)
+                    )
+                );
             }
         }
 
         // if starttime or endtime are defined, evaluate them
         if (!empty($timeFields)) {
             // find the timestamp, when the current page's content changes the next time
-            $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
-                implode(', ', $selectFields),
-                $tableName,
-                'pid=' . (int)$pid
-                . ' AND (' . implode(' OR ', $whereConditions) . ')'
-                . $enableFields
-            );
+            $row = $queryBuilder
+                ->from($tableName)
+                ->where(
+                    $queryBuilder->expr()->eq(
+                        'pid',
+                        $queryBuilder->createNamedParameter($pid, \PDO::PARAM_INT)
+                    ),
+                    $timeConditions
+                )
+                ->execute()
+                ->fetch();
+
             if ($row) {
                 foreach ($timeFields as $timeField => $_) {
                     // if a MIN value is found, take it into account for the
@@ -4777,7 +4310,6 @@ class TypoScriptFrontendController
         return $result;
     }
 
-
     /**
      * Fetches/returns the cached contents of the sys_domain database table.
      *
@@ -4789,19 +4321,25 @@ class TypoScriptFrontendController
         /** @var $runtimeCache \TYPO3\CMS\Core\Cache\Frontend\AbstractFrontend */
         $runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
 
-        $sysDomainData = array();
+        $sysDomainData = [];
         if ($runtimeCache->has($entryIdentifier)) {
             $sysDomainData = $runtimeCache->get($entryIdentifier);
         } else {
-            $domainRecords = $this->getDatabaseConnection()->exec_SELECTgetRows(
-                'uid, pid, domainName, forced',
-                'sys_domain',
-                'redirectTo=\'\' ' . $this->sys_page->enableFields('sys_domain', 0),
-                '',
-                'sorting ASC'
-            );
+            $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_domain');
+            $queryBuilder->setRestrictions(GeneralUtility::makeInstance(DefaultRestrictionContainer::class));
+            $result = $queryBuilder
+                ->select('uid', 'pid', 'domainName', 'forced')
+                ->from('sys_domain')
+                ->where(
+                    $queryBuilder->expr()->eq(
+                        'redirectTo',
+                        $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
+                    )
+                )
+                ->orderBy('sorting', 'ASC')
+                ->execute();
 
-            foreach ($domainRecords as $row) {
+            while ($row = $result->fetch()) {
                 // if there is already an entry for this pid, check if we should overwrite it
                 if (isset($sysDomainData[$row['pid']])) {
                     // There is already a "forced" entry, which must not be overwritten
@@ -4816,12 +4354,12 @@ class TypoScriptFrontendController
                 }
 
                 // as we passed all previous checks, we save this domain for the current pid
-                $sysDomainData[$row['pid']] = array(
+                $sysDomainData[$row['pid']] = [
                     'uid' => $row['uid'],
                     'pid' => $row['pid'],
                     'domainName' => rtrim($row['domainName'], '/'),
                     'forced' => $row['forced'],
-                );
+                ];
             }
             $runtimeCache->set($entryIdentifier, $sysDomainData);
         }
@@ -4938,9 +4476,8 @@ class TypoScriptFrontendController
             $this->locks[$type]['accessLock']->release();
             if ($locked) {
                 break;
-            } else {
-                throw new \RuntimeException('Could not acquire page lock for ' . $key . '.', 1294586098);
             }
+            throw new \RuntimeException('Could not acquire page lock for ' . $key . '.', 1460975877);
         } while (true);
     }
 
@@ -4956,7 +4493,7 @@ class TypoScriptFrontendController
     {
         if ($this->locks[$type]['accessLock']) {
             if (!$this->locks[$type]['accessLock']->acquire()) {
-                throw new \RuntimeException('Could not acquire access lock for "' . $type . '"".', 1294586098);
+                throw new \RuntimeException('Could not acquire access lock for "' . $type . '"".', 1460975902);
             }
 
             $this->locks[$type]['pageLock']->release();
@@ -4969,40 +4506,61 @@ class TypoScriptFrontendController
     }
 
     /**
-     * Returns the current BE user.
+     * Send additional headers from config.additionalHeaders
      *
-     * @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
+     * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::processOutput()
      */
-    protected function getBackendUser()
+    protected function sendAdditionalHeaders()
     {
-        return $GLOBALS['BE_USER'];
+        if (!isset($this->config['config']['additionalHeaders.'])) {
+            return;
+        }
+        ksort($this->config['config']['additionalHeaders.']);
+        foreach ($this->config['config']['additionalHeaders.'] as $options) {
+            if (!is_array($options)) {
+                continue;
+            }
+            $header = $options['header'] ?? '';
+            $header = isset($options['header.'])
+                ? $this->cObj->stdWrap(trim($header), $options['header.'])
+                : trim($header);
+            if ($header === '') {
+                continue;
+            }
+            $replace = $options['replace'] ?? '';
+            $replace = isset($options['replace.'])
+                ? $this->cObj->stdWrap($replace, $options['replace.'])
+                : $replace;
+            $httpResponseCode = $options['httpResponseCode'] ?? '';
+            $httpResponseCode = isset($options['httpResponseCode.'])
+                ? $this->cObj->stdWrap($httpResponseCode, $options['httpResponseCode.'])
+                : $httpResponseCode;
+            $httpResponseCode = (int)$httpResponseCode;
+
+            header(
+                $header,
+                // "replace existing headers" is turned on by default, unless turned off
+                $replace !== '0',
+                $httpResponseCode ?: null
+            );
+        }
     }
 
     /**
-     * Returns the database connection
+     * Returns the current BE user.
      *
-     * @return \TYPO3\CMS\Core\Database\DatabaseConnection
+     * @return \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
      */
-    protected function getDatabaseConnection()
+    protected function getBackendUser()
     {
-        return $GLOBALS['TYPO3_DB'];
+        return $GLOBALS['BE_USER'];
     }
 
     /**
-     * @return \TYPO3\CMS\Core\TimeTracker\TimeTracker
+     * @return TimeTracker
      */
     protected function getTimeTracker()
     {
-        return $GLOBALS['TT'];
-    }
-
-    /**
-     * Returns an instance of DocumentTemplate
-     *
-     * @return \TYPO3\CMS\Backend\Template\DocumentTemplate
-     */
-    protected function getDocumentTemplate()
-    {
-        return $GLOBALS['TBE_TEMPLATE'];
+        return GeneralUtility::makeInstance(TimeTracker::class);
     }
 }