first commit

This commit is contained in:
salam committed 2026-10-19 08:18:39 +02:00
commit 1218dd1517
12716 files changed
+989233

No files matched your search

@@ -0,0 +1,294 @@
<?php
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!
*/
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Logic for cHash calculation
*/
class CacheHashCalculator implements SingletonInterface
{
/**
* @var array Parameters that are relevant for cacheHash calculation. Optional.
*/
protected $cachedParametersWhiteList = [];
/**
* @var array Parameters that are not relevant for cacheHash calculation.
*/
protected $excludedParameters = [];
/**
* @var array Parameters that forces a presence of a valid cacheHash.
*/
protected $requireCacheHashPresenceParameters = [];
/**
* @var array Parameters that need a value to be relevant for cacheHash calculation
*/
protected $excludedParametersIfEmpty = [];
/**
* @var bool Whether to exclude all empty parameters for cacheHash calculation
*/
protected $excludeAllEmptyParameters = false;
/**
* Initialise class properties by using the relevant TYPO3 configuration
*
* @param array $configuration
*/
public function __construct(array $configuration = null)
{
$configuration = $configuration ?? $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash'] ?? [];
$this->setConfiguration($configuration);
}
/**
* Calculates the cHash based on the provided parameters
*
* @param array $params Array of cHash key-value pairs
* @return string Hash of all the values
*/
public function calculateCacheHash(array $params)
{
return !empty($params) ? md5(serialize($params)) : '';
}
/**
* Returns the cHash based on provided query parameters and added values from internal call
*
* @param string $queryString Query-parameters: "&xxx=yyy&zzz=uuu
* @return string Hash of all the values
* @throws \RuntimeException
*/
public function generateForParameters($queryString)
{
$cacheHashParams = $this->getRelevantParameters($queryString);
return $this->calculateCacheHash($cacheHashParams);
}
/**
* Checks whether a parameter of the given $queryString requires cHash calculation
*
* @param string $queryString
* @return bool
*/
public function doParametersRequireCacheHash($queryString)
{
if (empty($this->requireCacheHashPresenceParameters)) {
return false;
}
$hasRequiredParameter = false;
$parameterNames = array_keys($this->splitQueryStringToArray($queryString));
foreach ($parameterNames as $parameterName) {
if (in_array($parameterName, $this->requireCacheHashPresenceParameters, true)) {
$hasRequiredParameter = true;
break;
}
}
return $hasRequiredParameter;
}
/**
* Splits the input query-parameters into an array with certain parameters filtered out.
* Used to create the cHash value
*
* @param string $queryString Query-parameters: "&xxx=yyy&zzz=uuu
* @return array Array with key/value pairs of query-parameters WITHOUT a certain list of
* @throws \RuntimeException
* @see \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::typoLink()
*/
public function getRelevantParameters($queryString)
{
$parameters = $this->splitQueryStringToArray($queryString);
$relevantParameters = [];
foreach ($parameters as $parameterName => $parameterValue) {
if ($this->isAdminPanelParameter($parameterName) || $this->isExcludedParameter($parameterName) || $this->isCoreParameter($parameterName)) {
continue;
}
if ($this->hasCachedParametersWhiteList() && !$this->isInCachedParametersWhiteList($parameterName)) {
continue;
}
if (($parameterValue === null || $parameterValue === '') && !$this->isAllowedWithEmptyValue($parameterName)) {
continue;
}
$relevantParameters[$parameterName] = $parameterValue;
}
if (!empty($relevantParameters)) {
if (empty($parameters['id'])) {
throw new \RuntimeException('ID parameter needs to be passed for the cHash calculation!', 1467983513);
}
$relevantParameters['id'] = $parameters['id'];
// Finish and sort parameters array by keys:
$relevantParameters['encryptionKey'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
ksort($relevantParameters);
}
return $relevantParameters;
}
/**
* Parses the query string and converts it to an array.
* Unlike parse_str it only creates an array with one level.
*
* e.g. foo[bar]=baz will be array('foo[bar]' => 'baz')
*
* @param string $queryString
* @return array
*/
protected function splitQueryStringToArray($queryString)
{
$parameters = array_filter(explode('&', ltrim($queryString, '?')));
$parameterArray = [];
foreach ($parameters as $parameter) {
// should not remove empty values with trimExplode, otherwise cases like &=value, value is used as parameterName.
$parts = GeneralUtility::trimExplode('=', $parameter, false);
$parameterName = $parts[0];
$parameterValue = $parts[1] ?? '';
if (trim($parameterName) === '') {
// This parameter cannot appear in $_GET in PHP even if its value is not empty, so it should be ignored!
continue;
}
$parameterArray[rawurldecode($parameterName)] = rawurldecode($parameterValue);
}
return $parameterArray;
}
/**
* Checks whether the given parameter is out of a known data-set starting
* with ADMCMD or starts with TSFE_ADMIN_PANEL.
*
* @param string $key
* @return bool
*/
protected function isAdminPanelParameter($key)
{
return $key === 'ADMCMD_noBeUser' || $key === 'ADMCMD_view' || $key === 'ADMCMD_editIcons'
|| $key === 'ADMCMD_simUser' || $key === 'ADMCMD_simTime' || $key === 'ADMCMD_prev'
|| stripos($key, 'TSFE_ADMIN_PANEL') !== false && preg_match('/TSFE_ADMIN_PANEL\\[.*?\\]/', $key);
}
/**
* Checks whether the given parameter is a core parameter
*
* @param string $key
* @return bool
*/
protected function isCoreParameter($key)
{
return $key === 'id' || $key === 'type' || $key === 'no_cache' || $key === 'cHash' || $key === 'MP' || $key === 'ftu';
}
/**
* Checks whether the given parameter should be excluded from cHash calculation
*
* @param string $key
* @return bool
*/
protected function isExcludedParameter($key)
{
return in_array($key, $this->excludedParameters, true);
}
/**
* Checks whether the given parameter is an exclusive parameter for cHash calculation
*
* @param string $key
* @return bool
*/
protected function isInCachedParametersWhiteList($key)
{
return in_array($key, $this->cachedParametersWhiteList, true);
}
/**
* Checks whether cachedParametersWhiteList parameters are configured
*
* @return bool
*/
protected function hasCachedParametersWhiteList()
{
return !empty($this->cachedParametersWhiteList);
}
/**
* Check whether the given parameter may be used even with an empty value
*
* @param $key
* @return bool
*/
protected function isAllowedWithEmptyValue($key)
{
return !($this->excludeAllEmptyParameters || in_array($key, $this->excludedParametersIfEmpty, true));
}
/**
* Loops through the configuration array and calls the accordant
* getters with the value.
*
* @param array $configuration
*/
public function setConfiguration(array $configuration)
{
foreach ($configuration as $name => $value) {
$setterName = 'set' . ucfirst($name);
if (method_exists($this, $setterName)) {
$this->{$setterName}($value);
}
}
}
/**
* @param array $cachedParametersWhiteList
*/
protected function setCachedParametersWhiteList(array $cachedParametersWhiteList)
{
$this->cachedParametersWhiteList = $cachedParametersWhiteList;
}
/**
* @param bool $excludeAllEmptyParameters
*/
protected function setExcludeAllEmptyParameters($excludeAllEmptyParameters)
{
$this->excludeAllEmptyParameters = $excludeAllEmptyParameters;
}
/**
* @param array $excludedParameters
*/
protected function setExcludedParameters(array $excludedParameters)
{
$this->excludedParameters = $excludedParameters;
}
/**
* @param array $excludedParametersIfEmpty
*/
protected function setExcludedParametersIfEmpty(array $excludedParametersIfEmpty)
{
$this->excludedParametersIfEmpty = $excludedParametersIfEmpty;
}
/**
* @param array $requireCacheHashPresenceParameters
*/
protected function setRequireCacheHashPresenceParameters(array $requireCacheHashPresenceParameters)
{
$this->requireCacheHashPresenceParameters = $requireCacheHashPresenceParameters;
}
}
@@ -0,0 +1,73 @@
<?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!
*/
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Http\RedirectResponse;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Handles the redirection for external URL pages.
* @deprecated since TYPO3 v9.3, will be removed in TYPO3 v10.0. The functionality has been moved into a PSR-15 middleware.
*/
class ExternalPageUrlHandler implements \TYPO3\CMS\Frontend\Http\UrlHandlerInterface
{
/**
* @var string
*/
protected $externalUrl = '';
public function __construct()
{
trigger_error('ExternalPageUrlHandler has been moved into a PSR-15 middleware and will be removed in TYPO3 v10.0. In order to modify the external page redirection, use a PSR-15 middleware as well.', E_USER_DEPRECATED);
}
/**
* Checks if external URLs are enabled and if the current page points to an external URL.
*
* @return bool
*/
public function canHandleCurrentUrl(): bool
{
$tsfe = $this->getTypoScriptFrontendController();
if (!empty($tsfe->config['config']['disablePageExternalUrl'])) {
return false;
}
$this->externalUrl = $tsfe->sys_page->getExtURL($tsfe->page);
if (empty($this->externalUrl)) {
return false;
}
return true;
}
/**
* Redirects the user to the detected external URL.
*/
public function handle(): ResponseInterface
{
return new RedirectResponse($this->externalUrl, 303);
}
/**
* @return TypoScriptFrontendController
*/
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
{
return $GLOBALS['TSFE'];
}
}
@@ -0,0 +1,96 @@
<?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];
}
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,30 @@
<?php
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!
*/
/**
* Interface for classes which hook into pageSelect and do additional getPage processing
*/
interface PageRepositoryGetPageHookInterface
{
/**
* Modifies the DB params
*
* @param int $uid The page ID
* @param bool $disableGroupAccessCheck If set, the check for group access is disabled. VERY rarely used
* @param \TYPO3\CMS\Frontend\Page\PageRepository $parentObject Parent object
*/
public function getPage_preProcess(&$uid, &$disableGroupAccessCheck, PageRepository $parentObject);
}
@@ -0,0 +1,30 @@
<?php
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!
*/
/**
* Interface for classes which hook into \TYPO3\CMS\Frontend\Page\PageRepository
*/
interface PageRepositoryGetPageOverlayHookInterface
{
/**
* enables to preprocess the pageoverlay
*
* @param array $pageInput The page record
* @param int $lUid The overlay language
* @param \TYPO3\CMS\Frontend\Page\PageRepository $parent The calling parent object
*/
public function getPageOverlay_preProcess(&$pageInput, &$lUid, PageRepository $parent);
}
@@ -0,0 +1,43 @@
<?php
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!
*/
/**
* Interface for classes which hook into \TYPO3\CMS\Frontend\Page\PageRepository
*/
interface PageRepositoryGetRecordOverlayHookInterface
{
/**
* Enables to preprocess a record overlay
*
* @param string $table
* @param array $row
* @param int $sys_language_content
* @param string $OLmode
* @param \TYPO3\CMS\Frontend\Page\PageRepository $parent
*/
public function getRecordOverlay_preProcess($table, &$row, &$sys_language_content, $OLmode, PageRepository $parent);
/**
* Enables to postprocess a record overlay
*
* @param string $table
* @param array $row
* @param int $sys_language_content
* @param string $OLmode
* @param \TYPO3\CMS\Frontend\Page\PageRepository $parent
*/
public function getRecordOverlay_postProcess($table, &$row, &$sys_language_content, $OLmode, PageRepository $parent);
}
@@ -0,0 +1,28 @@
<?php
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!
*/
/**
* Interface for classes which hook into pageSelect and do additional getPage processing
*/
interface PageRepositoryInitHookInterface
{
/**
* Modifies the DB params
*
* @param \TYPO3\CMS\Frontend\Page\PageRepository $parentObject Parent object
*/
public function init_postProcess(PageRepository $parentObject);
}