| Current Path : /var/www/surf/TYPO3/vendor/typo3/cms-frontend/Classes/Page/ |
| Current File : /var/www/surf/TYPO3/vendor/typo3/cms-frontend/Classes/Page/CacheHashCalculator.php |
<?php
/*
* 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!
*/
namespace TYPO3\CMS\Frontend\Page;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Logic for cHash calculation
*/
class CacheHashCalculator implements SingletonInterface
{
/**
* @var CacheHashConfiguration
*/
protected $configuration;
/**
* Initialise class properties by using the relevant TYPO3 configuration
*
* @param CacheHashConfiguration|null $configuration
*/
public function __construct(CacheHashConfiguration $configuration = null)
{
$this->configuration = $configuration ?? GeneralUtility::makeInstance(CacheHashConfiguration::class);
}
/**
* 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 (!$this->configuration->hasData(CacheHashConfiguration::ASPECT_REQUIRED_CACHE_HASH_PRESENCE_PARAMETERS)) {
return false;
}
$parameterNames = array_keys($this->splitQueryStringToArray($queryString));
foreach ($parameterNames as $parameterName) {
$hasRequiredParameter = $this->configuration->applies(
CacheHashConfiguration::ASPECT_REQUIRED_CACHE_HASH_PRESENCE_PARAMETERS,
$parameterName
);
if ($hasRequiredParameter) {
return true;
}
}
return false;
}
/**
* 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.
*
* @param string $key
* @return bool
*/
protected function isAdminPanelParameter($key)
{
return $key === 'ADMCMD_simUser' || $key === 'ADMCMD_simTime' || $key === 'ADMCMD_prev';
}
/**
* 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';
}
/**
* Checks whether the given parameter should be excluded from cHash calculation
*
* @param string $key
* @return bool
*/
protected function isExcludedParameter($key)
{
return $this->configuration->applies(
CacheHashConfiguration::ASPECT_EXCLUDED_PARAMETERS,
$key
);
}
/**
* Checks whether the given parameter is an exclusive parameter for cHash calculation
*
* @param string $key
* @return bool
*/
protected function isInCachedParametersWhiteList($key)
{
return $this->configuration->applies(
CacheHashConfiguration::ASPECT_CACHED_PARAMETERS_WHITELIST,
$key
);
}
/**
* Checks whether cachedParametersWhiteList parameters are configured
*
* @return bool
*/
protected function hasCachedParametersWhiteList()
{
return $this->configuration->hasData(
CacheHashConfiguration::ASPECT_CACHED_PARAMETERS_WHITELIST
);
}
/**
* Check whether the given parameter may be used even with an empty value
*
* @param string $key
* @return bool
*/
protected function isAllowedWithEmptyValue($key)
{
return $this->configuration->shallExcludeAllEmptyParameters()
|| $this->configuration->applies(
CacheHashConfiguration::ASPECT_EXCLUDED_PARAMETERS_IF_EMPTY,
$key
);
}
/**
* Extends (or overrides) property names of current configuration.
*/
public function setConfiguration(array $configuration)
{
$newConfiguration = GeneralUtility::makeInstance(CacheHashConfiguration::class, $configuration);
$this->configuration = $this->configuration->with($newConfiguration);
}
}