method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; $this->uri = $_SERVER['REQUEST_URI'] ?? '/'; $urlParts = parse_url($this->uri); $this->path = $urlParts['path'] ?? '/'; $this->query = $urlParts['query'] ?? ''; parse_str($this->query, $this->queryParams); $this->headers = $this->parseHeaders(); $this->body = file_get_contents('php://input') ?: ''; $this->cookies = $_COOKIE ?? []; if ($this->method === 'POST' && $this->contentType() === 'application/x-www-form-urlencoded') { parse_str($this->body, $this->postData); } elseif ($this->method === 'POST' && str_contains($this->contentType(), 'multipart/form-data')) { $this->postData = $_POST ?? []; } } /** * parseHeaders extracts HTTP headers from $_SERVER */ private function parseHeaders(): array { $headers = []; foreach ($_SERVER as $key => $value) { if (str_starts_with($key, 'HTTP_')) { $header = str_replace('_', '-', substr($key, 5)); $headers[strtolower($header)] = $value; } } if (isset($_SERVER['CONTENT_TYPE'])) $headers['content-type'] = $_SERVER['CONTENT_TYPE']; if (isset($_SERVER['CONTENT_LENGTH'])) $headers['content-length'] = $_SERVER['CONTENT_LENGTH']; return $headers; } /** * header returns the value of the specified header */ public function header(string $name): ?string { return $this->headers[strtolower($name)] ?? null; } /** * contentType returns the content type without charset */ public function contentType(): string { $contentType = $this->header('content-type') ?? ''; return explode(';', $contentType)[0]; } /** * json decodes the request body as JSON */ public function json(): mixed { return json_decode($this->body, true); } /** * cookie returns the value of the specified cookie */ public function cookie(string $name): ?string { return $this->cookies[$name] ?? null; } /** * param returns a route parameter */ public function param(string $name, mixed $default = null): mixed { return $this->params[$name] ?? $default; } /** * input returns a form input value (POST data) */ public function input(string $name, mixed $default = null): mixed { return $this->postData[$name] ?? $default; } /** * query returns a query parameter value */ public function query(string $name, mixed $default = null): mixed { return $this->queryParams[$name] ?? $default; } /** * jsonValue returns a value from JSON body */ public function jsonValue(string $name, mixed $default = null): mixed { if ($this->contentType() !== 'application/json') { return $default; } $json = $this->json(); if (!is_array($json)) { return $default; } return $json[$name] ?? $default; } /** * all returns all input data merged from all sources */ public function all(): array { $data = array_merge($this->queryParams, $this->postData, $this->params); if ($this->contentType() === 'application/json') { $json = $this->json(); if (is_array($json)) { $data = array_merge($data, $json); } } return $data; } /** * only returns only specified keys from input */ public function only(array $keys): array { $all = $this->all(); return array_intersect_key($all, array_flip($keys)); } /** * except returns all input except specified keys */ public function except(array $keys): array { $all = $this->all(); return array_diff_key($all, array_flip($keys)); } /** * has checks if input key exists */ public function has(string $key): bool { return $this->input($key) !== null; } /** * expectsJson checks if request expects JSON response */ public function expectsJson(): bool { $accept = $this->header('accept') ?? ''; return str_contains($accept, 'application/json') || str_contains($accept, 'text/json') || $this->header('x-requested-with') === 'XMLHttpRequest'; } /** * isAjax checks if request is AJAX */ public function isAjax(): bool { return $this->header('x-requested-with') === 'XMLHttpRequest'; } /** * ip returns the client IP address */ public function ip(): string { // Check for proxied IPs if ($ip = $this->header('x-forwarded-for')) { return explode(',', $ip)[0]; } if ($ip = $this->header('x-real-ip')) { return $ip; } return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'; } /** * userAgent returns the user agent string */ public function userAgent(): string { return $this->header('user-agent') ?? ''; } /** * referer returns the referer URL */ public function referer(): ?string { return $this->header('referer'); } /** * isSecure checks if request is over HTTPS */ public function isSecure(): bool { return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || ($_SERVER['SERVER_PORT'] ?? 80) == 443 || ($this->header('x-forwarded-proto') === 'https'); } /** * url returns the full URL of the request */ public function url(): string { $protocol = $this->isSecure() ? 'https' : 'http'; $host = $_SERVER['HTTP_HOST'] ?? 'localhost'; return $protocol . '://' . $host . $this->uri; } /** * fullUrl returns the URL with query string */ public function fullUrl(): string { return $this->url(); } /** * is checks if the request path matches a pattern */ public function is(string $pattern): bool { $pattern = preg_quote($pattern, '#'); $pattern = str_replace('\*', '.*', $pattern); return preg_match('#^' . $pattern . '$#', $this->path) === 1; } }