TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,835 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\Http;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* This class provides normalized server parameters in HTTP request context.
|
||||
* It normalizes reverse proxy scenarios and various other web server specific differences
|
||||
* of the native PSR-7 request object parameters (->getServerParams() / $GLOBALS['_SERVER']).
|
||||
*
|
||||
* An instance of this class is available as PSR-7 ServerRequestInterface attribute:
|
||||
*
|
||||
* ```
|
||||
* $normalizedParams = $request->getAttribute('normalizedParams')
|
||||
* ```
|
||||
*/
|
||||
class NormalizedParams
|
||||
{
|
||||
/**
|
||||
* Sanitized HTTP_HOST value
|
||||
*
|
||||
* host[:port]
|
||||
*
|
||||
* - www.domain.com
|
||||
* - www.domain.com:443
|
||||
* - 192.168.1.42:80
|
||||
*/
|
||||
protected string $httpHost = '';
|
||||
|
||||
/**
|
||||
* True if request has been done via HTTPS
|
||||
*/
|
||||
protected bool $isHttps = false;
|
||||
|
||||
/**
|
||||
* Sanitized HTTP_HOST with protocol
|
||||
*
|
||||
* scheme://host[:port]
|
||||
*
|
||||
* - https://www.domain.com
|
||||
*/
|
||||
protected string $requestHost = '';
|
||||
|
||||
/**
|
||||
* Host / domain part of HTTP_HOST, no port, no protocol
|
||||
*
|
||||
* - www.domain.com
|
||||
* - 192.168.1.42
|
||||
*/
|
||||
protected string $requestHostOnly = '';
|
||||
|
||||
/**
|
||||
* Port of HTTP_HOST if given
|
||||
*/
|
||||
protected int $requestPort = 0;
|
||||
|
||||
/**
|
||||
* Entry script path of URI, without domain and without query parameters, with leading /
|
||||
*
|
||||
* [path_script]
|
||||
*
|
||||
* - /index.php
|
||||
* - /typo3/index.php
|
||||
*/
|
||||
protected string $scriptName = '';
|
||||
|
||||
/**
|
||||
* REQUEST URI without domain and scheme, with trailing slash
|
||||
*
|
||||
* [path][?[query]]
|
||||
*
|
||||
* - /some/path?p1=parameter1&p2[key]=value
|
||||
* - /typo3/some/path?p1=parameter1&p2[key]=value
|
||||
*/
|
||||
protected string $requestUri = '';
|
||||
|
||||
/**
|
||||
* REQUEST URI with scheme, host, port, path and query
|
||||
*
|
||||
* scheme://host[:[port]][path][?[query]]
|
||||
*
|
||||
* - http://www.domain.com/some/path?p1=parameter1&p2[key]=value
|
||||
* - http://www.domain.com/typo3/some/path?id=42
|
||||
*/
|
||||
protected string $requestUrl = '';
|
||||
|
||||
/**
|
||||
* REQUEST URI with scheme, host, port and path, but *without* query part
|
||||
*
|
||||
* scheme://host[:[port]][path_script]
|
||||
*
|
||||
* - http://www.domain.com/index.php
|
||||
* - http://www.domain.com/typo3/index.php
|
||||
*/
|
||||
protected string $requestScript = '';
|
||||
|
||||
/**
|
||||
* Full Uri with path, but without script name and query parts
|
||||
*
|
||||
* scheme://host[:[port]][path_dir]
|
||||
*
|
||||
* - http://www.domain.com/
|
||||
* - http://www.domain.com/typo3/
|
||||
*/
|
||||
protected string $requestDir = '';
|
||||
|
||||
/**
|
||||
* True if request via a reverse proxy is detected
|
||||
*/
|
||||
protected bool $isBehindReverseProxy = false;
|
||||
|
||||
/**
|
||||
* IPv4 or IPv6 address of remote client with resolved proxy setup
|
||||
*/
|
||||
protected string $remoteAddress = '';
|
||||
|
||||
/**
|
||||
* Absolute server path to entry script on server filesystem
|
||||
*
|
||||
* - /var/www/index.php
|
||||
* - /var/www/typo3/index.php
|
||||
*/
|
||||
protected string $scriptFilename = '';
|
||||
|
||||
/**
|
||||
* Absolute server path to web document root without trailing slash
|
||||
*
|
||||
* - /var/www
|
||||
*/
|
||||
protected string $documentRoot = '';
|
||||
|
||||
/**
|
||||
* Website frontend URL.
|
||||
* Note this is note "safe" if called from Backend since sys_domain and
|
||||
* other factors are not taken into account.
|
||||
*
|
||||
* scheme://host[:[port]]/[path_dir]
|
||||
*
|
||||
* - https://www.domain.com/
|
||||
* - https://www.domain.com/some/sub/dir/
|
||||
*/
|
||||
protected string $siteUrl = '';
|
||||
|
||||
/**
|
||||
* Path part to frontend, no domain, no protocol
|
||||
*
|
||||
* - /
|
||||
* - /some/sub/dir/
|
||||
*/
|
||||
protected string $sitePath = '';
|
||||
|
||||
/**
|
||||
* Path to script, without sub path if TYPO3 is running in sub directory, without trailing slash
|
||||
*
|
||||
* - index.php?id=42
|
||||
* - /some/path?id=42
|
||||
* - typo3/some/path?id=411
|
||||
*/
|
||||
protected string $siteScript = '';
|
||||
|
||||
/**
|
||||
* Entry script path of URI, without domain and without query parameters, with leading /
|
||||
* This is often not set at all.
|
||||
* Will be deprecated later, use $scriptName instead as more reliable solution.
|
||||
*
|
||||
* [path_script]
|
||||
*/
|
||||
protected string $pathInfo = '';
|
||||
|
||||
/**
|
||||
* HTTP_REFERER
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_REFERER'] instead
|
||||
*
|
||||
* scheme://host[:[port]][path]
|
||||
*
|
||||
* - https://www.domain.com/typo3/module/web/layout?id=42
|
||||
*/
|
||||
protected string $httpReferer = '';
|
||||
|
||||
/**
|
||||
* HTTP_USER_AGENT
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_USER_AGENT'] instead
|
||||
*
|
||||
* - Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36
|
||||
*/
|
||||
protected string $httpUserAgent = '';
|
||||
|
||||
/**
|
||||
* HTTP_ACCEPT_ENCODING
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_ENCODING'] instead
|
||||
*
|
||||
* - gzip, deflate
|
||||
*/
|
||||
protected string $httpAcceptEncoding = '';
|
||||
|
||||
/**
|
||||
* HTTP_ACCEPT_LANGUAGE
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] instead
|
||||
*
|
||||
* - de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
|
||||
*/
|
||||
protected string $httpAcceptLanguage = '';
|
||||
|
||||
/**
|
||||
* REMOTE_HOST Resolved host name of REMOTE_ADDR if configured in web server
|
||||
* Will be deprecated later, use $request->getServerParams()['REMOTE_HOST'] instead
|
||||
*
|
||||
* - www.clientDomain.com
|
||||
*/
|
||||
protected string $remoteHost = '';
|
||||
|
||||
/**
|
||||
* QUERY_STRING
|
||||
* Will be deprecated later, use $request->getServerParams()['QUERY_STRING'] instead
|
||||
*
|
||||
* [query]
|
||||
*
|
||||
* - id=42&foo=bar
|
||||
*/
|
||||
protected string $queryString = '';
|
||||
|
||||
/**
|
||||
* Constructor calculates all values by incoming variables.
|
||||
*
|
||||
* This object is immutable.
|
||||
*
|
||||
* All determine*() "detail worker methods" in this class retrieve their dependencies
|
||||
* to other properties as method arguments, they are static, stateless and have no
|
||||
* dependency to $this. This ensures the chain of inter-property dependencies
|
||||
* is visible by only looking at the construct() method.
|
||||
*
|
||||
* @param array $serverParams , usually coming from $_SERVER or $request->getServerParams()
|
||||
* @param array $configuration $GLOBALS['TYPO3_CONF_VARS']['SYS']
|
||||
* @param string $pathThisScript Absolute server entry script path, usually found within Environment::getCurrentScript()
|
||||
* @param string $pathSite Absolute server path to document root, Environment::getPublicPath()
|
||||
*/
|
||||
public function __construct(array $serverParams, array $configuration, string $pathThisScript, string $pathSite)
|
||||
{
|
||||
$isBehindReverseProxy = $this->isBehindReverseProxy = self::determineIsBehindReverseProxy(
|
||||
$serverParams,
|
||||
$configuration
|
||||
);
|
||||
$httpHost = $this->httpHost = self::determineHttpHost($serverParams, $configuration, $isBehindReverseProxy);
|
||||
$isHttps = $this->isHttps = self::determineHttps($serverParams, $configuration);
|
||||
$requestHost = $this->requestHost = ($isHttps ? 'https://' : 'http://') . $httpHost;
|
||||
$requestHostOnly = $this->requestHostOnly = self::determineRequestHostOnly($httpHost);
|
||||
$this->requestPort = self::determineRequestPort($httpHost, $requestHostOnly);
|
||||
$scriptNameOnFileSystem = self::determineScriptName(
|
||||
$serverParams,
|
||||
$configuration,
|
||||
$isHttps,
|
||||
$isBehindReverseProxy
|
||||
);
|
||||
$scriptName = $this->scriptName = self::encodeFileSystemPathComponentForUrlPath($scriptNameOnFileSystem);
|
||||
$requestUri = $this->requestUri = self::determineRequestUri(
|
||||
$serverParams,
|
||||
$configuration,
|
||||
$isHttps,
|
||||
$scriptName,
|
||||
$isBehindReverseProxy
|
||||
);
|
||||
$requestUrl = $this->requestUrl = $requestHost . $requestUri;
|
||||
$this->requestScript = $requestHost . $scriptName;
|
||||
$requestDir = $this->requestDir = $requestHost . GeneralUtility::dirname($scriptName) . '/';
|
||||
$this->remoteAddress = self::determineRemoteAddress($serverParams, $configuration, $isBehindReverseProxy);
|
||||
$scriptFilename = $this->scriptFilename = $pathThisScript;
|
||||
$this->documentRoot = self::determineDocumentRoot($scriptNameOnFileSystem, $scriptFilename);
|
||||
$siteUrl = $this->siteUrl = self::determineSiteUrl($requestDir, $pathThisScript, $pathSite . '/');
|
||||
$this->sitePath = self::determineSitePath($requestHost, $siteUrl);
|
||||
$this->siteScript = self::determineSiteScript($requestUrl, $siteUrl);
|
||||
|
||||
// @deprecated Below variables can be fully deprecated as soon as core does not use them anymore
|
||||
$this->pathInfo = $serverParams['PATH_INFO'] ?? '';
|
||||
$this->httpReferer = $serverParams['HTTP_REFERER'] ?? '';
|
||||
$this->httpUserAgent = $serverParams['HTTP_USER_AGENT'] ?? '';
|
||||
$this->httpAcceptEncoding = $serverParams['HTTP_ACCEPT_ENCODING'] ?? '';
|
||||
$this->httpAcceptLanguage = $serverParams['HTTP_ACCEPT_LANGUAGE'] ?? '';
|
||||
$this->remoteHost = $serverParams['REMOTE_HOST'] ?? '';
|
||||
$this->queryString = $serverParams['QUERY_STRING'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method, to allow TYPO3 to handle configuration options directly.
|
||||
*
|
||||
* @param array $serverParams - could be fulfilled by $_SERVER (on web requests)
|
||||
* @internal framework method. Not part of TYPO3 API.
|
||||
*/
|
||||
public static function createFromServerParams(array $serverParams, ?array $systemConfiguration = null): self
|
||||
{
|
||||
return new NormalizedParams(
|
||||
$serverParams,
|
||||
$systemConfiguration ?? $GLOBALS['TYPO3_CONF_VARS']['SYS'],
|
||||
Environment::getCurrentScript(),
|
||||
Environment::getPublicPath()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating normalized params from a PSR-7 server request object
|
||||
*
|
||||
* @internal framework method. Not part of TYPO3 API.
|
||||
*/
|
||||
public static function createFromRequest(ServerRequestInterface $request, ?array $systemConfiguration = null): self
|
||||
{
|
||||
return static::createFromServerParams(
|
||||
$request->getServerParams(),
|
||||
$systemConfiguration ?? $GLOBALS['TYPO3_CONF_VARS']['SYS']
|
||||
);
|
||||
}
|
||||
|
||||
private static function encodeFileSystemPathComponentForUrlPath(string $path): string
|
||||
{
|
||||
return implode('/', array_map(rawurlencode(...), explode('/', $path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Sanitized HTTP_HOST value host[:port]
|
||||
*/
|
||||
public function getHttpHost(): string
|
||||
{
|
||||
return $this->httpHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if client request has been done using HTTPS
|
||||
*/
|
||||
public function isHttps(): bool
|
||||
{
|
||||
return $this->isHttps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Sanitized HTTP_HOST with protocol scheme://host[:port], eg. https://www.domain.com/
|
||||
*/
|
||||
public function getRequestHost(): string
|
||||
{
|
||||
return $this->requestHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Host / domain /IP only, eg. www.domain.com
|
||||
*/
|
||||
public function getRequestHostOnly(): string
|
||||
{
|
||||
return $this->requestHostOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Requested port if given, eg. 8080 - often not explicitly given, then 0
|
||||
*/
|
||||
public function getRequestPort(): int
|
||||
{
|
||||
return $this->requestPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Script path part of URI, eg. '/typo3/index.php'
|
||||
*/
|
||||
public function getScriptName(): string
|
||||
{
|
||||
return $this->scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Request Uri without domain and protocol, eg. /index.php?id=42
|
||||
*/
|
||||
public function getRequestUri(): string
|
||||
{
|
||||
return $this->requestUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Full REQUEST_URI, eg. http://www.domain.com/typo3/foo/bar?id=42
|
||||
*/
|
||||
public function getRequestUrl(): string
|
||||
{
|
||||
return $this->requestUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string REQUEST URI without query part, eg. http://www.domain.com/typo3/index.php
|
||||
*/
|
||||
public function getRequestScript(): string
|
||||
{
|
||||
return $this->requestScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string REQUEST URI without script file name and query parts, eg. http://www.domain.com/typo3/
|
||||
*/
|
||||
public function getRequestDir(): string
|
||||
{
|
||||
return $this->requestDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if request comes from a configured reverse proxy
|
||||
*/
|
||||
public function isBehindReverseProxy(): bool
|
||||
{
|
||||
return $this->isBehindReverseProxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Client IP
|
||||
*/
|
||||
public function getRemoteAddress(): string
|
||||
{
|
||||
return $this->remoteAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absolute entry script path on server, eg. /var/www/typo3/index.php
|
||||
*/
|
||||
public function getScriptFilename(): string
|
||||
{
|
||||
return $this->scriptFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Absolute path to web document root, eg. /var/www/typo3
|
||||
*/
|
||||
public function getDocumentRoot(): string
|
||||
{
|
||||
return $this->documentRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Website frontend url, eg. https://www.domain.com/some/sub/dir/
|
||||
*/
|
||||
public function getSiteUrl(): string
|
||||
{
|
||||
return $this->siteUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Path part to frontend, eg. /some/sub/dir/
|
||||
*/
|
||||
public function getSitePath(): string
|
||||
{
|
||||
return $this->sitePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Path part to entry script with parameters, without sub dir, eg 'typo3/index.php?id=42'
|
||||
*/
|
||||
public function getSiteScript(): string
|
||||
{
|
||||
return $this->siteScript;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use getScriptName() as reliable solution instead
|
||||
*
|
||||
* @return string Script path part of URI, eg. 'typo3/index.php'
|
||||
*/
|
||||
public function getPathInfo(): string
|
||||
{
|
||||
return $this->pathInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_REFERER'] instead
|
||||
*
|
||||
* @return string HTTP_REFERER, eg. 'https://www.domain.com/typo3/index.php?id=42'
|
||||
*/
|
||||
public function getHttpReferer(): string
|
||||
{
|
||||
return $this->httpReferer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_USER_AGENT'] instead
|
||||
*
|
||||
* @return string HTTP_USER_AGENT identifier
|
||||
*/
|
||||
public function getHttpUserAgent(): string
|
||||
{
|
||||
return $this->httpUserAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_ENCODING'] instead
|
||||
*
|
||||
* @return string HTTP_ACCEPT_ENCODING, eg. 'gzip, deflate'
|
||||
*/
|
||||
public function getHttpAcceptEncoding(): string
|
||||
{
|
||||
return $this->httpAcceptEncoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] instead
|
||||
*
|
||||
* @return string HTTP_ACCEPT_LANGUAGE, eg. 'de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7'
|
||||
*/
|
||||
public function getHttpAcceptLanguage(): string
|
||||
{
|
||||
return $this->httpAcceptLanguage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use $request->getServerParams()['REMOTE_HOST'] instead
|
||||
*
|
||||
* @return string REMOTE_HOST if configured in web server, eg. 'www.clientDomain.com'
|
||||
*/
|
||||
public function getRemoteHost(): string
|
||||
{
|
||||
return $this->remoteHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be deprecated later, use $request->getServerParams()['QUERY_STRING'] instead
|
||||
*
|
||||
* @return string QUERY_STRING, eg 'id=42&foo=bar'
|
||||
*/
|
||||
public function getQueryString(): string
|
||||
{
|
||||
return $this->queryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize HTTP_HOST by taking proxy configuration into account.
|
||||
*
|
||||
* @param array $serverParams Basically the $_SERVER, but from $request object
|
||||
* @param array $configuration $TYPO3_CONF_VARS['SYS'] array
|
||||
* @param bool $isBehindReverseProxy True if reverse proxy setup is detected
|
||||
* @return string Normalized HTTP_HOST
|
||||
*/
|
||||
protected static function determineHttpHost(
|
||||
array $serverParams,
|
||||
array $configuration,
|
||||
bool $isBehindReverseProxy
|
||||
): string {
|
||||
$httpHost = $serverParams['HTTP_HOST'] ?? '';
|
||||
if ($isBehindReverseProxy) {
|
||||
// If the request comes from a configured proxy which has set HTTP_X_FORWARDED_HOST, then
|
||||
// evaluate reverseProxyHeaderMultiValue and
|
||||
$xForwardedHostArray = GeneralUtility::trimExplode(',', $serverParams['HTTP_X_FORWARDED_HOST'] ?? '', true);
|
||||
$xForwardedHost = '';
|
||||
// Choose which host in list to use
|
||||
if (!empty($xForwardedHostArray)) {
|
||||
$configuredReverseProxyHeaderMultiValue = trim($configuration['reverseProxyHeaderMultiValue'] ?? '');
|
||||
// Default if reverseProxyHeaderMultiValue is not set or set to 'none', instead of 'first' / 'last' is to
|
||||
// ignore $serverParams['HTTP_X_FORWARDED_HOST']
|
||||
// @todo: Maybe this default is stupid: Both SYS/reverseProxyIP hand SYS/reverseProxyHeaderMultiValue have to
|
||||
// be configured for a working setup. It would be easier to only configure SYS/reverseProxyIP and fall
|
||||
// back to "first" if SYS/reverseProxyHeaderMultiValue is not set.
|
||||
if ($configuredReverseProxyHeaderMultiValue === 'last') {
|
||||
$xForwardedHost = array_pop($xForwardedHostArray);
|
||||
} elseif ($configuredReverseProxyHeaderMultiValue === 'first') {
|
||||
$xForwardedHost = array_shift($xForwardedHostArray);
|
||||
}
|
||||
}
|
||||
if ($xForwardedHost) {
|
||||
$httpHost = $xForwardedHost;
|
||||
}
|
||||
}
|
||||
return $httpHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the client called via HTTPS. Takes proxy ssl terminator
|
||||
* configurations into account.
|
||||
*
|
||||
* How does TYPO3 determine if the connection was established via TLS/SSL/https?
|
||||
* 1. If reverseProxySSL matches, then we now that Client -> Proxy is SSL,
|
||||
* and Proxy -> App Server is non-SSL. SSL Termination happens at Proxy at ALL times.
|
||||
* 2. If reverseProxyIP matches, and HTTP_X_FORWARDED_PROTO is set, it is evaluated
|
||||
* 3. If no other matches, see webserverUsesHttps()
|
||||
*
|
||||
* Note: HTTP_X_FORWARDED_PROTO is ONLY evaluated at the point, where we know
|
||||
* that the incoming REMOTE_ADDR is a trusted proxy!
|
||||
*
|
||||
* @param array $serverParams Basically the $_SERVER, but from $request object
|
||||
* @param array $configuration $TYPO3_CONF_VARS['SYS'] array
|
||||
* @return bool True if request has been done via HTTPS
|
||||
*/
|
||||
protected static function determineHttps(array $serverParams, array $configuration): bool
|
||||
{
|
||||
$configuredProxySSL = trim($configuration['reverseProxySSL'] ?? '');
|
||||
$configuredProxyRegular = trim($configuration['reverseProxyIP'] ?? '');
|
||||
|
||||
if ($configuredProxySSL === '*') {
|
||||
$configuredProxySSL = $configuredProxyRegular;
|
||||
}
|
||||
$httpsParam = (string)($serverParams['HTTPS'] ?? '');
|
||||
if (GeneralUtility::cmpIP($serverParams['REMOTE_ADDR'] ?? '', $configuredProxySSL)) {
|
||||
$isHttps = true;
|
||||
} elseif (isset($serverParams['HTTP_X_FORWARDED_PROTO'])
|
||||
&& GeneralUtility::cmpIP($serverParams['REMOTE_ADDR'] ?? '', $configuredProxyRegular)) {
|
||||
// If the X-Forwarded-Proto header is set, and we can trust the RemoteAddr to be a proxy, check it
|
||||
$isHttps = strtolower($serverParams['HTTP_X_FORWARDED_PROTO']) === 'https';
|
||||
} else {
|
||||
// https://secure.php.net/manual/en/reserved.variables.server.php
|
||||
// "Set to a non-empty value if the script was queried through the HTTPS protocol."
|
||||
$isHttps = ($serverParams['SSL_SESSION_ID'] ?? '')
|
||||
|| ($httpsParam !== '' && $httpsParam !== 'off' && $httpsParam !== '0');
|
||||
}
|
||||
return $isHttps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine script name and path
|
||||
*
|
||||
* @param array $serverParams Basically the $_SERVER, but from $request object
|
||||
* @param array $configuration TYPO3_CONF_VARS['SYS'] array
|
||||
* @param bool $isHttps True if used protocol is HTTPS
|
||||
* @param bool $isBehindReverseProxy True if reverse proxy setup is detected
|
||||
* @return string Sanitized script name
|
||||
*/
|
||||
protected static function determineScriptName(
|
||||
array $serverParams,
|
||||
array $configuration,
|
||||
bool $isHttps,
|
||||
bool $isBehindReverseProxy
|
||||
): string {
|
||||
$scriptName = $serverParams['SCRIPT_NAME'] ?? '';
|
||||
if ($isBehindReverseProxy) {
|
||||
// Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
|
||||
if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) {
|
||||
$scriptName = $configuration['reverseProxyPrefixSSL'] . $scriptName;
|
||||
} elseif (!empty($configuration['reverseProxyPrefix'])) {
|
||||
$scriptName = $configuration['reverseProxyPrefix'] . $scriptName;
|
||||
}
|
||||
}
|
||||
return $scriptName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine REQUEST_URI, taking proxy configuration and various web server
|
||||
* specifics into account.
|
||||
*
|
||||
* @param array $serverParams Basically the $_SERVER, but from $request object
|
||||
* @param array $configuration $TYPO3_CONF_VARS['SYS'] array
|
||||
* @param bool $isHttps True if used protocol is HTTPS
|
||||
* @param string $scriptName Script name
|
||||
* @param bool $isBehindReverseProxy True if reverse proxy setup is detected
|
||||
* @return string Sanitized REQUEST_URI
|
||||
*/
|
||||
protected static function determineRequestUri(
|
||||
array $serverParams,
|
||||
array $configuration,
|
||||
bool $isHttps,
|
||||
string $scriptName,
|
||||
bool $isBehindReverseProxy
|
||||
): string {
|
||||
$proxyPrefixApplied = false;
|
||||
if (!empty($configuration['requestURIvar'])) {
|
||||
// This is for URL rewriter that store the original URI in a server
|
||||
// variable (e.g. ISAPI Rewriter for IIS: HTTP_X_REWRITE_URL), a config then looks like:
|
||||
// requestURIvar = '_SERVER|HTTP_X_REWRITE_URL' which will access $GLOBALS['_SERVER']['HTTP_X_REWRITE_URL']
|
||||
[$firstLevel, $secondLevel] = GeneralUtility::trimExplode('|', $configuration['requestURIvar'], true);
|
||||
$requestUri = $GLOBALS[$firstLevel][$secondLevel];
|
||||
} elseif (empty($serverParams['REQUEST_URI'])) {
|
||||
// This is for ISS/CGI which does not have the REQUEST_URI available.
|
||||
$queryString = !empty($serverParams['QUERY_STRING']) ? '?' . $serverParams['QUERY_STRING'] : '';
|
||||
// script name already had the proxy prefix handling, we must not add it a second time
|
||||
$proxyPrefixApplied = true;
|
||||
$requestUri = '/' . ltrim($scriptName, '/') . $queryString;
|
||||
} else {
|
||||
$requestUri = '/' . ltrim($serverParams['REQUEST_URI'], '/');
|
||||
}
|
||||
if (!$proxyPrefixApplied && $isBehindReverseProxy) {
|
||||
// Add a prefix if TYPO3 is behind a proxy: ext-domain.com => int-server.com/prefix
|
||||
if ($isHttps && !empty($configuration['reverseProxyPrefixSSL'])) {
|
||||
$requestUri = $configuration['reverseProxyPrefixSSL'] . $requestUri;
|
||||
} elseif (!empty($configuration['reverseProxyPrefix'])) {
|
||||
$requestUri = $configuration['reverseProxyPrefix'] . $requestUri;
|
||||
}
|
||||
}
|
||||
return $requestUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine clients REMOTE_ADDR, even if there is a reverse proxy in between.
|
||||
*
|
||||
* @param array $serverParams Basically the $_SERVER, but from $request object
|
||||
* @param array $configuration $TYPO3_CONF_VARS[SYS] array
|
||||
* @param bool $isBehindReverseProxy True if reverse proxy setup is detected
|
||||
* @return string Resolved REMOTE_ADDR
|
||||
*/
|
||||
protected static function determineRemoteAddress(
|
||||
array $serverParams,
|
||||
array $configuration,
|
||||
bool $isBehindReverseProxy
|
||||
): string {
|
||||
$remoteAddress = trim($serverParams['REMOTE_ADDR'] ?? '');
|
||||
if ($isBehindReverseProxy) {
|
||||
$ip = GeneralUtility::trimExplode(',', $serverParams['HTTP_X_FORWARDED_FOR'] ?? '', true);
|
||||
// Choose which IP in list to use
|
||||
$configuredReverseProxyHeaderMultiValue = trim($configuration['reverseProxyHeaderMultiValue'] ?? '');
|
||||
if (!empty($ip) && $configuredReverseProxyHeaderMultiValue === 'last') {
|
||||
$ip = (string)array_pop($ip);
|
||||
} elseif (!empty($ip) && $configuredReverseProxyHeaderMultiValue === 'first') {
|
||||
$ip = (string)array_shift($ip);
|
||||
} else {
|
||||
$ip = '';
|
||||
}
|
||||
if (GeneralUtility::validIP($ip)) {
|
||||
$remoteAddress = $ip;
|
||||
}
|
||||
}
|
||||
return $remoteAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a configured reverse proxy setup is detected.
|
||||
*
|
||||
* @param array $serverParams Basically the $_SERVER, but from $request object
|
||||
* @param array $configuration $TYPO3_CONF_VARS[SYS] array
|
||||
* @return bool True if TYPO3 is behind a reverse proxy
|
||||
*/
|
||||
protected static function determineIsBehindReverseProxy($serverParams, $configuration): bool
|
||||
{
|
||||
return GeneralUtility::cmpIP(
|
||||
trim($serverParams['REMOTE_ADDR'] ?? ''),
|
||||
trim($configuration['reverseProxyIP'] ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP_HOST without port
|
||||
*
|
||||
* @param string $httpHost host[:[port]]
|
||||
* @return string Resolved host
|
||||
*/
|
||||
protected static function determineRequestHostOnly(string $httpHost): string
|
||||
{
|
||||
$httpHostBracketPosition = strpos($httpHost, ']');
|
||||
$httpHostParts = explode(':', $httpHost);
|
||||
return $httpHostBracketPosition !== false ? substr(
|
||||
$httpHost,
|
||||
0,
|
||||
$httpHostBracketPosition + 1
|
||||
) : array_shift($httpHostParts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requested port if given
|
||||
*
|
||||
* @param string $httpHost host[:[port]]
|
||||
* @param string $httpHostOnly host
|
||||
* @return int Resolved port if given, else 0
|
||||
*/
|
||||
protected static function determineRequestPort(string $httpHost, string $httpHostOnly): int
|
||||
{
|
||||
return strlen($httpHost) > strlen($httpHostOnly) ? (int)substr($httpHost, strlen($httpHostOnly) + 1) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate absolute path to web document root
|
||||
*
|
||||
* @param string $scriptNameOnFileSystem Entry script path of URI on file system, without domain and without query parameters, with leading /
|
||||
* @param string $scriptFilename Absolute path to entry script on server filesystem
|
||||
* @return string Path to document root with trailing slash
|
||||
*/
|
||||
protected static function determineDocumentRoot(string $scriptNameOnFileSystem, string $scriptFilename): string
|
||||
{
|
||||
// Get the web root (it is not the root of the TYPO3 installation)
|
||||
// Some CGI-versions (LA13CGI) and mod-rewrite rules on MODULE versions will deliver a 'wrong'
|
||||
// DOCUMENT_ROOT (according to our description). Further various aliases/mod_rewrite rules can
|
||||
// disturb this as well. Therefore the DOCUMENT_ROOT is always calculated as the SCRIPT_FILENAME
|
||||
// minus the end part shared with SCRIPT_NAME.
|
||||
$webDocRoot = '';
|
||||
$scriptNameArray = explode('/', strrev($scriptNameOnFileSystem));
|
||||
$scriptFilenameArray = explode('/', strrev($scriptFilename));
|
||||
$path = [];
|
||||
foreach ($scriptNameArray as $segmentNumber => $segment) {
|
||||
if ($scriptFilenameArray[$segmentNumber] === (string)$segment) {
|
||||
$path[] = $segment;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$commonEnd = strrev(implode('/', $path));
|
||||
if ($commonEnd !== '') {
|
||||
$webDocRoot = substr($scriptFilename, 0, -(strlen($commonEnd) + 1));
|
||||
}
|
||||
return $webDocRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine frontend url
|
||||
*
|
||||
* @param string $requestDir Full Uri with path, but without script name and query parts
|
||||
* @param string $pathThisScript Absolute path to entry script on server filesystem
|
||||
* @param string $pathSite Absolute server path to document root
|
||||
* @return string Calculated Frontend Url
|
||||
*/
|
||||
protected static function determineSiteUrl(string $requestDir, string $pathThisScript, string $pathSite): string
|
||||
{
|
||||
$pathThisScriptDir = substr(dirname($pathThisScript), strlen($pathSite)) . '/';
|
||||
$siteUrl = substr($requestDir, 0, -strlen($pathThisScriptDir));
|
||||
|
||||
return rtrim($siteUrl, '/') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine site path
|
||||
*
|
||||
* @param string $requestHost scheme://host[:port]
|
||||
* @param string $siteUrl Full Frontend Url
|
||||
*/
|
||||
protected static function determineSitePath(string $requestHost, string $siteUrl): string
|
||||
{
|
||||
return substr($siteUrl, strlen($requestHost));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine site script
|
||||
*/
|
||||
protected static function determineSiteScript(string $requestUrl, string $siteUrl): string
|
||||
{
|
||||
return substr($requestUrl, strlen($siteUrl));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user