[FEATURE] Add Contexts for storing data access modes
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Configuration / TypoScript / ConditionMatching / ConditionMatcher.php
1 <?php
2
3 namespace TYPO3\CMS\Frontend\Configuration\TypoScript\ConditionMatching;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\Context\UserAspect;
22 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24
25 /**
26 * Matching TypoScript conditions for frontend disposal.
27 *
28 * Used with the TypoScript parser. Matches browserinfo
29 * and IP numbers for use with templates.
30 */
31 class ConditionMatcher extends AbstractConditionMatcher
32 {
33 /**
34 * @var Context
35 */
36 protected $context;
37
38 /**
39 * @param Context $context optional context to fetch data from
40 */
41 public function __construct(Context $context = null)
42 {
43 $this->context = $context ?? GeneralUtility::makeInstance(Context::class);
44 }
45
46 /**
47 * Evaluates a TypoScript condition given as input,
48 * eg. "[browser=net][...(other conditions)...]"
49 *
50 * @param string $string The condition to match against its criteria.
51 * @return bool Whether the condition matched
52 * @see \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::parse()
53 * @throws \TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException
54 */
55 protected function evaluateCondition($string)
56 {
57 list($key, $value) = GeneralUtility::trimExplode('=', $string, false, 2);
58 $result = $this->evaluateConditionCommon($key, $value);
59
60 if (is_bool($result)) {
61 return $result;
62 }
63 switch ($key) {
64 case 'usergroup':
65 $groupList = $this->getGroupList();
66 // '0,-1' is the default usergroups when not logged in!
67 if ($groupList !== '0,-1') {
68 $values = GeneralUtility::trimExplode(',', $value, true);
69 foreach ($values as $test) {
70 if ($test === '*' || GeneralUtility::inList($groupList, $test)) {
71 return true;
72 }
73 }
74 }
75 break;
76 case 'treeLevel':
77 $values = GeneralUtility::trimExplode(',', $value, true);
78 $treeLevel = count($this->rootline) - 1;
79 foreach ($values as $test) {
80 if ($test == $treeLevel) {
81 return true;
82 }
83 }
84 break;
85 case 'PIDupinRootline':
86 case 'PIDinRootline':
87 $values = GeneralUtility::trimExplode(',', $value, true);
88 if ($key === 'PIDinRootline' || !in_array($this->pageId, $values)) {
89 foreach ($values as $test) {
90 foreach ($this->rootline as $rlDat) {
91 if ($rlDat['uid'] == $test) {
92 return true;
93 }
94 }
95 }
96 }
97 break;
98 case 'site':
99 $siteLanguage = $this->getCurrentSiteLanguage();
100 if ($siteLanguage instanceof SiteLanguage) {
101 $site = $siteLanguage->getSite();
102 $values = GeneralUtility::trimExplode(',', $value, true);
103 foreach ($values as $test) {
104 $point = strcspn($test, '=');
105 $testValue = substr($test, $point + 1);
106 $testValue = trim($testValue);
107 $theVarName = trim(substr($test, 0, $point));
108 $methodName = 'get' . ucfirst($theVarName);
109 if (method_exists($site, $methodName)) {
110 $sitePropertyValue = call_user_func([$site, $methodName]);
111 // loose check on purpose in order to check for integer values
112 if ($testValue == $sitePropertyValue) {
113 return true;
114 }
115 }
116 }
117 }
118 break;
119 case 'siteLanguage':
120 $siteLanguage = $this->getCurrentSiteLanguage();
121 if ($siteLanguage instanceof SiteLanguage) {
122 $values = GeneralUtility::trimExplode(',', $value, true);
123 foreach ($values as $test) {
124 $point = strcspn($test, '=');
125 $testValue = substr($test, $point + 1);
126 $testValue = trim($testValue);
127 $theVarName = trim(substr($test, 0, $point));
128 $methodName = 'get' . ucfirst($theVarName);
129 if (method_exists($siteLanguage, $methodName)) {
130 $languagePropertyValue = call_user_func([$siteLanguage, $methodName]);
131 // loose check on purpose in order to check for integer values
132 if ($testValue == $languagePropertyValue) {
133 return true;
134 }
135 }
136 }
137 }
138 break;
139 default:
140 $conditionResult = $this->evaluateCustomDefinedCondition($string);
141 if ($conditionResult !== null) {
142 return $conditionResult;
143 }
144 }
145
146 return false;
147 }
148
149 /**
150 * Returns GP / ENV / TSFE / session vars
151 *
152 * @example GP:L
153 * @example TSFE:fe_user|sesData|foo|bar
154 * @example TSFE:id
155 * @example ENV:HTTP_HOST
156 *
157 * @param string $var Identifier
158 * @return mixed|null The value of the variable pointed to or NULL if variable did not exist
159 */
160 protected function getVariable($var)
161 {
162 $vars = explode(':', $var, 2);
163 $val = $this->getVariableCommon($vars);
164 if ($val === null) {
165 $splitAgain = explode('|', $vars[1], 2);
166 $k = trim($splitAgain[0]);
167 if ($k) {
168 switch ((string)trim($vars[0])) {
169 case 'TSFE':
170 if (strpos($vars[1], 'fe_user|sesData|') === 0) {
171 trigger_error(
172 'Condition on TSFE|fe_user|sesData is deprecated and will be removed in TYPO3 CMS 10',
173 E_USER_DEPRECATED
174 );
175 $val = $this->getSessionVariable(substr($vars[1], 16));
176 } else {
177 $val = $this->getGlobal('TSFE|' . $vars[1]);
178 }
179 break;
180 case 'session':
181 $val = $this->getSessionVariable($vars[1]);
182 break;
183 default:
184 }
185 }
186 }
187 return $val;
188 }
189
190 /**
191 * Return variable from current frontend user session
192 *
193 * @param string $var Session key
194 * @return mixed|null The value of the variable pointed to or NULL if variable did not exist
195 */
196 protected function getSessionVariable(string $var)
197 {
198 $retVal = null;
199 $keyParts = explode('|', $var);
200 $sessionKey = array_shift($keyParts);
201 $tsfe = $this->getTypoScriptFrontendController();
202 if ($tsfe && is_object($tsfe->fe_user)) {
203 $retVal = $tsfe->fe_user->getSessionData($sessionKey);
204 foreach ($keyParts as $keyPart) {
205 if (is_object($retVal)) {
206 $retVal = $retVal->{$keyPart};
207 } elseif (is_array($retVal)) {
208 $retVal = $retVal[$keyPart];
209 } else {
210 break;
211 }
212 }
213 }
214 return $retVal;
215 }
216
217 /**
218 * Get the usergroup list of the current user.
219 *
220 * @return string The usergroup list of the current user
221 */
222 protected function getGroupList()
223 {
224 /** @var UserAspect $userAspect */
225 $userAspect = $this->context->getAspect('frontend.user');
226 return implode(',', $userAspect->getGroupIds());
227 }
228
229 /**
230 * Determines the current page Id.
231 *
232 * @return int The current page Id
233 */
234 protected function determinePageId()
235 {
236 return (int)($this->getTypoScriptFrontendController()->id ?? 0);
237 }
238
239 /**
240 * Gets the properties for the current page.
241 *
242 * @return array The properties for the current page.
243 */
244 protected function getPage()
245 {
246 return $this->getTypoScriptFrontendController()->page;
247 }
248
249 /**
250 * Determines the rootline for the current page.
251 *
252 * @return array The rootline for the current page.
253 */
254 protected function determineRootline()
255 {
256 return (array)$this->getTypoScriptFrontendController()->tmpl->rootLine;
257 }
258
259 /**
260 * Get the id of the current user.
261 *
262 * @return int The id of the current user
263 */
264 protected function getUserId()
265 {
266 $userAspect = $this->context->getAspect('frontend.user');
267 return $userAspect->get('id');
268 }
269
270 /**
271 * Determines if a user is logged in.
272 *
273 * @return bool Determines if a user is logged in
274 */
275 protected function isUserLoggedIn()
276 {
277 /** @var UserAspect $userAspect */
278 $userAspect = $this->context->getAspect('frontend.user');
279 return $userAspect->isLoggedIn();
280 }
281
282 /**
283 * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
284 */
285 protected function getTypoScriptFrontendController()
286 {
287 return $GLOBALS['TSFE'];
288 }
289
290 /**
291 * Returns the currently configured "site language" if a site is configured (= resolved) in the current request.
292 *
293 * @internal
294 */
295 protected function getCurrentSiteLanguage(): ?SiteLanguage
296 {
297 if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface
298 && $GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof SiteLanguage) {
299 return $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
300 }
301 return null;
302 }
303 }