[TASK] Use NormalizedParams with simplified arguments
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Http / NormalizedParams.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Core\Http;
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 TYPO3\CMS\Core\Utility\GeneralUtility;
19
20 /**
21 * This class provides normalized server parameters in HTTP request context.
22 * It normalizes reverse proxy scenarios and various other web server specific differences
23 * of the native PSR-7 request object parameters (->getServerParams() / $GLOBALS['_SERVER']).
24 *
25 * An instance of this class is available as PSR-7 ServerRequestInterface attribute:
26 * $normalizedParams = $request->getAttribute('normalizedParams')
27 *
28 * This class substitutes the old GeneralUtility::getIndpEnv() method.
29 */
30 class NormalizedParams
31 {
32 /**
33 * Sanitized HTTP_HOST value
34 *
35 * host[:port]
36 *
37 * - www.domain.com
38 * - www.domain.com:443
39 * - 192.168.1.42:80
40 *
41 * @var string
42 */
43 protected $httpHost = '';
44
45 /**
46 * @var bool True if request has been done via HTTPS
47 */
48 protected $isHttps = false;
49
50 /**
51 * Sanitized HTTP_HOST with protocol
52 *
53 * scheme://host[:port]
54 *
55 * - https://www.domain.com
56 *
57 * @var string
58 */
59 protected $requestHost = '';
60
61 /**
62 * Host / domain part of HTTP_HOST, no port, no protocol
63 *
64 * - www.domain.com
65 * - 192.168.1.42
66 *
67 * @var string
68 */
69 protected $requestHostOnly = '';
70
71 /**
72 * Port of HTTP_HOST if given
73 *
74 * @var int
75 */
76 protected $requestPort = 0;
77
78 /**
79 * Entry script path of URI, without domain and without query parameters, with leading /
80 *
81 * [path_script]
82 *
83 * - /typo3/index.php
84 *
85 * @var string
86 */
87 protected $scriptName = '';
88
89 /**
90 * REQUEST URI without domain and scheme, with trailing slash
91 *
92 * [path][?[query]]
93 *
94 * - /index.php
95 * - /typo3/index.php/arg1/arg2/?arg1,arg2&p1=parameter1&p2[key]=value
96 *
97 * @var string
98 */
99 protected $requestUri = '';
100
101 /**
102 * REQUEST URI with scheme, host, port, path and query
103 *
104 * scheme://host[:[port]][path][?[query]]
105 *
106 * - http://www.domain.com/typo3/index.php?route=foo/bar&id=42
107 *
108 * @var string
109 */
110 protected $requestUrl = '';
111
112 /**
113 * REQUEST URI with scheme, host, port and path, but *without* query part
114 *
115 * scheme://host[:[port]][path_script]
116 *
117 * - http://www.domain.com/typo3/index.php
118 *
119 * @var string
120 */
121 protected $requestScript = '';
122
123 /**
124 * Full Uri with path, but without script name and query parts
125 *
126 * scheme://host[:[port]][path_dir]
127 *
128 * - http://www.domain.com/typo3/
129 *
130 * @var string
131 */
132 protected $requestDir = '';
133
134 /**
135 * True if request via a reverse proxy is detected
136 *
137 * @var bool
138 */
139 protected $isBehindReverseProxy = false;
140
141 /**
142 * IPv4 or IPv6 address of remote client with resolved proxy setup
143 *
144 * @var string
145 */
146 protected $remoteAddress = '';
147
148 /**
149 * Absolute server path to entry script on server filesystem
150 *
151 * - /var/www/typo3/index.php
152 *
153 * @var string
154 */
155 protected $scriptFilename = '';
156
157 /**
158 * Absolute server path to web document root without trailing slash
159 *
160 * - /var/www/typo3
161 *
162 * @var string
163 */
164 protected $documentRoot = '';
165
166 /**
167 * Website frontend URL.
168 * Note this is note "safe" if called from Backend since sys_domain and
169 * other factors are not taken into account.
170 *
171 * scheme://host[:[port]]/[path_dir]
172 *
173 * - https://www.domain.com/
174 * - https://www.domain.com/some/sub/dir/
175 *
176 * @var string
177 */
178 protected $siteUrl = '';
179
180 /**
181 * Path part to frontend, no domain, no protocol
182 *
183 * - /
184 * - /some/sub/dir/
185 *
186 * @var string
187 */
188 protected $sitePath = '';
189
190 /**
191 * Path to script, without sub path if TYPO3 is running in sub directory, without trailing slash
192 *
193 * - typo/index.php?id=42
194 * - index.php?id=42
195 *
196 * @var string
197 */
198 protected $siteScript = '';
199
200 /**
201 * Entry script path of URI, without domain and without query parameters, with leading /
202 * This is often not set at all.
203 * Will be deprecated later, use $scriptName instead as more reliable solution.
204 *
205 * [path_script]
206 *
207 * - /typo3/index.php
208 *
209 * @var string
210 */
211 protected $pathInfo = '';
212
213 /**
214 * HTTP_REFERER
215 * Will be deprecated later, use $request->getServerParams()['HTTP_REFERER'] instead
216 *
217 * scheme://host[:[port]][path]
218 *
219 * - https://www.domain.com/typo3/index.php?id=42
220 *
221 * @var string
222 */
223 protected $httpReferer = '';
224
225 /**
226 * HTTP_USER_AGENT
227 * Will be deprecated later, use $request->getServerParams()['HTTP_USER_AGENT'] instead
228 *
229 * - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36
230 *
231 * @var string
232 */
233 protected $httpUserAgent = '';
234
235 /**
236 * HTTP_ACCEPT_ENCODING
237 * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_ENCODING'] instead
238 *
239 * - gzip, deflate
240 *
241 * @var string
242 */
243 protected $httpAcceptEncoding = '';
244
245 /**
246 * HTTP_ACCEPT_LANGUAGE
247 * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] instead
248 *
249 * - de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
250 *
251 * @var string
252 */
253 protected $httpAcceptLanguage = '';
254
255 /**
256 * REMOTE_HOST Resolved host name of REMOTE_ADDR if configured in web server
257 * Will be deprecated later, use $request->getServerParams()['REMOTE_HOST'] instead
258 *
259 * - www.clientDomain.com
260 *
261 * @var string
262 */
263 protected $remoteHost = '';
264
265 /**
266 * QUERY_STRING
267 * Will be deprecated later, use $request->getServerParams()['QUERY_STRING'] instead
268 *
269 * [query]
270 *
271 * - id=42&foo=bar
272 *
273 * @var string
274 */
275 protected $queryString = '';
276
277 /**
278 * Constructor calculates all values by incoming variables.
279 *
280 * This object is immutable.
281 *
282 * All determine*() "detail worker methods" in this class retrieve their dependencies
283 * to other properties as method arguments, they are static, stateless and have no
284 * dependency to $this. This ensures the chain of inter-property dependencies
285 * is visible by only looking at the construct() method.
286 *
287 * @param array $serverParams, usually coming from $_SERVER or $request->getServerParams()
288 * @param array $configuration $GLOBALS['TYPO3_CONF_VARS']['SYS']
289 * @param string $pathThisScript Absolute server entry script path, usually found within Environment::getCurrentScript()
290 * @param string $pathSite Absolute server path to document root, Environment::getPublicPath()
291 */
292 public function __construct(array $serverParams, array $configuration, string $pathThisScript, string $pathSite)
293 {
294 $isBehindReverseProxy = $this->isBehindReverseProxy = self::determineIsBehindReverseProxy($serverParams, $configuration);
295 $httpHost = $this->httpHost = self::determineHttpHost($serverParams, $configuration, $isBehindReverseProxy);
296 $isHttps = $this->isHttps = self::determineHttps($serverParams, $configuration);
297 $requestHost = $this->requestHost = ($isHttps ? 'https://' : 'http://') . $httpHost;
298 $requestHostOnly = $this->requestHostOnly = self::determineRequestHostOnly($httpHost);
299 $this->requestPort = self::determineRequestPort($httpHost, $requestHostOnly);
300 $scriptName = $this->scriptName = self::determineScriptName($serverParams, $configuration, $isHttps, $isBehindReverseProxy);
301 $requestUri = $this->requestUri = self::determineRequestUri($serverParams, $configuration, $isHttps, $scriptName, $isBehindReverseProxy);
302 $requestUrl = $this->requestUrl = $requestHost . $requestUri;
303 $this->requestScript = $requestHost . $scriptName;
304 $requestDir = $this->requestDir = $requestHost . GeneralUtility::dirname($scriptName) . '/';
305 $this->remoteAddress = self::determineRemoteAddress($serverParams, $configuration, $isBehindReverseProxy);
306 $scriptFilename = $this->scriptFilename = $pathThisScript;
307 $this->documentRoot = self::determineDocumentRoot($scriptName, $scriptFilename);
308 $siteUrl = $this->siteUrl = self::determineSiteUrl($requestDir, $pathThisScript, $pathSite . '/');
309 $this->sitePath = self::determineSitePath($requestHost, $siteUrl);
310 $this->siteScript = self::determineSiteScript($requestUrl, $siteUrl);
311
312 // @deprecated Below variables can be fully deprecated as soon as core does not use them anymore
313 $this->pathInfo = $serverParams['PATH_INFO'] ?? '';
314 $this->httpReferer = $serverParams['HTTP_REFERER'] ?? '';
315 $this->httpUserAgent = $serverParams['HTTP_USER_AGENT'] ?? '';
316 $this->httpAcceptEncoding = $serverParams['HTTP_ACCEPT_ENCODING'] ?? '';
317 $this->httpAcceptLanguage = $serverParams['HTTP_ACCEPT_LANGUAGE'] ?? '';
318 $this->remoteHost = $serverParams['REMOTE_HOST'] ?? '';
319 $this->queryString = $serverParams['QUERY_STRING'] ?? '';
320 }
321
322 /**
323 * @return string Sanitized HTTP_HOST value host[:port]
324 */
325 public function getHttpHost(): string
326 {
327 return $this->httpHost;
328 }
329
330 /**
331 * @return bool True if client request has been done using HTTPS
332 */
333 public function isHttps(): bool
334 {
335 return $this->isHttps;
336 }
337
338 /**
339 * @return string Sanitized HTTP_HOST with protocol scheme://host[:port], eg. https://www.domain.com/
340 */
341 public function getRequestHost(): string
342 {
343 return $this->requestHost;
344 }
345
346 /**
347 * @return string Host / domain /IP only, eg. www.domain.com
348 */
349 public function getRequestHostOnly(): string
350 {
351 return $this->requestHostOnly;
352 }
353
354 /**
355 * @return int Requested port if given, eg. 8080 - often not explicitly given, then 0
356 */
357 public function getRequestPort(): int
358 {
359 return $this->requestPort;
360 }
361
362 /**
363 * @return string Script path part of URI, eg. 'typo3/index.php'
364 */
365 public function getScriptName(): string
366 {
367 return $this->scriptName;
368 }
369
370 /**
371 * @return string Request Uri without domain and protocol, eg. /index.php?id=42
372 */
373 public function getRequestUri(): string
374 {
375 return $this->requestUri;
376 }
377
378 /**
379 * @return string Full REQUEST_URI, eg. http://www.domain.com/typo3/index.php?route=foo/bar&id=42
380 */
381 public function getRequestUrl(): string
382 {
383 return $this->requestUrl;
384 }
385
386 /**
387 * @return string REQUEST URI without query part, eg. http://www.domain.com/typo3/index.php
388 */
389 public function getRequestScript(): string
390 {
391 return $this->requestScript;
392 }
393
394 /**
395 * @return string REQUEST URI without script file name and query parts, eg. http://www.domain.com/typo3/
396 */
397 public function getRequestDir(): string
398 {
399 return $this->requestDir;
400 }
401
402 /**
403 * @return bool True if request comes from a configured reverse proxy
404 */
405 public function isBehindReverseProxy(): bool
406 {
407 return $this->isBehindReverseProxy;
408 }
409
410 /**
411 * @return string Client IP
412 */
413 public function getRemoteAddress(): string
414 {
415 return $this->remoteAddress;
416 }
417
418 /**
419 * @return string Absolute entry script path on server, eg. /var/www/typo3/index.php
420 */
421 public function getScriptFilename(): string
422 {
423 return $this->scriptFilename;
424 }
425
426 /**
427 * @return string Absolute path to web document root, eg. /var/www/typo3
428 */
429 public function getDocumentRoot(): string
430 {
431 return $this->documentRoot;
432 }
433
434 /**
435 * @return string Website frontend url, eg. https://www.domain.com/some/sub/dir/
436 */
437 public function getSiteUrl(): string
438 {
439 return $this->siteUrl;
440 }
441
442 /**
443 * @return string Path part to frontend, eg. /some/sub/dir/
444 */
445 public function getSitePath(): string
446 {
447 return $this->sitePath;
448 }
449
450 /**
451 * @return string Path part to entry script with parameters, without sub dir, eg 'typo3/index.php?id=42'
452 */
453 public function getSiteScript(): string
454 {
455 return $this->siteScript;
456 }
457
458 /**
459 * Will be deprecated later, use getScriptName() as reliable solution instead
460 *
461 * @return string Script path part of URI, eg. 'typo3/index.php'
462 */
463 public function getPathInfo(): string
464 {
465 return $this->pathInfo;
466 }
467
468 /**
469 * Will be deprecated later, use $request->getServerParams()['HTTP_REFERER'] instead
470 *
471 * @return string HTTP_REFERER, eg. 'https://www.domain.com/typo3/index.php?id=42'
472 */
473 public function getHttpReferer(): string
474 {
475 return $this->httpReferer;
476 }
477
478 /**
479 * Will be deprecated later, use $request->getServerParams()['HTTP_USER_AGENT'] instead
480 *
481 * @return string HTTP_USER_AGENT identifier
482 */
483 public function getHttpUserAgent(): string
484 {
485 return $this->httpUserAgent;
486 }
487
488 /**
489 * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_ENCODING'] instead
490 *
491 * @return string HTTP_ACCEPT_ENCODING, eg. 'gzip, deflate'
492 */
493 public function getHttpAcceptEncoding(): string
494 {
495 return $this->httpAcceptEncoding;
496 }
497
498 /**
499 * Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] instead
500 *
501 * @return string HTTP_ACCEPT_LANGUAGE, eg. 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7'
502 */
503 public function getHttpAcceptLanguage(): string
504 {
505 return $this->httpAcceptLanguage;
506 }
507
508 /**
509 * Will be deprecated later, use $request->getServerParams()['REMOTE_HOST'] instead
510 *
511 * @return string REMOTE_HOST if configured in web server, eg. 'www.clientDomain.com'
512 */
513 public function getRemoteHost(): string
514 {
515 return $this->remoteHost;
516 }
517
518 /**
519 * Will be deprecated later, use $request->getServerParams()['QUERY_STRING'] instead
520 *
521 * @return string QUERY_STRING, eg 'id=42&foo=bar'
522 */
523 public function getQueryString(): string
524 {
525 return $this->queryString;
526 }
527
528 /**
529 * Sanitize HTTP_HOST, take proxy configuration into account and
530 * verify allowed hosts with configured trusted hosts pattern.
531 *
532 * @param array $serverParams Basically the $_SERVER, but from $request object
533 * @param array $configuration $TYPO3_CONF_VARS['SYS'] array
534 * @param bool $isBehindReverseProxy True if reverse proxy setup is detected
535 * @return string Sanitized HTTP_HOST
536 */
537 protected static function determineHttpHost(array $serverParams, array $configuration, bool $isBehindReverseProxy): string
538 {
539 $httpHost = $serverParams['HTTP_HOST'] ?? '';
540 if ($isBehindReverseProxy) {
541 // If the request comes from a configured proxy which has set HTTP_X_FORWARDED_HOST, then
542 // evaluate reverseProxyHeaderMultiValue and
543 $xForwardedHostArray = GeneralUtility::trimExplode(',', $serverParams['HTTP_X_FORWARDED_HOST'] ?? '', true);
544 $xForwardedHost = '';
545 // Choose which host in list to use
546 if (!empty($xForwardedHostArray)) {
547 $configuredReverseProxyHeaderMultiValue = trim($configuration['reverseProxyHeaderMultiValue'] ?? '');
548 // Default if reverseProxyHeaderMultiValue is not set or set to 'none', instead of 'first' / 'last' is to
549 // ignore $serverParams['HTTP_X_FORWARDED_HOST']
550 // @todo: Maybe this default is stupid: Both SYS/reverseProxyIP hand SYS/reverseProxyHeaderMultiValue have to
551 // @todo: be configured for a working setup. It would be easier to only configure SYS/reverseProxyIP and fall
552 // @todo: back to "first" if SYS/reverseProxyHeaderMultiValue is not set.
553 if ($configuredReverseProxyHeaderMultiValue === 'last') {
554 $xForwardedHost = array_pop($xForwardedHostArray);
555 } elseif ($configuredReverseProxyHeaderMultiValue === 'first') {
556 $xForwardedHost = array_shift($xForwardedHostArray);
557 }
558 }
559 if ($xForwardedHost) {
560 $httpHost = $xForwardedHost;
561 }
562 }
563 if (!GeneralUtility::isAllowedHostHeaderValue($httpHost)) {
564 throw new \UnexpectedValueException(
565 'The current host header value does not match the configured trusted hosts pattern!'
566 . ' Check the pattern defined in $GLOBALS[\'TYPO3_CONF_VARS\'][\'SYS\'][\'trustedHostsPattern\']'
567 . ' and adapt it, if you want to allow the current host header \'' . $httpHost . '\' for your installation.',
568 1396795886
569 );
570 }
571 return $httpHost;
572 }
573
574 /**
575 * Determine if the client called via HTTPS. Takes proxy ssl terminator
576 * configurations into account.
577 *
578 * @param array $serverParams Basically the $_SERVER, but from $request object
579 * @param array $configuration $TYPO3_CONF_VARS['SYS'] array
580 * @return bool True if request has been done via HTTPS
581 */
582 protected static function determineHttps(array $serverParams, array $configuration): bool
583 {
584 $isHttps = false;
585 $configuredProxySSL = trim($configuration['reverseProxySSL'] ?? '');
586 if ($configuredProxySSL === '*') {
587 $configuredProxySSL = trim($configuration['reverseProxyIP'] ?? '');
588 }
589 $httpsParam = (string)($serverParams['HTTPS'] ?? '');
590 if (GeneralUtility::cmpIP(trim($serverParams['REMOTE_ADDR'] ?? ''), $configuredProxySSL)
591 || ($serverParams['SSL_SESSION_ID'] ?? '')
592 // https://secure.php.net/manual/en/reserved.variables.server.php
593 // "Set to a non-empty value if the script was queried through the HTTPS protocol."
594 || ($httpsParam !== '' && $httpsParam !== 'off' && $httpsParam !== '0')
595 ) {
596 $isHttps = true;
597 }
598 return $isHttps;
599 }
600
601 /**
602 * Determine script name and path
603 *
604 * @param array $serverParams Basically the $_SERVER, but from $request object
605 * @param array $configuration TYPO3_CONF_VARS['SYS'] array
606 * @param bool $isHttps True if used protocol is HTTPS
607 * @param bool $isBehindReverseProxy True if reverse proxy setup is detected
608 * @return string Sanitized script name
609 */
610 protected static function determineScriptName(array $serverParams, array $configuration, bool $isHttps, bool $isBehindReverseProxy): string
611 {
612 $scriptName = $serverParams['ORIG_PATH_INFO'] ??
613 $serverParams['PATH_INFO'] ??
614 $serverParams['ORIG_SCRIPT_NAME'] ??
615 $serverParams['SCRIPT_NAME'] ??
616 '';
617 if ($isBehindReverseProxy) {
618 // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
619 if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) {
620 $scriptName = $configuration['reverseProxyPrefixSSL'] . $scriptName;
621 } elseif (!empty($configuration['reverseProxyPrefix'])) {
622 $scriptName = $configuration['reverseProxyPrefix'] . $scriptName;
623 }
624 }
625 return $scriptName;
626 }
627
628 /**
629 * Determine REQUEST_URI, taking proxy configuration and various web server
630 * specifics into account.
631 *
632 * @param array $serverParams Basically the $_SERVER, but from $request object
633 * @param array $configuration $TYPO3_CONF_VARS['SYS'] array
634 * @param bool $isHttps True if used protocol is HTTPS
635 * @param string $scriptName Script name
636 * @param bool $isBehindReverseProxy True if reverse proxy setup is detected
637 * @return string Sanitized REQUEST_URI
638 */
639 protected static function determineRequestUri(array $serverParams, array $configuration, bool $isHttps, string $scriptName, bool $isBehindReverseProxy): string
640 {
641 $proxyPrefixApplied = false;
642 if (!empty($configuration['requestURIvar'])) {
643 // This is for URL rewriter that store the original URI in a server
644 // variable (e.g. ISAPI Rewriter for IIS: HTTP_X_REWRITE_URL), a config then looks like:
645 // requestURIvar = '_SERVER|HTTP_X_REWRITE_URL' which will access $GLOBALS['_SERVER']['HTTP_X_REWRITE_URL']
646 list($firstLevel, $secondLevel) = GeneralUtility::trimExplode('|', $configuration['requestURIvar'], true);
647 $requestUri = $GLOBALS[$firstLevel][$secondLevel];
648 } elseif (empty($serverParams['REQUEST_URI'])) {
649 // This is for ISS/CGI which does not have the REQUEST_URI available.
650 $queryString = !empty($serverParams['QUERY_STRING']) ? '?' . $serverParams['QUERY_STRING'] : '';
651 // script name already had the proxy prefix handling, we must not add it a second time
652 $proxyPrefixApplied = true;
653 $requestUri = '/' . ltrim($scriptName, '/') . $queryString;
654 } else {
655 $requestUri = '/' . ltrim($serverParams['REQUEST_URI'], '/');
656 }
657 if (!$proxyPrefixApplied && $isBehindReverseProxy) {
658 // Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
659 if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) {
660 $requestUri = $configuration['reverseProxyPrefixSSL'] . $requestUri;
661 } elseif (!empty($configuration['reverseProxyPrefix'])) {
662 $requestUri = $configuration['reverseProxyPrefix'] . $requestUri;
663 }
664 }
665 return $requestUri;
666 }
667
668 /**
669 * Determine clients REMOTE_ADDR, even if there is a reverse proxy in between.
670 *
671 * @param array $serverParams Basically the $_SERVER, but from $request object
672 * @param array $configuration $TYPO3_CONF_VARS[SYS] array
673 * @param bool $isBehindReverseProxy True if reverse proxy setup is detected
674 * @return string Resolved REMOTE_ADDR
675 */
676 protected static function determineRemoteAddress(array $serverParams, array $configuration, bool $isBehindReverseProxy): string
677 {
678 $remoteAddress = trim($serverParams['REMOTE_ADDR'] ?? '');
679 if ($isBehindReverseProxy) {
680 $ip = GeneralUtility::trimExplode(',', $serverParams['HTTP_X_FORWARDED_FOR'] ?? '', true);
681 // Choose which IP in list to use
682 $configuredReverseProxyHeaderMultiValue = trim($configuration['reverseProxyHeaderMultiValue'] ?? '');
683 if (!empty($ip) && $configuredReverseProxyHeaderMultiValue === 'last') {
684 $ip = array_pop($ip);
685 } elseif (!empty($ip) && $configuredReverseProxyHeaderMultiValue === 'first') {
686 $ip = array_shift($ip);
687 } else {
688 $ip = '';
689 }
690 if (GeneralUtility::validIP($ip)) {
691 $remoteAddress = $ip;
692 }
693 }
694 return $remoteAddress;
695 }
696
697 /**
698 * Check if a configured reverse proxy setup is detected.
699 *
700 * @param array $serverParams Basically the $_SERVER, but from $request object
701 * @param array $configuration $TYPO3_CONF_VARS[SYS] array
702 * @return bool True if TYPO3 is behind a reverse proxy
703 */
704 protected static function determineIsBehindReverseProxy($serverParams, $configuration): bool
705 {
706 return GeneralUtility::cmpIP(trim($serverParams['REMOTE_ADDR'] ?? ''), trim($configuration['reverseProxyIP'] ?? ''));
707 }
708
709 /**
710 * HTTP_HOST without port
711 *
712 * @param string $httpHost host[:[port]]
713 * @return string Resolved host
714 */
715 protected static function determineRequestHostOnly(string $httpHost): string
716 {
717 $httpHostBracketPosition = strpos($httpHost, ']');
718 $httpHostParts = explode(':', $httpHost);
719 return $httpHostBracketPosition !== false ? substr($httpHost, 0, $httpHostBracketPosition + 1) : array_shift($httpHostParts);
720 }
721
722 /**
723 * Requested port if given
724 *
725 * @param string $httpHost host[:[port]]
726 * @param string $httpHostOnly host
727 * @return int Resolved port if given, else 0
728 */
729 protected static function determineRequestPort(string $httpHost, string $httpHostOnly): int
730 {
731 return strlen($httpHost) > strlen($httpHostOnly) ? (int)substr($httpHost, strlen($httpHostOnly) + 1) : 0;
732 }
733
734 /**
735 * Calculate absolute path to web document root
736 *
737 * @param string $scriptName Entry script path of URI, without domain and without query parameters, with leading /
738 * @param string $scriptFilename Absolute path to entry script on server filesystem
739 * @return string Path to document root with trailing slash
740 */
741 protected static function determineDocumentRoot(string $scriptName, string $scriptFilename): string
742 {
743 // Get the web root (it is not the root of the TYPO3 installation)
744 // Some CGI-versions (LA13CGI) and mod-rewrite rules on MODULE versions will deliver a 'wrong'
745 // DOCUMENT_ROOT (according to our description). Further various aliases/mod_rewrite rules can
746 // disturb this as well. Therefore the DOCUMENT_ROOT is always calculated as the SCRIPT_FILENAME
747 // minus the end part shared with SCRIPT_NAME.
748 $webDocRoot = '';
749 $scriptNameArray = explode('/', strrev($scriptName));
750 $scriptFilenameArray = explode('/', strrev($scriptFilename));
751 $path = [];
752 foreach ($scriptNameArray as $segmentNumber => $segment) {
753 if ((string)$scriptFilenameArray[$segmentNumber] === (string)$segment) {
754 $path[] = $segment;
755 } else {
756 break;
757 }
758 }
759 $commonEnd = strrev(implode('/', $path));
760 if ((string)$commonEnd !== '') {
761 $webDocRoot = substr($scriptFilename, 0, -(strlen($commonEnd) + 1));
762 }
763 return $webDocRoot;
764 }
765
766 /**
767 * Determine frontend url
768 *
769 * @param string $requestDir Full Uri with path, but without script name and query parts
770 * @param string $pathThisScript Absolute path to entry script on server filesystem
771 * @param string $pathSite Absolute server path to document root
772 * @return string Calculated Frontend Url
773 */
774 protected static function determineSiteUrl(string $requestDir, string $pathThisScript, string $pathSite): string
775 {
776 if (defined('TYPO3_PATH_WEB')) {
777 // This can only be set by external entry scripts
778 $siteUrl = $requestDir;
779 } else {
780 $pathThisScriptDir = substr(dirname($pathThisScript), strlen($pathSite)) . '/';
781 $siteUrl = substr($requestDir, 0, -strlen($pathThisScriptDir));
782 $siteUrl = rtrim($siteUrl, '/') . '/';
783 }
784 return $siteUrl;
785 }
786
787 /**
788 * Determine site path
789 *
790 * @param string $requestHost scheme://host[:port]
791 * @param string $siteUrl Full Frontend Url
792 * @return string
793 */
794 protected static function determineSitePath(string $requestHost, string $siteUrl): string
795 {
796 return (string)substr($siteUrl, strlen($requestHost));
797 }
798
799 /**
800 * Determine site script
801 *
802 * @param string $requestUrl
803 * @param string $siteUrl
804 * @return string
805 */
806 protected static function determineSiteScript(string $requestUrl, string $siteUrl): string
807 {
808 return substr($requestUrl, strlen($siteUrl));
809 }
810 }