| Total Complexity | 80 |
| Total Lines | 852 |
| Duplicated Lines | 0 % |
| Changes | 1 | ||
| Bugs | 0 | Features | 0 |
Complex classes like NormalizedParams often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use NormalizedParams, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 32 | class NormalizedParams |
||
| 33 | { |
||
| 34 | /** |
||
| 35 | * Sanitized HTTP_HOST value |
||
| 36 | * |
||
| 37 | * host[:port] |
||
| 38 | * |
||
| 39 | * - www.domain.com |
||
| 40 | * - www.domain.com:443 |
||
| 41 | * - 192.168.1.42:80 |
||
| 42 | * |
||
| 43 | * @var string |
||
| 44 | */ |
||
| 45 | protected $httpHost = ''; |
||
| 46 | |||
| 47 | /** |
||
| 48 | * @var bool True if request has been done via HTTPS |
||
| 49 | */ |
||
| 50 | protected $isHttps = false; |
||
| 51 | |||
| 52 | /** |
||
| 53 | * Sanitized HTTP_HOST with protocol |
||
| 54 | * |
||
| 55 | * scheme://host[:port] |
||
| 56 | * |
||
| 57 | * - https://www.domain.com |
||
| 58 | * |
||
| 59 | * @var string |
||
| 60 | */ |
||
| 61 | protected $requestHost = ''; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * Host / domain part of HTTP_HOST, no port, no protocol |
||
| 65 | * |
||
| 66 | * - www.domain.com |
||
| 67 | * - 192.168.1.42 |
||
| 68 | * |
||
| 69 | * @var string |
||
| 70 | */ |
||
| 71 | protected $requestHostOnly = ''; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Port of HTTP_HOST if given |
||
| 75 | * |
||
| 76 | * @var int |
||
| 77 | */ |
||
| 78 | protected $requestPort = 0; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Entry script path of URI, without domain and without query parameters, with leading / |
||
| 82 | * |
||
| 83 | * [path_script] |
||
| 84 | * |
||
| 85 | * - /typo3/index.php |
||
| 86 | * |
||
| 87 | * @var string |
||
| 88 | */ |
||
| 89 | protected $scriptName = ''; |
||
| 90 | |||
| 91 | /** |
||
| 92 | * REQUEST URI without domain and scheme, with trailing slash |
||
| 93 | * |
||
| 94 | * [path][?[query]] |
||
| 95 | * |
||
| 96 | * - /index.php |
||
| 97 | * - /typo3/index.php/arg1/arg2/?arg1,arg2&p1=parameter1&p2[key]=value |
||
| 98 | * |
||
| 99 | * @var string |
||
| 100 | */ |
||
| 101 | protected $requestUri = ''; |
||
| 102 | |||
| 103 | /** |
||
| 104 | * REQUEST URI with scheme, host, port, path and query |
||
| 105 | * |
||
| 106 | * scheme://host[:[port]][path][?[query]] |
||
| 107 | * |
||
| 108 | * - http://www.domain.com/typo3/index.php?route=foo/bar&id=42 |
||
| 109 | * |
||
| 110 | * @var string |
||
| 111 | */ |
||
| 112 | protected $requestUrl = ''; |
||
| 113 | |||
| 114 | /** |
||
| 115 | * REQUEST URI with scheme, host, port and path, but *without* query part |
||
| 116 | * |
||
| 117 | * scheme://host[:[port]][path_script] |
||
| 118 | * |
||
| 119 | * - http://www.domain.com/typo3/index.php |
||
| 120 | * |
||
| 121 | * @var string |
||
| 122 | */ |
||
| 123 | protected $requestScript = ''; |
||
| 124 | |||
| 125 | /** |
||
| 126 | * Full Uri with path, but without script name and query parts |
||
| 127 | * |
||
| 128 | * scheme://host[:[port]][path_dir] |
||
| 129 | * |
||
| 130 | * - http://www.domain.com/typo3/ |
||
| 131 | * |
||
| 132 | * @var string |
||
| 133 | */ |
||
| 134 | protected $requestDir = ''; |
||
| 135 | |||
| 136 | /** |
||
| 137 | * True if request via a reverse proxy is detected |
||
| 138 | * |
||
| 139 | * @var bool |
||
| 140 | */ |
||
| 141 | protected $isBehindReverseProxy = false; |
||
| 142 | |||
| 143 | /** |
||
| 144 | * IPv4 or IPv6 address of remote client with resolved proxy setup |
||
| 145 | * |
||
| 146 | * @var string |
||
| 147 | */ |
||
| 148 | protected $remoteAddress = ''; |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Absolute server path to entry script on server filesystem |
||
| 152 | * |
||
| 153 | * - /var/www/typo3/index.php |
||
| 154 | * |
||
| 155 | * @var string |
||
| 156 | */ |
||
| 157 | protected $scriptFilename = ''; |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Absolute server path to web document root without trailing slash |
||
| 161 | * |
||
| 162 | * - /var/www/typo3 |
||
| 163 | * |
||
| 164 | * @var string |
||
| 165 | */ |
||
| 166 | protected $documentRoot = ''; |
||
| 167 | |||
| 168 | /** |
||
| 169 | * Website frontend URL. |
||
| 170 | * Note this is note "safe" if called from Backend since sys_domain and |
||
| 171 | * other factors are not taken into account. |
||
| 172 | * |
||
| 173 | * scheme://host[:[port]]/[path_dir] |
||
| 174 | * |
||
| 175 | * - https://www.domain.com/ |
||
| 176 | * - https://www.domain.com/some/sub/dir/ |
||
| 177 | * |
||
| 178 | * @var string |
||
| 179 | */ |
||
| 180 | protected $siteUrl = ''; |
||
| 181 | |||
| 182 | /** |
||
| 183 | * Path part to frontend, no domain, no protocol |
||
| 184 | * |
||
| 185 | * - / |
||
| 186 | * - /some/sub/dir/ |
||
| 187 | * |
||
| 188 | * @var string |
||
| 189 | */ |
||
| 190 | protected $sitePath = ''; |
||
| 191 | |||
| 192 | /** |
||
| 193 | * Path to script, without sub path if TYPO3 is running in sub directory, without trailing slash |
||
| 194 | * |
||
| 195 | * - typo/index.php?id=42 |
||
| 196 | * - index.php?id=42 |
||
| 197 | * |
||
| 198 | * @var string |
||
| 199 | */ |
||
| 200 | protected $siteScript = ''; |
||
| 201 | |||
| 202 | /** |
||
| 203 | * Entry script path of URI, without domain and without query parameters, with leading / |
||
| 204 | * This is often not set at all. |
||
| 205 | * Will be deprecated later, use $scriptName instead as more reliable solution. |
||
| 206 | * |
||
| 207 | * [path_script] |
||
| 208 | * |
||
| 209 | * - /typo3/index.php |
||
| 210 | * |
||
| 211 | * @var string |
||
| 212 | */ |
||
| 213 | protected $pathInfo = ''; |
||
| 214 | |||
| 215 | /** |
||
| 216 | * HTTP_REFERER |
||
| 217 | * Will be deprecated later, use $request->getServerParams()['HTTP_REFERER'] instead |
||
| 218 | * |
||
| 219 | * scheme://host[:[port]][path] |
||
| 220 | * |
||
| 221 | * - https://www.domain.com/typo3/index.php?id=42 |
||
| 222 | * |
||
| 223 | * @var string |
||
| 224 | */ |
||
| 225 | protected $httpReferer = ''; |
||
| 226 | |||
| 227 | /** |
||
| 228 | * HTTP_USER_AGENT |
||
| 229 | * Will be deprecated later, use $request->getServerParams()['HTTP_USER_AGENT'] instead |
||
| 230 | * |
||
| 231 | * - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 |
||
| 232 | * |
||
| 233 | * @var string |
||
| 234 | */ |
||
| 235 | protected $httpUserAgent = ''; |
||
| 236 | |||
| 237 | /** |
||
| 238 | * HTTP_ACCEPT_ENCODING |
||
| 239 | * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_ENCODING'] instead |
||
| 240 | * |
||
| 241 | * - gzip, deflate |
||
| 242 | * |
||
| 243 | * @var string |
||
| 244 | */ |
||
| 245 | protected $httpAcceptEncoding = ''; |
||
| 246 | |||
| 247 | /** |
||
| 248 | * HTTP_ACCEPT_LANGUAGE |
||
| 249 | * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] instead |
||
| 250 | * |
||
| 251 | * - de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7 |
||
| 252 | * |
||
| 253 | * @var string |
||
| 254 | */ |
||
| 255 | protected $httpAcceptLanguage = ''; |
||
| 256 | |||
| 257 | /** |
||
| 258 | * REMOTE_HOST Resolved host name of REMOTE_ADDR if configured in web server |
||
| 259 | * Will be deprecated later, use $request->getServerParams()['REMOTE_HOST'] instead |
||
| 260 | * |
||
| 261 | * - www.clientDomain.com |
||
| 262 | * |
||
| 263 | * @var string |
||
| 264 | */ |
||
| 265 | protected $remoteHost = ''; |
||
| 266 | |||
| 267 | /** |
||
| 268 | * QUERY_STRING |
||
| 269 | * Will be deprecated later, use $request->getServerParams()['QUERY_STRING'] instead |
||
| 270 | * |
||
| 271 | * [query] |
||
| 272 | * |
||
| 273 | * - id=42&foo=bar |
||
| 274 | * |
||
| 275 | * @var string |
||
| 276 | */ |
||
| 277 | protected $queryString = ''; |
||
| 278 | |||
| 279 | /** |
||
| 280 | * Constructor calculates all values by incoming variables. |
||
| 281 | * |
||
| 282 | * This object is immutable. |
||
| 283 | * |
||
| 284 | * All determine*() "detail worker methods" in this class retrieve their dependencies |
||
| 285 | * to other properties as method arguments, they are static, stateless and have no |
||
| 286 | * dependency to $this. This ensures the chain of inter-property dependencies |
||
| 287 | * is visible by only looking at the construct() method. |
||
| 288 | * |
||
| 289 | * @param array $serverParams , usually coming from $_SERVER or $request->getServerParams() |
||
| 290 | * @param array $configuration $GLOBALS['TYPO3_CONF_VARS']['SYS'] |
||
| 291 | * @param string $pathThisScript Absolute server entry script path, usually found within Environment::getCurrentScript() |
||
| 292 | * @param string $pathSite Absolute server path to document root, Environment::getPublicPath() |
||
| 293 | */ |
||
| 294 | public function __construct(array $serverParams, array $configuration, string $pathThisScript, string $pathSite) |
||
| 295 | { |
||
| 296 | $isBehindReverseProxy = $this->isBehindReverseProxy = self::determineIsBehindReverseProxy( |
||
| 297 | $serverParams, |
||
| 298 | $configuration |
||
| 299 | ); |
||
| 300 | $httpHost = $this->httpHost = self::determineHttpHost($serverParams, $configuration, $isBehindReverseProxy); |
||
| 301 | $isHttps = $this->isHttps = self::determineHttps($serverParams, $configuration); |
||
| 302 | $requestHost = $this->requestHost = ($isHttps ? 'https://' : 'http://') . $httpHost; |
||
| 303 | $requestHostOnly = $this->requestHostOnly = self::determineRequestHostOnly($httpHost); |
||
| 304 | $this->requestPort = self::determineRequestPort($httpHost, $requestHostOnly); |
||
| 305 | $scriptName = $this->scriptName = self::determineScriptName( |
||
| 306 | $serverParams, |
||
| 307 | $configuration, |
||
| 308 | $isHttps, |
||
| 309 | $isBehindReverseProxy |
||
| 310 | ); |
||
| 311 | $requestUri = $this->requestUri = self::determineRequestUri( |
||
| 312 | $serverParams, |
||
| 313 | $configuration, |
||
| 314 | $isHttps, |
||
| 315 | $scriptName, |
||
| 316 | $isBehindReverseProxy |
||
| 317 | ); |
||
| 318 | $requestUrl = $this->requestUrl = $requestHost . $requestUri; |
||
| 319 | $this->requestScript = $requestHost . $scriptName; |
||
| 320 | $requestDir = $this->requestDir = $requestHost . GeneralUtility::dirname($scriptName) . '/'; |
||
| 321 | $this->remoteAddress = self::determineRemoteAddress($serverParams, $configuration, $isBehindReverseProxy); |
||
| 322 | $scriptFilename = $this->scriptFilename = $pathThisScript; |
||
| 323 | $this->documentRoot = self::determineDocumentRoot($scriptName, $scriptFilename); |
||
| 324 | $siteUrl = $this->siteUrl = self::determineSiteUrl($requestDir, $pathThisScript, $pathSite . '/'); |
||
| 325 | $this->sitePath = self::determineSitePath($requestHost, $siteUrl); |
||
| 326 | $this->siteScript = self::determineSiteScript($requestUrl, $siteUrl); |
||
| 327 | |||
| 328 | // @deprecated Below variables can be fully deprecated as soon as core does not use them anymore |
||
| 329 | $this->pathInfo = $serverParams['PATH_INFO'] ?? ''; |
||
| 330 | $this->httpReferer = $serverParams['HTTP_REFERER'] ?? ''; |
||
| 331 | $this->httpUserAgent = $serverParams['HTTP_USER_AGENT'] ?? ''; |
||
| 332 | $this->httpAcceptEncoding = $serverParams['HTTP_ACCEPT_ENCODING'] ?? ''; |
||
| 333 | $this->httpAcceptLanguage = $serverParams['HTTP_ACCEPT_LANGUAGE'] ?? ''; |
||
| 334 | $this->remoteHost = $serverParams['REMOTE_HOST'] ?? ''; |
||
| 335 | $this->queryString = $serverParams['QUERY_STRING'] ?? ''; |
||
| 336 | } |
||
| 337 | |||
| 338 | /** |
||
| 339 | * @return string Sanitized HTTP_HOST value host[:port] |
||
| 340 | */ |
||
| 341 | public function getHttpHost(): string |
||
| 342 | { |
||
| 343 | return $this->httpHost; |
||
| 344 | } |
||
| 345 | |||
| 346 | /** |
||
| 347 | * @return bool True if client request has been done using HTTPS |
||
| 348 | */ |
||
| 349 | public function isHttps(): bool |
||
| 350 | { |
||
| 351 | return $this->isHttps; |
||
| 352 | } |
||
| 353 | |||
| 354 | /** |
||
| 355 | * @return string Sanitized HTTP_HOST with protocol scheme://host[:port], eg. https://www.domain.com/ |
||
| 356 | */ |
||
| 357 | public function getRequestHost(): string |
||
| 358 | { |
||
| 359 | return $this->requestHost; |
||
| 360 | } |
||
| 361 | |||
| 362 | /** |
||
| 363 | * @return string Host / domain /IP only, eg. www.domain.com |
||
| 364 | */ |
||
| 365 | public function getRequestHostOnly(): string |
||
| 366 | { |
||
| 367 | return $this->requestHostOnly; |
||
| 368 | } |
||
| 369 | |||
| 370 | /** |
||
| 371 | * @return int Requested port if given, eg. 8080 - often not explicitly given, then 0 |
||
| 372 | */ |
||
| 373 | public function getRequestPort(): int |
||
| 374 | { |
||
| 375 | return $this->requestPort; |
||
| 376 | } |
||
| 377 | |||
| 378 | /** |
||
| 379 | * @return string Script path part of URI, eg. 'typo3/index.php' |
||
| 380 | */ |
||
| 381 | public function getScriptName(): string |
||
| 382 | { |
||
| 383 | return $this->scriptName; |
||
| 384 | } |
||
| 385 | |||
| 386 | /** |
||
| 387 | * @return string Request Uri without domain and protocol, eg. /index.php?id=42 |
||
| 388 | */ |
||
| 389 | public function getRequestUri(): string |
||
| 390 | { |
||
| 391 | return $this->requestUri; |
||
| 392 | } |
||
| 393 | |||
| 394 | /** |
||
| 395 | * @return string Full REQUEST_URI, eg. http://www.domain.com/typo3/index.php?route=foo/bar&id=42 |
||
| 396 | */ |
||
| 397 | public function getRequestUrl(): string |
||
| 398 | { |
||
| 399 | return $this->requestUrl; |
||
| 400 | } |
||
| 401 | |||
| 402 | /** |
||
| 403 | * @return string REQUEST URI without query part, eg. http://www.domain.com/typo3/index.php |
||
| 404 | */ |
||
| 405 | public function getRequestScript(): string |
||
| 406 | { |
||
| 407 | return $this->requestScript; |
||
| 408 | } |
||
| 409 | |||
| 410 | /** |
||
| 411 | * @return string REQUEST URI without script file name and query parts, eg. http://www.domain.com/typo3/ |
||
| 412 | */ |
||
| 413 | public function getRequestDir(): string |
||
| 414 | { |
||
| 415 | return $this->requestDir; |
||
| 416 | } |
||
| 417 | |||
| 418 | /** |
||
| 419 | * @return bool True if request comes from a configured reverse proxy |
||
| 420 | */ |
||
| 421 | public function isBehindReverseProxy(): bool |
||
| 422 | { |
||
| 423 | return $this->isBehindReverseProxy; |
||
| 424 | } |
||
| 425 | |||
| 426 | /** |
||
| 427 | * @return string Client IP |
||
| 428 | */ |
||
| 429 | public function getRemoteAddress(): string |
||
| 430 | { |
||
| 431 | return $this->remoteAddress; |
||
| 432 | } |
||
| 433 | |||
| 434 | /** |
||
| 435 | * @return string Absolute entry script path on server, eg. /var/www/typo3/index.php |
||
| 436 | */ |
||
| 437 | public function getScriptFilename(): string |
||
| 438 | { |
||
| 439 | return $this->scriptFilename; |
||
| 440 | } |
||
| 441 | |||
| 442 | /** |
||
| 443 | * @return string Absolute path to web document root, eg. /var/www/typo3 |
||
| 444 | */ |
||
| 445 | public function getDocumentRoot(): string |
||
| 446 | { |
||
| 447 | return $this->documentRoot; |
||
| 448 | } |
||
| 449 | |||
| 450 | /** |
||
| 451 | * @return string Website frontend url, eg. https://www.domain.com/some/sub/dir/ |
||
| 452 | */ |
||
| 453 | public function getSiteUrl(): string |
||
| 454 | { |
||
| 455 | return $this->siteUrl; |
||
| 456 | } |
||
| 457 | |||
| 458 | /** |
||
| 459 | * @return string Path part to frontend, eg. /some/sub/dir/ |
||
| 460 | */ |
||
| 461 | public function getSitePath(): string |
||
| 462 | { |
||
| 463 | return $this->sitePath; |
||
| 464 | } |
||
| 465 | |||
| 466 | /** |
||
| 467 | * @return string Path part to entry script with parameters, without sub dir, eg 'typo3/index.php?id=42' |
||
| 468 | */ |
||
| 469 | public function getSiteScript(): string |
||
| 472 | } |
||
| 473 | |||
| 474 | /** |
||
| 475 | * Will be deprecated later, use getScriptName() as reliable solution instead |
||
| 476 | * |
||
| 477 | * @return string Script path part of URI, eg. 'typo3/index.php' |
||
| 478 | */ |
||
| 479 | public function getPathInfo(): string |
||
| 480 | { |
||
| 481 | return $this->pathInfo; |
||
| 482 | } |
||
| 483 | |||
| 484 | /** |
||
| 485 | * Will be deprecated later, use $request->getServerParams()['HTTP_REFERER'] instead |
||
| 486 | * |
||
| 487 | * @return string HTTP_REFERER, eg. 'https://www.domain.com/typo3/index.php?id=42' |
||
| 488 | */ |
||
| 489 | public function getHttpReferer(): string |
||
| 490 | { |
||
| 491 | return $this->httpReferer; |
||
| 492 | } |
||
| 493 | |||
| 494 | /** |
||
| 495 | * Will be deprecated later, use $request->getServerParams()['HTTP_USER_AGENT'] instead |
||
| 496 | * |
||
| 497 | * @return string HTTP_USER_AGENT identifier |
||
| 498 | */ |
||
| 499 | public function getHttpUserAgent(): string |
||
| 500 | { |
||
| 501 | return $this->httpUserAgent; |
||
| 502 | } |
||
| 503 | |||
| 504 | /** |
||
| 505 | * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_ENCODING'] instead |
||
| 506 | * |
||
| 507 | * @return string HTTP_ACCEPT_ENCODING, eg. 'gzip, deflate' |
||
| 508 | */ |
||
| 509 | public function getHttpAcceptEncoding(): string |
||
| 510 | { |
||
| 511 | return $this->httpAcceptEncoding; |
||
| 512 | } |
||
| 513 | |||
| 514 | /** |
||
| 515 | * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] instead |
||
| 516 | * |
||
| 517 | * @return string HTTP_ACCEPT_LANGUAGE, eg. 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7' |
||
| 518 | */ |
||
| 519 | public function getHttpAcceptLanguage(): string |
||
| 522 | } |
||
| 523 | |||
| 524 | /** |
||
| 525 | * Will be deprecated later, use $request->getServerParams()['REMOTE_HOST'] instead |
||
| 526 | * |
||
| 527 | * @return string REMOTE_HOST if configured in web server, eg. 'www.clientDomain.com' |
||
| 528 | */ |
||
| 529 | public function getRemoteHost(): string |
||
| 530 | { |
||
| 531 | return $this->remoteHost; |
||
| 532 | } |
||
| 533 | |||
| 534 | /** |
||
| 535 | * Will be deprecated later, use $request->getServerParams()['QUERY_STRING'] instead |
||
| 536 | * |
||
| 537 | * @return string QUERY_STRING, eg 'id=42&foo=bar' |
||
| 538 | */ |
||
| 539 | public function getQueryString(): string |
||
| 542 | } |
||
| 543 | |||
| 544 | /** |
||
| 545 | * Sanitize HTTP_HOST, take proxy configuration into account and |
||
| 546 | * verify allowed hosts with configured trusted hosts pattern. |
||
| 547 | * |
||
| 548 | * @param array $serverParams Basically the $_SERVER, but from $request object |
||
| 549 | * @param array $configuration $TYPO3_CONF_VARS['SYS'] array |
||
| 550 | * @param bool $isBehindReverseProxy True if reverse proxy setup is detected |
||
| 551 | * @return string Sanitized HTTP_HOST |
||
| 552 | */ |
||
| 553 | protected static function determineHttpHost( |
||
| 554 | array $serverParams, |
||
| 555 | array $configuration, |
||
| 556 | bool $isBehindReverseProxy |
||
| 557 | ): string { |
||
| 558 | $httpHost = $serverParams['HTTP_HOST'] ?? ''; |
||
| 559 | if ($isBehindReverseProxy) { |
||
| 560 | // If the request comes from a configured proxy which has set HTTP_X_FORWARDED_HOST, then |
||
| 561 | // evaluate reverseProxyHeaderMultiValue and |
||
| 562 | $xForwardedHostArray = GeneralUtility::trimExplode(',', $serverParams['HTTP_X_FORWARDED_HOST'] ?? '', true); |
||
| 563 | $xForwardedHost = ''; |
||
| 564 | // Choose which host in list to use |
||
| 565 | if (!empty($xForwardedHostArray)) { |
||
| 566 | $configuredReverseProxyHeaderMultiValue = trim($configuration['reverseProxyHeaderMultiValue'] ?? ''); |
||
| 567 | // Default if reverseProxyHeaderMultiValue is not set or set to 'none', instead of 'first' / 'last' is to |
||
| 568 | // ignore $serverParams['HTTP_X_FORWARDED_HOST'] |
||
| 569 | // @todo: Maybe this default is stupid: Both SYS/reverseProxyIP hand SYS/reverseProxyHeaderMultiValue have to |
||
| 570 | // @todo: be configured for a working setup. It would be easier to only configure SYS/reverseProxyIP and fall |
||
| 571 | // @todo: back to "first" if SYS/reverseProxyHeaderMultiValue is not set. |
||
| 572 | if ($configuredReverseProxyHeaderMultiValue === 'last') { |
||
| 573 | $xForwardedHost = array_pop($xForwardedHostArray); |
||
| 574 | } elseif ($configuredReverseProxyHeaderMultiValue === 'first') { |
||
| 575 | $xForwardedHost = array_shift($xForwardedHostArray); |
||
| 576 | } |
||
| 577 | } |
||
| 578 | if ($xForwardedHost) { |
||
| 579 | $httpHost = $xForwardedHost; |
||
| 580 | } |
||
| 581 | } |
||
| 582 | if (!GeneralUtility::isAllowedHostHeaderValue($httpHost)) { |
||
| 583 | throw new \UnexpectedValueException( |
||
| 584 | 'The current host header value does not match the configured trusted hosts pattern!' |
||
| 585 | . ' Check the pattern defined in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'trustedHostsPattern\']' |
||
| 586 | . ' and adapt it, if you want to allow the current host header \'' . $httpHost . '\' for your installation.', |
||
| 587 | 1396795886 |
||
| 588 | ); |
||
| 589 | } |
||
| 590 | return $httpHost; |
||
| 591 | } |
||
| 592 | |||
| 593 | /** |
||
| 594 | * Determine if the client called via HTTPS. Takes proxy ssl terminator |
||
| 595 | * configurations into account. |
||
| 596 | * |
||
| 597 | * @param array $serverParams Basically the $_SERVER, but from $request object |
||
| 598 | * @param array $configuration $TYPO3_CONF_VARS['SYS'] array |
||
| 599 | * @return bool True if request has been done via HTTPS |
||
| 600 | */ |
||
| 601 | protected static function determineHttps(array $serverParams, array $configuration): bool |
||
| 618 | } |
||
| 619 | |||
| 620 | /** |
||
| 621 | * Determine script name and path |
||
| 622 | * |
||
| 623 | * @param array $serverParams Basically the $_SERVER, but from $request object |
||
| 624 | * @param array $configuration TYPO3_CONF_VARS['SYS'] array |
||
| 625 | * @param bool $isHttps True if used protocol is HTTPS |
||
| 626 | * @param bool $isBehindReverseProxy True if reverse proxy setup is detected |
||
| 627 | * @return string Sanitized script name |
||
| 628 | */ |
||
| 629 | protected static function determineScriptName( |
||
| 630 | array $serverParams, |
||
| 631 | array $configuration, |
||
| 632 | bool $isHttps, |
||
| 633 | bool $isBehindReverseProxy |
||
| 634 | ): string { |
||
| 635 | // see https://forge.typo3.org/issues/89312 |
||
| 636 | // When using a CGI wrapper to dispatch the PHP process `ORIG_SCRIPT_NAME` |
||
| 637 | // contains the name of the wrapper script (which is most probably outside |
||
| 638 | // the TYPO3's project root) and leads to invalid prefixes, e.g. resolving |
||
| 639 | // the `siteUrl` incorrectly as `http://ip10.local/fcgi/` instead of |
||
| 640 | // actual `http://ip10.local/` |
||
| 641 | $possiblePathInfo = ($serverParams['ORIG_PATH_INFO'] ?? '') ?: ($serverParams['PATH_INFO'] ?? ''); |
||
| 642 | $possibleScriptName = ($serverParams['ORIG_SCRIPT_NAME'] ?? '') ?: ($serverParams['SCRIPT_NAME'] ?? ''); |
||
| 643 | $scriptName = Environment::isRunningOnCgiServer() && $possiblePathInfo |
||
| 644 | ? $possiblePathInfo |
||
|
|
|||
| 645 | : $possibleScriptName; |
||
| 646 | if ($isBehindReverseProxy) { |
||
| 647 | // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix |
||
| 648 | if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) { |
||
| 649 | $scriptName = $configuration['reverseProxyPrefixSSL'] . $scriptName; |
||
| 650 | } elseif (!empty($configuration['reverseProxyPrefix'])) { |
||
| 651 | $scriptName = $configuration['reverseProxyPrefix'] . $scriptName; |
||
| 652 | } |
||
| 653 | } |
||
| 654 | return $scriptName; |
||
| 655 | } |
||
| 656 | |||
| 657 | /** |
||
| 658 | * Determine REQUEST_URI, taking proxy configuration and various web server |
||
| 659 | * specifics into account. |
||
| 660 | * |
||
| 661 | * @param array $serverParams Basically the $_SERVER, but from $request object |
||
| 662 | * @param array $configuration $TYPO3_CONF_VARS['SYS'] array |
||
| 663 | * @param bool $isHttps True if used protocol is HTTPS |
||
| 664 | * @param string $scriptName Script name |
||
| 665 | * @param bool $isBehindReverseProxy True if reverse proxy setup is detected |
||
| 666 | * @return string Sanitized REQUEST_URI |
||
| 667 | */ |
||
| 668 | protected static function determineRequestUri( |
||
| 669 | array $serverParams, |
||
| 670 | array $configuration, |
||
| 671 | bool $isHttps, |
||
| 672 | string $scriptName, |
||
| 673 | bool $isBehindReverseProxy |
||
| 674 | ): string { |
||
| 675 | $proxyPrefixApplied = false; |
||
| 676 | if (!empty($configuration['requestURIvar'])) { |
||
| 677 | // This is for URL rewriter that store the original URI in a server |
||
| 678 | // variable (e.g. ISAPI Rewriter for IIS: HTTP_X_REWRITE_URL), a config then looks like: |
||
| 679 | // requestURIvar = '_SERVER|HTTP_X_REWRITE_URL' which will access $GLOBALS['_SERVER']['HTTP_X_REWRITE_URL'] |
||
| 680 | [$firstLevel, $secondLevel] = GeneralUtility::trimExplode('|', $configuration['requestURIvar'], true); |
||
| 681 | $requestUri = $GLOBALS[$firstLevel][$secondLevel]; |
||
| 682 | } elseif (empty($serverParams['REQUEST_URI'])) { |
||
| 683 | // This is for ISS/CGI which does not have the REQUEST_URI available. |
||
| 684 | $queryString = !empty($serverParams['QUERY_STRING']) ? '?' . $serverParams['QUERY_STRING'] : ''; |
||
| 685 | // script name already had the proxy prefix handling, we must not add it a second time |
||
| 686 | $proxyPrefixApplied = true; |
||
| 687 | $requestUri = '/' . ltrim($scriptName, '/') . $queryString; |
||
| 688 | } else { |
||
| 689 | $requestUri = '/' . ltrim($serverParams['REQUEST_URI'], '/'); |
||
| 690 | } |
||
| 691 | if (!$proxyPrefixApplied && $isBehindReverseProxy) { |
||
| 692 | // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix |
||
| 693 | if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) { |
||
| 694 | $requestUri = $configuration['reverseProxyPrefixSSL'] . $requestUri; |
||
| 695 | } elseif (!empty($configuration['reverseProxyPrefix'])) { |
||
| 696 | $requestUri = $configuration['reverseProxyPrefix'] . $requestUri; |
||
| 697 | } |
||
| 698 | } |
||
| 699 | return $requestUri; |
||
| 700 | } |
||
| 701 | |||
| 702 | /** |
||
| 703 | * Determine clients REMOTE_ADDR, even if there is a reverse proxy in between. |
||
| 704 | * |
||
| 705 | * @param array $serverParams Basically the $_SERVER, but from $request object |
||
| 706 | * @param array $configuration $TYPO3_CONF_VARS[SYS] array |
||
| 707 | * @param bool $isBehindReverseProxy True if reverse proxy setup is detected |
||
| 708 | * @return string Resolved REMOTE_ADDR |
||
| 709 | */ |
||
| 710 | protected static function determineRemoteAddress( |
||
| 711 | array $serverParams, |
||
| 712 | array $configuration, |
||
| 713 | bool $isBehindReverseProxy |
||
| 714 | ): string { |
||
| 715 | $remoteAddress = trim($serverParams['REMOTE_ADDR'] ?? ''); |
||
| 716 | if ($isBehindReverseProxy) { |
||
| 717 | $ip = GeneralUtility::trimExplode(',', $serverParams['HTTP_X_FORWARDED_FOR'] ?? '', true); |
||
| 718 | // Choose which IP in list to use |
||
| 719 | $configuredReverseProxyHeaderMultiValue = trim($configuration['reverseProxyHeaderMultiValue'] ?? ''); |
||
| 720 | if (!empty($ip) && $configuredReverseProxyHeaderMultiValue === 'last') { |
||
| 721 | $ip = array_pop($ip); |
||
| 722 | } elseif (!empty($ip) && $configuredReverseProxyHeaderMultiValue === 'first') { |
||
| 723 | $ip = array_shift($ip); |
||
| 724 | } else { |
||
| 725 | $ip = ''; |
||
| 726 | } |
||
| 727 | if (GeneralUtility::validIP($ip)) { |
||
| 728 | $remoteAddress = $ip; |
||
| 729 | } |
||
| 730 | } |
||
| 731 | return $remoteAddress; |
||
| 732 | } |
||
| 733 | |||
| 734 | /** |
||
| 735 | * Check if a configured reverse proxy setup is detected. |
||
| 736 | * |
||
| 737 | * @param array $serverParams Basically the $_SERVER, but from $request object |
||
| 738 | * @param array $configuration $TYPO3_CONF_VARS[SYS] array |
||
| 739 | * @return bool True if TYPO3 is behind a reverse proxy |
||
| 740 | */ |
||
| 741 | protected static function determineIsBehindReverseProxy($serverParams, $configuration): bool |
||
| 742 | { |
||
| 743 | return GeneralUtility::cmpIP( |
||
| 744 | trim($serverParams['REMOTE_ADDR'] ?? ''), |
||
| 745 | trim($configuration['reverseProxyIP'] ?? '') |
||
| 746 | ); |
||
| 747 | } |
||
| 748 | |||
| 749 | /** |
||
| 750 | * HTTP_HOST without port |
||
| 751 | * |
||
| 752 | * @param string $httpHost host[:[port]] |
||
| 753 | * @return string Resolved host |
||
| 754 | */ |
||
| 755 | protected static function determineRequestHostOnly(string $httpHost): string |
||
| 756 | { |
||
| 757 | $httpHostBracketPosition = strpos($httpHost, ']'); |
||
| 758 | $httpHostParts = explode(':', $httpHost); |
||
| 759 | return $httpHostBracketPosition !== false ? substr( |
||
| 760 | $httpHost, |
||
| 761 | 0, |
||
| 762 | $httpHostBracketPosition + 1 |
||
| 763 | ) : array_shift($httpHostParts); |
||
| 764 | } |
||
| 765 | |||
| 766 | /** |
||
| 767 | * Requested port if given |
||
| 768 | * |
||
| 769 | * @param string $httpHost host[:[port]] |
||
| 770 | * @param string $httpHostOnly host |
||
| 771 | * @return int Resolved port if given, else 0 |
||
| 772 | */ |
||
| 773 | protected static function determineRequestPort(string $httpHost, string $httpHostOnly): int |
||
| 774 | { |
||
| 775 | return strlen($httpHost) > strlen($httpHostOnly) ? (int)substr($httpHost, strlen($httpHostOnly) + 1) : 0; |
||
| 776 | } |
||
| 777 | |||
| 778 | /** |
||
| 779 | * Calculate absolute path to web document root |
||
| 780 | * |
||
| 781 | * @param string $scriptName Entry script path of URI, without domain and without query parameters, with leading / |
||
| 782 | * @param string $scriptFilename Absolute path to entry script on server filesystem |
||
| 783 | * @return string Path to document root with trailing slash |
||
| 784 | */ |
||
| 785 | protected static function determineDocumentRoot(string $scriptName, string $scriptFilename): string |
||
| 808 | } |
||
| 809 | |||
| 810 | /** |
||
| 811 | * Determine frontend url |
||
| 812 | * |
||
| 813 | * @param string $requestDir Full Uri with path, but without script name and query parts |
||
| 814 | * @param string $pathThisScript Absolute path to entry script on server filesystem |
||
| 815 | * @param string $pathSite Absolute server path to document root |
||
| 816 | * @return string Calculated Frontend Url |
||
| 817 | */ |
||
| 818 | protected static function determineSiteUrl(string $requestDir, string $pathThisScript, string $pathSite): string |
||
| 819 | { |
||
| 820 | if (defined('TYPO3_PATH_WEB')) { |
||
| 821 | // This can only be set by external entry scripts |
||
| 822 | $siteUrl = $requestDir; |
||
| 823 | } else { |
||
| 824 | $pathThisScriptDir = substr(dirname($pathThisScript), strlen($pathSite)) . '/'; |
||
| 825 | $siteUrl = substr($requestDir, 0, -strlen($pathThisScriptDir)); |
||
| 826 | $siteUrl = rtrim($siteUrl, '/') . '/'; |
||
| 827 | } |
||
| 828 | return $siteUrl; |
||
| 829 | } |
||
| 830 | |||
| 831 | /** |
||
| 832 | * Determine site path |
||
| 833 | * |
||
| 834 | * @param string $requestHost scheme://host[:port] |
||
| 835 | * @param string $siteUrl Full Frontend Url |
||
| 836 | * @return string |
||
| 837 | */ |
||
| 838 | protected static function determineSitePath(string $requestHost, string $siteUrl): string |
||
| 839 | { |
||
| 840 | return (string)substr($siteUrl, strlen($requestHost)); |
||
| 841 | } |
||
| 842 | |||
| 843 | /** |
||
| 844 | * Determine site script |
||
| 845 | * |
||
| 846 | * @param string $requestUrl |
||
| 847 | * @param string $siteUrl |
||
| 848 | * @return string |
||
| 849 | */ |
||
| 850 | protected static function determineSiteScript(string $requestUrl, string $siteUrl): string |
||
| 853 | } |
||
| 854 | |||
| 855 | /** |
||
| 856 | * Factory method, to allow TYPO3 to handle configuration options directly. |
||
| 857 | * |
||
| 858 | * @param array $serverParams - could be fulfilled by $_SERVER (on web requests) |
||
| 859 | * @param array|null $systemConfiguration |
||
| 860 | * @return static |
||
| 861 | */ |
||
| 862 | public static function createFromServerParams(array $serverParams, array $systemConfiguration = null): self |
||
| 863 | { |
||
| 864 | return new NormalizedParams( |
||
| 865 | $serverParams, |
||
| 866 | $systemConfiguration ?? $GLOBALS['TYPO3_CONF_VARS']['SYS'], |
||
| 867 | Environment::getCurrentScript(), |
||
| 868 | Environment::getPublicPath() |
||
| 869 | ); |
||
| 870 | } |
||
| 871 | |||
| 872 | /** |
||
| 873 | * Factory method for creating normalized params from a PSR-7 server request object |
||
| 874 | * |
||
| 875 | * @param ServerRequestInterface $request |
||
| 876 | * @param array|null $systemConfiguration |
||
| 877 | * @return static |
||
| 878 | */ |
||
| 879 | public static function createFromRequest(ServerRequestInterface $request, array $systemConfiguration = null): self |
||
| 884 | ); |
||
| 885 | } |
||
| 886 | } |
||
| 887 |