chore: complete update
This commit is contained in:
184
src/Framework/Http/ServerEnvironment.php
Normal file
184
src/Framework/Http/ServerEnvironment.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Http;
|
||||
|
||||
/**
|
||||
* Kapselt Server-Environment-Daten aus $_SERVER
|
||||
*/
|
||||
final readonly class ServerEnvironment
|
||||
{
|
||||
public function __construct(
|
||||
private array $serverData = []
|
||||
) {}
|
||||
|
||||
public static function fromGlobals(): self
|
||||
{
|
||||
return new self($_SERVER);
|
||||
}
|
||||
|
||||
public function get(string|ServerKey $key, mixed $default = null): mixed
|
||||
{
|
||||
if($key instanceof ServerKey) {
|
||||
$key = $key->value;
|
||||
}
|
||||
|
||||
return $this->serverData[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function has(string|ServerKey $key): bool
|
||||
{
|
||||
!$key instanceof ServerKey ?: $key = $key->value;
|
||||
|
||||
return array_key_exists($key, $this->serverData);
|
||||
}
|
||||
|
||||
// Häufig verwendete Server-Informationen als typisierte Methoden
|
||||
public function getRemoteAddr(): IpAddress
|
||||
{
|
||||
$ip = $this->get(ServerKey::REMOTE_ADDR, '0.0.0.0');
|
||||
return new IpAddress($ip);
|
||||
}
|
||||
|
||||
public function getUserAgent(): string
|
||||
{
|
||||
return $this->get(ServerKey::HTTP_USER_AGENT, '');
|
||||
}
|
||||
|
||||
public function getServerName(): string
|
||||
{
|
||||
return $this->get(ServerKey::SERVER_NAME, '');
|
||||
}
|
||||
|
||||
public function getServerPort(): int
|
||||
{
|
||||
return (int) $this->get(ServerKey::SERVER_PORT, 80);
|
||||
}
|
||||
|
||||
public function getRequestUri(): Uri
|
||||
{
|
||||
$uriString = $this->get(ServerKey::REQUEST_URI, '/');
|
||||
return new Uri($uriString);
|
||||
}
|
||||
|
||||
public function getScriptName(): string
|
||||
{
|
||||
return $this->get(ServerKey::SCRIPT_NAME, '');
|
||||
}
|
||||
|
||||
public function getHttpHost(): string
|
||||
{
|
||||
return $this->get(ServerKey::HTTP_HOST, '');
|
||||
}
|
||||
|
||||
public function isHttps(): bool
|
||||
{
|
||||
return $this->get(ServerKey::HTTPS) === 'on' ||
|
||||
$this->get(ServerKey::SERVER_PORT) === '443' ||
|
||||
$this->get(ServerKey::HTTP_X_FORWARDED_PROTO) === 'https';
|
||||
}
|
||||
|
||||
public function getRequestMethod(): Method
|
||||
{
|
||||
$methodString = $this->get(ServerKey::REQUEST_METHOD, 'GET');
|
||||
return Method::tryFrom($methodString) ?? Method::GET;
|
||||
|
||||
}
|
||||
|
||||
public function getQueryString(): string
|
||||
{
|
||||
return $this->get(ServerKey::QUERY_STRING, '');
|
||||
}
|
||||
|
||||
public function getClientIp(): IpAddress
|
||||
{
|
||||
return new IpAddress($this->getClientIpString());
|
||||
}
|
||||
|
||||
public function getProtocol(): ServerProtocol
|
||||
{
|
||||
$protocol = $this->get(ServerKey::SERVER_PROTOCOL);
|
||||
return ServerProtocol::tryFrom($protocol) ?? ServerProtocol::HTTP_1_0;
|
||||
}
|
||||
|
||||
private function getClientIpString(): string
|
||||
{
|
||||
// Priorisierte IP-Erkennung
|
||||
$candidates = [
|
||||
ServerKey::HTTP_X_REAL_IP,
|
||||
ServerKey::HTTP_X_FORWARDED_FOR,
|
||||
ServerKey::REMOTE_ADDR
|
||||
];
|
||||
|
||||
foreach ($candidates as $key) {
|
||||
$ip = $this->get($key);
|
||||
if ($ip) {
|
||||
// Bei X-Forwarded-For kann es mehrere IPs geben
|
||||
if ($key === ServerKey::HTTP_X_FORWARDED_FOR) {
|
||||
$ips = explode(',', $ip);
|
||||
return trim($ips[0]);
|
||||
}
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
|
||||
return '0.0.0.0';
|
||||
}
|
||||
|
||||
public function getReferer(): string
|
||||
{
|
||||
return $this->get(ServerKey::HTTP_REFERER, '');
|
||||
}
|
||||
|
||||
public function getRefererUri(): Uri
|
||||
{
|
||||
$referer = $this->getReferer();
|
||||
|
||||
return new Uri($referer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob ein Referer gesetzt ist
|
||||
*/
|
||||
public function hasReferer(): bool
|
||||
{
|
||||
return !empty($this->get(ServerKey::HTTP_REFERER, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft ob der Referer von der gleichen Domain stammt
|
||||
*/
|
||||
public function isRefererSameDomain(): bool
|
||||
{
|
||||
$referer = $this->getReferer();
|
||||
|
||||
if (empty($referer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$refererHost = parse_url($referer, PHP_URL_HOST);
|
||||
$currentHost = $this->getHttpHost();
|
||||
|
||||
return $refererHost === $currentHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sichere Referer-URL für Redirects
|
||||
*/
|
||||
public function getSafeRefererUrl(string $fallback = '/'): string
|
||||
{
|
||||
$referer = $this->getReferer();
|
||||
|
||||
// Kein Referer gesetzt
|
||||
if (empty($referer)) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
// Nur interne Referer erlauben (CSRF-Schutz)
|
||||
if (!$this->isRefererSameDomain()) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
return $referer;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user