chore: complete update

This commit is contained in:
2025-07-17 16:24:20 +02:00
parent 899227b0a4
commit 64a7051137
1300 changed files with 85570 additions and 2756 deletions

View 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;
}
}