diff --git a/request.php b/request.php index 6d4f2c6..e1b8dcb 100644 --- a/request.php +++ b/request.php @@ -100,4 +100,168 @@ class Request { return $this->params[$name] ?? $this->queryParams[$name] ?? $this->postData[$name] ?? null; } + + /** + * input returns input value from any source (route, query, post, json) + */ + public function input(string $name, mixed $default = null): mixed + { + // Check route params first + if (isset($this->params[$name])) { + return $this->params[$name]; + } + + // Check query params + if (isset($this->queryParams[$name])) { + return $this->queryParams[$name]; + } + + // Check post data + if (isset($this->postData[$name])) { + return $this->postData[$name]; + } + + // Check JSON body + if ($this->contentType() === 'application/json') { + $json = $this->json(); + if (is_array($json) && isset($json[$name])) { + return $json[$name]; + } + } + + return $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; + } }