02c8fbdb835340126ce3a4b80f3a41bb41f2afb9
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Page / CacheHashCalculator.php
1 <?php
2 namespace TYPO3\CMS\Frontend\Page;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 /**
18 * Logic for cHash calculation
19 */
20 class CacheHashCalculator implements \TYPO3\CMS\Core\SingletonInterface
21 {
22 /**
23 * @var array Parameters that are relevant for cacheHash calculation. Optional.
24 */
25 protected $cachedParametersWhiteList = [];
26
27 /**
28 * @var array Parameters that are not relevant for cacheHash calculation.
29 */
30 protected $excludedParameters = [];
31
32 /**
33 * @var array Parameters that forces a presence of a valid cacheHash.
34 */
35 protected $requireCacheHashPresenceParameters = [];
36
37 /**
38 * @var array Parameters that need a value to be relevant for cacheHash calculation
39 */
40 protected $excludedParametersIfEmpty = [];
41
42 /**
43 * @var bool Whether to exclude all empty parameters for cacheHash calculation
44 */
45 protected $excludeAllEmptyParameters = false;
46
47 /**
48 * Initialise class properties by using the relevant TYPO3 configuration
49 */
50 public function __construct()
51 {
52 $this->setConfiguration($GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']);
53 }
54
55 /**
56 * Calculates the cHash based on the provided parameters
57 *
58 * @param array $params Array of cHash key-value pairs
59 * @return string Hash of all the values
60 */
61 public function calculateCacheHash(array $params)
62 {
63 return !empty($params) ? md5(serialize($params)) : '';
64 }
65
66 /**
67 * Returns the cHash based on provided query parameters and added values from internal call
68 *
69 * @param string $queryString Query-parameters: "&xxx=yyy&zzz=uuu
70 * @return string Hash of all the values
71 */
72 public function generateForParameters($queryString)
73 {
74 $cacheHashParams = $this->getRelevantParameters($queryString);
75 return $this->calculateCacheHash($cacheHashParams);
76 }
77
78 /**
79 * Checks whether a parameter of the given $queryString requires cHash calculation
80 *
81 * @param string $queryString
82 * @return bool
83 */
84 public function doParametersRequireCacheHash($queryString)
85 {
86 if (empty($this->requireCacheHashPresenceParameters)) {
87 return false;
88 }
89 $hasRequiredParameter = false;
90 $parameterNames = array_keys($this->splitQueryStringToArray($queryString));
91 foreach ($parameterNames as $parameterName) {
92 if (in_array($parameterName, $this->requireCacheHashPresenceParameters)) {
93 $hasRequiredParameter = true;
94 }
95 }
96 return $hasRequiredParameter;
97 }
98
99 /**
100 * Splits the input query-parameters into an array with certain parameters filtered out.
101 * Used to create the cHash value
102 *
103 * @param string $queryString Query-parameters: "&xxx=yyy&zzz=uuu
104 * @return array Array with key/value pairs of query-parameters WITHOUT a certain list of
105 * @see \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::makeCacheHash(), \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::typoLink()
106 */
107 public function getRelevantParameters($queryString)
108 {
109 $parameters = $this->splitQueryStringToArray($queryString);
110 $relevantParameters = [];
111 foreach ($parameters as $parameterName => $parameterValue) {
112 if ($this->isAdminPanelParameter($parameterName) || $this->isExcludedParameter($parameterName) || $this->isCoreParameter($parameterName)) {
113 continue;
114 }
115 if ($this->hasCachedParametersWhiteList() && !$this->isInCachedParametersWhiteList($parameterName)) {
116 continue;
117 }
118 if ((is_null($parameterValue) || $parameterValue === '') && !$this->isAllowedWithEmptyValue($parameterName)) {
119 continue;
120 }
121 $relevantParameters[$parameterName] = $parameterValue;
122 }
123 if (!empty($relevantParameters)) {
124 // Finish and sort parameters array by keys:
125 $relevantParameters['encryptionKey'] = $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'];
126 ksort($relevantParameters);
127 }
128 return $relevantParameters;
129 }
130
131 /**
132 * Parses the query string and converts it to an array.
133 * Unlike parse_str it only creates an array with one level.
134 *
135 * e.g. foo[bar]=baz will be array('foo[bar]' => 'baz')
136 *
137 * @param $queryString
138 * @return array
139 */
140 protected function splitQueryStringToArray($queryString)
141 {
142 $parameters = array_filter(explode('&', ltrim($queryString, '?')));
143 $parameterArray = [];
144 foreach ($parameters as $parameter) {
145 list($parameterName, $parameterValue) = explode('=', $parameter);
146 $parameterArray[rawurldecode($parameterName)] = rawurldecode($parameterValue);
147 }
148 return $parameterArray;
149 }
150
151 /**
152 * Checks whether the given parameter starts with TSFE_ADMIN_PANEL
153 * stristr check added to avoid bad performance
154 *
155 * @param string $key
156 * @return bool
157 */
158 protected function isAdminPanelParameter($key)
159 {
160 return stristr($key, 'TSFE_ADMIN_PANEL') !== false && preg_match('/TSFE_ADMIN_PANEL\\[.*?\\]/', $key);
161 }
162
163 /**
164 * Checks whether the given parameter is a core parameter
165 *
166 * @param string $key
167 * @return bool
168 */
169 protected function isCoreParameter($key)
170 {
171 return $key === 'id' || $key === 'type' || $key === 'no_cache' || $key === 'cHash' || $key === 'MP' || $key === 'ftu';
172 }
173
174 /**
175 * Checks whether the given parameter should be exluded from cHash calculation
176 *
177 * @param string $key
178 * @return bool
179 */
180 protected function isExcludedParameter($key)
181 {
182 return in_array($key, $this->excludedParameters);
183 }
184
185 /**
186 * Checks whether the given parameter is an exclusive parameter for cHash calculation
187 *
188 * @param string $key
189 * @return bool
190 */
191 protected function isInCachedParametersWhiteList($key)
192 {
193 return in_array($key, $this->cachedParametersWhiteList);
194 }
195
196 /**
197 * Checks whether cachedParametersWhiteList parameters are configured
198 *
199 * @return bool
200 */
201 protected function hasCachedParametersWhiteList()
202 {
203 return !empty($this->cachedParametersWhiteList);
204 }
205
206 /**
207 * Check whether the given parameter may be used even with an empty value
208 *
209 * @param $key
210 * @return bool
211 */
212 protected function isAllowedWithEmptyValue($key)
213 {
214 return !($this->excludeAllEmptyParameters || in_array($key, $this->excludedParametersIfEmpty));
215 }
216
217 /**
218 * Loops through the configuration array and calls the accordant
219 * getters with the value.
220 *
221 * @param $configuration
222 */
223 public function setConfiguration($configuration)
224 {
225 foreach ($configuration as $name => $value) {
226 $setterName = 'set' . ucfirst($name);
227 if (method_exists($this, $setterName)) {
228 $this->{$setterName}($value);
229 }
230 }
231 }
232
233 /**
234 * @param array $cachedParametersWhiteList
235 */
236 protected function setCachedParametersWhiteList(array $cachedParametersWhiteList)
237 {
238 $this->cachedParametersWhiteList = $cachedParametersWhiteList;
239 }
240
241 /**
242 * @param bool $excludeAllEmptyParameters
243 */
244 protected function setExcludeAllEmptyParameters($excludeAllEmptyParameters)
245 {
246 $this->excludeAllEmptyParameters = $excludeAllEmptyParameters;
247 }
248
249 /**
250 * @param array $excludedParameters
251 */
252 protected function setExcludedParameters(array $excludedParameters)
253 {
254 $this->excludedParameters = $excludedParameters;
255 }
256
257 /**
258 * @param array $excludedParametersIfEmpty
259 */
260 protected function setExcludedParametersIfEmpty(array $excludedParametersIfEmpty)
261 {
262 $this->excludedParametersIfEmpty = $excludedParametersIfEmpty;
263 }
264
265 /**
266 * @param array $requireCacheHashPresenceParameters
267 */
268 protected function setRequireCacheHashPresenceParameters(array $requireCacheHashPresenceParameters)
269 {
270 $this->requireCacheHashPresenceParameters = $requireCacheHashPresenceParameters;
271 }
272 }