1<?php 2 3namespace 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 18use Psr\Http\Message\ServerRequestInterface; 19use TYPO3\CMS\Core\Configuration\TypoScript\ConditionMatching\AbstractConditionMatcher; 20use TYPO3\CMS\Core\Context\Context; 21use TYPO3\CMS\Core\Context\UserAspect; 22use TYPO3\CMS\Core\Site\Entity\Site; 23use TYPO3\CMS\Core\Site\Entity\SiteLanguage; 24use TYPO3\CMS\Core\Utility\GeneralUtility; 25 26/** 27 * Matching TypoScript conditions for frontend disposal. 28 * 29 * Used with the TypoScript parser. Matches browserinfo 30 * and IP numbers for use with templates. 31 */ 32class ConditionMatcher extends AbstractConditionMatcher 33{ 34 /** 35 * @var Context 36 */ 37 protected $context; 38 39 /** 40 * @param Context $context optional context to fetch data from 41 */ 42 public function __construct(Context $context = null) 43 { 44 $this->context = $context ?? GeneralUtility::makeInstance(Context::class); 45 $this->rootline = $this->determineRootline(); 46 $this->initializeExpressionLanguageResolver(); 47 } 48 49 protected function updateExpressionLanguageVariables(): void 50 { 51 $tree = new \stdClass(); 52 $tree->level = $this->rootline ? count($this->rootline) - 1 : 0; 53 $tree->rootLine = $this->rootline; 54 $tree->rootLineIds = array_column($this->rootline, 'uid'); 55 56 $frontendUserAspect = $this->context->getAspect('frontend.user'); 57 $frontend = new \stdClass(); 58 $frontend->user = new \stdClass(); 59 $frontend->user->isLoggedIn = $frontendUserAspect->get('isLoggedIn'); 60 $frontend->user->userId = $frontendUserAspect->get('id'); 61 $frontend->user->userGroupList = implode(',', $frontendUserAspect->get('groupIds')); 62 63 $backendUserAspect = $this->context->getAspect('backend.user'); 64 $backend = new \stdClass(); 65 $backend->user = new \stdClass(); 66 $backend->user->isAdmin = $backendUserAspect->get('isAdmin'); 67 $backend->user->isLoggedIn = $backendUserAspect->get('isLoggedIn'); 68 $backend->user->userId = $backendUserAspect->get('id'); 69 $backend->user->userGroupList = implode(',', $backendUserAspect->get('groupIds')); 70 71 $workspaceAspect = $this->context->getAspect('workspace'); 72 $workspace = new \stdClass(); 73 $workspace->workspaceId = $workspaceAspect->get('id'); 74 $workspace->isLive = $workspaceAspect->get('isLive'); 75 $workspace->isOffline = $workspaceAspect->get('isOffline'); 76 77 $this->expressionLanguageResolverVariables = [ 78 'tree' => $tree, 79 'frontend' => $frontend, 80 'backend' => $backend, 81 'workspace' => $workspace, 82 'page' => $this->getPage(), 83 ]; 84 } 85 86 /** 87 * Evaluates a TypoScript condition given as input, 88 * eg. "[browser=net][...(other conditions)...]" 89 * 90 * @param string $string The condition to match against its criteria. 91 * @return bool Whether the condition matched 92 * @see \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::parse() 93 * @throws \TYPO3\CMS\Core\Configuration\TypoScript\Exception\InvalidTypoScriptConditionException 94 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 95 */ 96 protected function evaluateCondition($string) 97 { 98 if ($this->strictSyntaxEnabled()) { 99 trigger_error('The old condition syntax will be removed in TYPO3 v10.0, use the new expression language. Used condition: [' . $string . '].', E_USER_DEPRECATED); 100 } 101 102 list($key, $value) = GeneralUtility::trimExplode('=', $string, false, 2); 103 $result = $this->evaluateConditionCommon($key, $value); 104 if (is_bool($result)) { 105 return $result; 106 } 107 108 switch ($key) { 109 case 'usergroup': 110 $groupList = $this->getGroupList(); 111 // '0,-1' is the default usergroups when not logged in! 112 if ($groupList !== '0,-1') { 113 $values = GeneralUtility::trimExplode(',', $value, true); 114 foreach ($values as $test) { 115 if ($test === '*' || GeneralUtility::inList($groupList, $test)) { 116 return true; 117 } 118 } 119 } 120 break; 121 case 'treeLevel': 122 $values = GeneralUtility::trimExplode(',', $value, true); 123 $treeLevel = count($this->rootline) - 1; 124 foreach ($values as $test) { 125 if ($test == $treeLevel) { 126 return true; 127 } 128 } 129 break; 130 case 'PIDupinRootline': 131 case 'PIDinRootline': 132 $values = GeneralUtility::trimExplode(',', $value, true); 133 if ($key === 'PIDinRootline' || !in_array($this->pageId, $values)) { 134 foreach ($values as $test) { 135 foreach ($this->rootline as $rlDat) { 136 if ($rlDat['uid'] == $test) { 137 return true; 138 } 139 } 140 } 141 } 142 break; 143 case 'site': 144 $site = $this->getCurrentSite(); 145 if ($site instanceof Site) { 146 $values = GeneralUtility::trimExplode(',', $value, true); 147 foreach ($values as $test) { 148 $point = strcspn($test, '='); 149 $testValue = substr($test, $point + 1); 150 $testValue = trim($testValue); 151 $theVarName = trim(substr($test, 0, $point)); 152 $methodName = 'get' . ucfirst($theVarName); 153 if (method_exists($site, $methodName)) { 154 $sitePropertyValue = call_user_func([$site, $methodName]); 155 // loose check on purpose in order to check for integer values 156 if ($testValue == $sitePropertyValue) { 157 return true; 158 } 159 } 160 } 161 } 162 break; 163 case 'siteLanguage': 164 $siteLanguage = $this->getCurrentSiteLanguage(); 165 if ($siteLanguage instanceof SiteLanguage) { 166 $values = GeneralUtility::trimExplode(',', $value, true); 167 foreach ($values as $test) { 168 $point = strcspn($test, '='); 169 $testValue = substr($test, $point + 1); 170 $testValue = trim($testValue); 171 $theVarName = trim(substr($test, 0, $point)); 172 $methodName = 'get' . ucfirst($theVarName); 173 if (method_exists($siteLanguage, $methodName)) { 174 $languagePropertyValue = call_user_func([$siteLanguage, $methodName]); 175 // loose check on purpose in order to check for integer values 176 if ($testValue == $languagePropertyValue) { 177 return true; 178 } 179 } 180 } 181 } 182 break; 183 default: 184 $conditionResult = $this->evaluateCustomDefinedCondition($string); 185 if ($conditionResult !== null) { 186 return $conditionResult; 187 } 188 } 189 190 return false; 191 } 192 193 /** 194 * Returns GP / ENV / TSFE / session vars 195 * 196 * @example GP:L 197 * @example TSFE:fe_user|sesData|foo|bar 198 * @example TSFE:id 199 * @example ENV:HTTP_HOST 200 * 201 * @param string $var Identifier 202 * @return mixed|null The value of the variable pointed to or NULL if variable did not exist 203 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 204 */ 205 protected function getVariable($var) 206 { 207 $vars = explode(':', $var, 2); 208 $val = $this->getVariableCommon($vars); 209 if ($val === null) { 210 $splitAgain = explode('|', $vars[1], 2); 211 $k = trim($splitAgain[0]); 212 if ($k) { 213 switch ((string)trim($vars[0])) { 214 case 'TSFE': 215 if (strpos($vars[1], 'fe_user|sesData|') === 0) { 216 trigger_error( 217 'Condition on TSFE|fe_user|sesData is deprecated and will be removed in TYPO3 v10.0.', 218 E_USER_DEPRECATED 219 ); 220 $val = $this->getSessionVariable(substr($vars[1], 16)); 221 } else { 222 $val = $this->getGlobal('TSFE|' . $vars[1]); 223 } 224 break; 225 case 'session': 226 $val = $this->getSessionVariable($vars[1]); 227 break; 228 default: 229 } 230 } 231 } 232 return $val; 233 } 234 235 /** 236 * Return variable from current frontend user session 237 * 238 * @param string $var Session key 239 * @return mixed|null The value of the variable pointed to or NULL if variable did not exist 240 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 241 */ 242 protected function getSessionVariable(string $var) 243 { 244 $retVal = null; 245 $keyParts = explode('|', $var); 246 $sessionKey = array_shift($keyParts); 247 $tsfe = $this->getTypoScriptFrontendController(); 248 if ($tsfe && is_object($tsfe->fe_user)) { 249 $retVal = $tsfe->fe_user->getSessionData($sessionKey); 250 foreach ($keyParts as $keyPart) { 251 if (is_object($retVal)) { 252 $retVal = $retVal->{$keyPart}; 253 } elseif (is_array($retVal)) { 254 $retVal = $retVal[$keyPart]; 255 } else { 256 break; 257 } 258 } 259 } 260 return $retVal; 261 } 262 263 /** 264 * Get the usergroup list of the current user. 265 * 266 * @return string The usergroup list of the current user 267 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 268 */ 269 protected function getGroupList(): string 270 { 271 /** @var UserAspect $userAspect */ 272 $userAspect = $this->context->getAspect('frontend.user'); 273 return implode(',', $userAspect->getGroupIds()); 274 } 275 276 /** 277 * Determines the current page Id. 278 * 279 * @return int The current page Id 280 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 281 */ 282 protected function determinePageId() 283 { 284 return (int)($this->getTypoScriptFrontendController()->id ?? 0); 285 } 286 287 /** 288 * Gets the properties for the current page. 289 * 290 * @return array The properties for the current page. 291 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 292 */ 293 protected function getPage() 294 { 295 return is_array($this->getTypoScriptFrontendController()->page) 296 ? $this->getTypoScriptFrontendController()->page 297 : []; 298 } 299 300 /** 301 * Determines the rootline for the current page. 302 * 303 * @return array The rootline for the current page. 304 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 305 */ 306 protected function determineRootline() 307 { 308 return (array)$this->getTypoScriptFrontendController()->tmpl->rootLine; 309 } 310 311 /** 312 * Get the id of the current user. 313 * 314 * @return int The id of the current user 315 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 316 */ 317 protected function getUserId(): int 318 { 319 $userAspect = $this->context->getAspect('frontend.user'); 320 return $userAspect->get('id'); 321 } 322 323 /** 324 * Determines if a user is logged in. 325 * 326 * @return bool Determines if a user is logged in 327 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 328 */ 329 protected function isUserLoggedIn(): bool 330 { 331 /** @var UserAspect $userAspect */ 332 $userAspect = $this->context->getAspect('frontend.user'); 333 return $userAspect->isLoggedIn(); 334 } 335 336 /** 337 * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController 338 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 339 */ 340 protected function getTypoScriptFrontendController() 341 { 342 return $GLOBALS['TSFE']; 343 } 344 345 /** 346 * Returns the currently configured "site language" if a site is configured (= resolved) in the current request. 347 * 348 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 349 */ 350 protected function getCurrentSiteLanguage(): ?SiteLanguage 351 { 352 if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface 353 && $GLOBALS['TYPO3_REQUEST']->getAttribute('language') instanceof SiteLanguage) { 354 return $GLOBALS['TYPO3_REQUEST']->getAttribute('language'); 355 } 356 return null; 357 } 358 359 /** 360 * Returns the currently configured site if a site is configured (= resolved) in the current request. 361 * 362 * @deprecated since TYPO3 v9.4, will be removed in TYPO3 v10.0. 363 */ 364 protected function getCurrentSite(): ?Site 365 { 366 if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface 367 && $GLOBALS['TYPO3_REQUEST']->getAttribute('site') instanceof Site) { 368 return $GLOBALS['TYPO3_REQUEST']->getAttribute('site'); 369 } 370 return null; 371 } 372} 373