hmac(serialize($params), self::class, HashAlgo::SHA3_256) : ''; } /** * 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() * @internal */ 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: 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' || $key === 'logintype'; } /** * 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 ); } }