use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;
use TYPO3\CMS\Frontend\Http\UrlHandlerInterface;
use TYPO3\CMS\Frontend\Page\CacheHashCalculator;
+use TYPO3\CMS\Frontend\Page\PageAccessFailureReasons;
use TYPO3\CMS\Frontend\Page\PageRepository;
/**
);
$this->logger->emergency($message, ['exception' => $exception]);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction($GLOBALS['TYPO3_REQUEST'], $message);
+ $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ ['code' => PageAccessFailureReasons::DATABASE_CONNECTION_FAILED]
+ );
$this->sendResponseAndExit($response);
} catch (ServiceUnavailableException $e) {
throw new ServiceUnavailableException($message, 1301648782);
$message = 'No pages are found on the rootlevel!';
$this->logger->alert($message);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction($GLOBALS['TYPO3_REQUEST'], $message);
+ $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ ['code' => PageAccessFailureReasons::NO_PAGES_FOUND]
+ );
$this->sendResponseAndExit($response);
} catch (ServiceUnavailableException $e) {
throw new ServiceUnavailableException($message, 1301648975);
}
$timeTracker->pull();
if ($this->pageNotFound) {
- $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'
- ];
- $message = $pNotFoundMsg[$this->pageNotFound];
- if ($this->pageNotFound === 1 || $this->pageNotFound === 2) {
- $response = GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction($GLOBALS['TYPO3_REQUEST'], $message, $this->getPageAccessFailureReasons());
- } else {
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], $message, $this->getPageAccessFailureReasons());
+ switch ($this->pageNotFound) {
+ case 1:
+ $response = GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'ID was not an accessible page',
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::ACCESS_DENIED_PAGE_NOT_RESOLVED)
+ );
+ break;
+ case 2:
+ $response = GeneralUtility::makeInstance(ErrorController::class)->accessDeniedAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Subsection was found and not accessible',
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::ACCESS_DENIED_SUBSECTION_NOT_RESOLVED)
+ );
+ break;
+ case 3:
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'ID was outside the domain',
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::ACCESS_DENIED_HOST_PAGE_MISMATCH)
+ );
+ break;
+ case 4:
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'The requested page alias does not exist',
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::PAGE_ALIAS_NOT_FOUND)
+ );
+ break;
+ default:
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Unspecified error',
+ $this->getPageAccessFailureReasons()
+ );
}
$this->sendResponseAndExit($response);
}
$message = 'The requested page does not exist!';
$this->logger->error($message);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], $message, $this->getPageAccessFailureReasons());
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::PAGE_NOT_FOUND)
+ );
$this->sendResponseAndExit($response);
} catch (PageNotFoundException $e) {
throw new PageNotFoundException($message, 1301648780);
$message = 'The requested page does not exist!';
$this->logger->error($message);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], $message, $this->getPageAccessFailureReasons());
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::ACCESS_DENIED_INVALID_PAGETYPE)
+ );
$this->sendResponseAndExit($response);
} catch (PageNotFoundException $e) {
throw new PageNotFoundException($message, 1301648781);
$message = 'The requested page didn\'t have a proper connection to the tree-root!';
$this->logger->error($message);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction($GLOBALS['TYPO3_REQUEST'], $message, $this->getPageAccessFailureReasons());
+ $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::ROOTLINE_BROKEN)
+ );
$this->sendResponseAndExit($response);
} catch (ServiceUnavailableException $e) {
throw new ServiceUnavailableException($message, 1301648167);
if (empty($this->rootLine)) {
$message = 'The requested page was not accessible!';
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction($GLOBALS['TYPO3_REQUEST'], $message, $this->getPageAccessFailureReasons());
+ $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ $this->getPageAccessFailureReasons(PageAccessFailureReasons::ACCESS_DENIED_GENERAL)
+ );
$this->sendResponseAndExit($response);
} catch (ServiceUnavailableException $e) {
$this->logger->warning($message);
/**
* Analysing $this->pageAccessFailureHistory into a summary array telling which features disabled display and on which pages and conditions. That data can be used inside a page-not-found handler
*
+ * @param string $failureReasonCode the error code to be attached (optional), see PageAccessFailureReasons list for details
* @return array Summary of why page access was not allowed.
*/
- public function getPageAccessFailureReasons()
+ public function getPageAccessFailureReasons(string $failureReasonCode = null)
{
$output = [];
+ if ($failureReasonCode) {
+ $output['code'] = $failureReasonCode;
+ }
$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) {
$cHash_calc = $this->cacheHash->calculateCacheHash($this->cHash_array);
if (!hash_equals($cHash_calc, $this->cHash)) {
if ($GLOBALS['TYPO3_CONF_VARS']['FE']['pageNotFoundOnCHashError']) {
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], 'Request parameters could not be validated (&cHash comparison failed)');
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Request parameters could not be validated (&cHash comparison failed)',
+ ['code' => PageAccessFailureReasons::CACHEHASH_COMPARISON_FAILED]
+ );
$this->sendResponseAndExit($response);
} else {
$this->disableCache();
if ($this->tempContent) {
$this->clearPageCacheContent();
}
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], 'Request parameters could not be validated (&cHash empty)');
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Request parameters could not be validated (&cHash empty)',
+ ['code' => PageAccessFailureReasons::CACHEHASH_EMPTY]
+ );
$this->sendResponseAndExit($response);
} else {
$this->disableCache();
$message = 'The page is not configured! [type=' . $this->type . '][' . $this->sPre . '].';
$this->logger->alert($message);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction($GLOBALS['TYPO3_REQUEST'], $message);
+ $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ ['code' => PageAccessFailureReasons::RENDERING_INSTRUCTIONS_NOT_CONFIGURED]
+ );
$this->sendResponseAndExit($response);
} catch (ServiceUnavailableException $e) {
$explanation = 'This means that there is no TypoScript object of type PAGE with typeNum=' . $this->type . ' configured.';
$message = 'No TypoScript template found!';
$this->logger->alert($message);
try {
- $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction($GLOBALS['TYPO3_REQUEST'], $message);
+ $response = GeneralUtility::makeInstance(ErrorController::class)->unavailableAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ ['code' => PageAccessFailureReasons::RENDERING_INSTRUCTIONS_NOT_FOUND]
+ );
$this->sendResponseAndExit($response);
} catch (ServiceUnavailableException $e) {
throw new ServiceUnavailableException($message, 1294587218);
if ($this->sys_language_uid) {
// If requested translation is not available:
if (GeneralUtility::hideIfNotTranslated($this->page['l18n_cfg'])) {
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], 'Page is not available in the requested language.');
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Page is not available in the requested language.',
+ ['code' => PageAccessFailureReasons::LANGUAGE_NOT_AVAILABLE]
+ );
$this->sendResponseAndExit($response);
} else {
switch ((string)$this->sys_language_mode) {
case 'strict':
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], 'Page is not available in the requested language (strict).');
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Page is not available in the requested language (strict).',
+ ['code' => PageAccessFailureReasons::LANGUAGE_NOT_AVAILABLE_STRICT_MODE]
+ );
$this->sendResponseAndExit($response);
break;
case 'fallback':
// 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.
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], 'Page is not available in the requested language (fallbacks did not apply).');
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ 'Page is not available in the requested language (fallbacks did not apply).',
+ ['code' => PageAccessFailureReasons::LANGUAGE_AND_FALLBACKS_NOT_AVAILABLE]
+ );
$this->sendResponseAndExit($response);
}
}
if ((!$this->sys_language_uid || !$this->sys_language_content) && GeneralUtility::hideIfDefaultLanguage($this->page['l18n_cfg'])) {
$message = 'Page is not available in default language.';
$this->logger->error($message);
- $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction($GLOBALS['TYPO3_REQUEST'], $message);
+ $response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
+ $GLOBALS['TYPO3_REQUEST'],
+ $message,
+ ['code' => PageAccessFailureReasons::LANGUAGE_DEFAULT_NOT_AVAILABLE]
+ );
$this->sendResponseAndExit($response);
}
$this->updateRootLinesWithTranslations();
--- /dev/null
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Frontend\Page;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Contains a list of all reasons that TYPO3 internally uses when a page cannot be found/rendered etc.
+ * See TypoScriptFrontendController for more details and the usage.
+ */
+final class PageAccessFailureReasons
+{
+ // Page resolving issues
+ public const NO_PAGES_FOUND = 'page.database.empty';
+ public const PAGE_NOT_FOUND = 'page';
+ public const PAGE_ALIAS_NOT_FOUND = 'page.alias';
+ public const ROOTLINE_BROKEN = 'page.rootline';
+
+ // Page configuration issues
+ public const RENDERING_INSTRUCTIONS_NOT_FOUND = 'rendering_instructions';
+ public const RENDERING_INSTRUCTIONS_NOT_CONFIGURED = 'rendering_instructions.type';
+
+ // Validation errors
+ public const CACHEHASH_COMPARISON_FAILED = 'cache_hash.comparison';
+ public const CACHEHASH_EMPTY = 'cache_hash.empty';
+
+ // Language-related issues
+ public const LANGUAGE_NOT_AVAILABLE = 'language';
+ public const LANGUAGE_NOT_AVAILABLE_STRICT_MODE = 'language.strict';
+ public const LANGUAGE_AND_FALLBACKS_NOT_AVAILABLE = 'language.fallbacks';
+ public const LANGUAGE_DEFAULT_NOT_AVAILABLE = 'language.default';
+
+ // Access restrictions
+ public const ACCESS_DENIED_GENERAL = 'access';
+ public const ACCESS_DENIED_PAGE_NOT_RESOLVED = 'access.page';
+ public const ACCESS_DENIED_SUBSECTION_NOT_RESOLVED = 'access.subsection';
+ public const ACCESS_DENIED_HOST_PAGE_MISMATCH = 'access.host_mismatch';
+ public const ACCESS_DENIED_INVALID_PAGETYPE = 'access.pagetype';
+
+ // System errors
+ public const DATABASE_CONNECTION_FAILED = 'system.database';
+
+ /**
+ * Labels for the status codes
+ *
+ * @var string[]
+ */
+ protected $messages = [
+ self::NO_PAGES_FOUND => 'No page on rootlevel found',
+ self::PAGE_NOT_FOUND => 'The requested page does not exist',
+ self::PAGE_ALIAS_NOT_FOUND => 'The requested page alias does not exist',
+
+ self::RENDERING_INSTRUCTIONS_NOT_FOUND => 'No TypoScript template found',
+ self::RENDERING_INSTRUCTIONS_NOT_CONFIGURED => 'The page is not configured',
+
+ self::CACHEHASH_COMPARISON_FAILED => 'Request parameters could not be validated (&cHash comparison failed)',
+ self::CACHEHASH_EMPTY => 'Request parameters could not be validated (&cHash empty)',
+
+ self::LANGUAGE_NOT_AVAILABLE => 'Page is not available in the requested language',
+ self::LANGUAGE_NOT_AVAILABLE_STRICT_MODE => 'Page is not available in the requested language (strict)',
+ self::LANGUAGE_AND_FALLBACKS_NOT_AVAILABLE => 'Page is not available in the requested language (fallbacks did not apply)',
+ self::LANGUAGE_DEFAULT_NOT_AVAILABLE => 'Page is not available in default language',
+
+ self::ACCESS_DENIED_GENERAL => 'The requested page was not accessible',
+ self::ACCESS_DENIED_PAGE_NOT_RESOLVED => 'ID was not an accessible page',
+ self::ACCESS_DENIED_SUBSECTION_NOT_RESOLVED => 'Subsection was found and not accessible',
+ self::ACCESS_DENIED_HOST_PAGE_MISMATCH => 'ID was outside the domain',
+ self::ACCESS_DENIED_INVALID_PAGETYPE => 'The requested page type cannot be rendered',
+
+ self::DATABASE_CONNECTION_FAILED => 'Database Connection failed',
+ self::ROOTLINE_BROKEN => 'The requested page did not have a proper connection to the tree-root'
+ ];
+
+ /**
+ * @param string $reasonCode a valid reason code (see above)
+ * @return string
+ */
+ public function getMessageForReason(string $reasonCode): string
+ {
+ if (!isset($this->messages[$reasonCode])) {
+ throw new \InvalidArgumentException('No message for page access reason code "' . $reasonCode . '" found.', 1529299833);
+ }
+ return $this->messages[$reasonCode];
+ }
+}