API żądania HTTP

OxPHP udostępnia obiektowe API do uzyskiwania dostępu do danych żądania HTTP. Zamiast czytać $_GET, $_POST, $_COOKIE, $_FILES i $_SERVER, wywołujesz metody na obiekcie Request, który zwraca dokładnie to, o co prosisz — nic więcej i nic mniej.

Spis treści

Przegląd

oxphp_http_request() zwraca proxy tylko do odczytu do danych żądania HTTP przechowywanych w bieżącym wątku worker. Dane są pobierane leniwie. Pojedyncze wywołanie metody, takie jak $request->header('Accept'), trafia bezpośrednio do struktury danych po stronie Rust i zwraca tylko tę wartość. Wywołania zwracające całą tablicę, takie jak $request->headers(), budują tablicę raz i buforują ją w obiekcie PHP na czas trwania żądania.

Dlaczego używać tego zamiast superglobalnych?

  • Parsowanie ciała JSON jest wbudowane. $request->payload() parsuje application/json, application/x-www-form-urlencoded oraz multipart/form-data bez dodatkowego kodu.
  • Bez literówek w kluczach tablicy. $request->method() trudniej pomylić przy pisaniu niż $_SERVER['REQUEST_METHOD'].
  • Wykrywanie typu przesyłanych plików. $request->file('avatar')->type() zwraca typ MIME ustalony na podstawie faktycznej zawartości pliku, a nie wartości podanej przez klienta.
  • Testowalność. Ponieważ zachowanie jest zdefiniowane przez interfejsy, w testach jednostkowych możesz wstrzykiwać atrapy implementacji.
  • Superglobalne pozostają dostępne. Ustawienie SUPERGLOBALS_ENABLED=false jest opcjonalne. Obiektowe API działa niezależnie.

Uzyskiwanie obiektu Request

php
<?php $request = oxphp_http_request();

Wywołaj oxphp_http_request() w dowolnym miejscu skryptu wykonywanego wewnątrz aktywnego żądania HTTP, w tym wewnątrz wywołania zwrotnego oxphp_worker():

php
<?php oxphp_worker(function () { $request = oxphp_http_request(); $method = $request->method(); // ... });

Metody RequestInterface

URI i metoda

php
$request->method(): string

Zwraca metodę HTTP wielkimi literami: "GET", "POST", "PUT", "PATCH", "DELETE" itd.

php
$request->isMethod(string $method): bool

Sprawdzenie metody bez rozróżniania wielkości liter.

php
$request->path(): string

Ścieżka URI bez ciągu zapytania: "/users/42".

php
$request->fullUri(): string

Kompletny URI zawierający schemat, host, opcjonalny niestandardowy port, ścieżkę i ciąg zapytania: "https://example.com:8080/users/42?page=2". Standardowe porty (80 dla HTTP, 443 dla HTTPS) są pomijane.

php
$request->scheme(): string

"https" lub "http".

php
$request->isSecure(): bool

true, gdy schematem jest "https".

php
$request->host(): string

Nazwa hosta z nagłówka Host. Zwraca pusty ciąg znaków, gdy nagłówek jest nieobecny (żądania HTTP/1.0 bez nagłówka Host).

php
$request->port(): int

Port z nagłówka Host. Gdy nie jest wprost obecny, zwraca wartość domyślną dla schematu: 80 dla HTTP, 443 dla HTTPS.

Za odwrotnym proxy

scheme(), isSecure(), host() i port() uwzględniają X-Forwarded-Proto oraz X-Forwarded-Host, gdy TRUSTED_PROXIES obejmuje peera. Bez zaufanych proxy odzwierciedlają one bezpośrednie połączenie.

php
$request->queryString(): ?string

Surowy ciąg zapytania bez wiodącego ?. Zwraca null, gdy nie ma ciągu zapytania.

Protokół

php
$request->httpProtocol(): string

Pełny ciąg protokołu: "HTTP/1.1" lub "HTTP/2".

php
$request->httpProtocolVersion(): string

Sam numer wersji: "1.1" lub "2".

Parametry zapytania

php
$request->query(?string $key = null, mixed $default = null): mixed

Dostęp do parametrów ciągu zapytania.

Wywołanie Zwraca
$request->query() Wszystkie parametry jako tablicę, w tym tablice zagnieżdżone
$request->query('page') Wartość page lub null, jeśli nieobecna
$request->query('page', 1) Wartość page lub 1, jeśli nieobecna

Notacja z nawiasami (?tags[]=php&tags[]=async) jest parsowana do tablic zagnieżdżonych:

php
// Request: GET /search?q=oxphp&tags[]=php&tags[]=async $q = $request->query('q'); // "oxphp" $tags = $request->query('tags'); // ["php", "async"] $all = $request->query(); // ["q" => "oxphp", "tags" => ["php", "async"]]

Znalezione wartości są zawsze ciągami znaków. $default jest zwracany bez zmian, gdy klucz jest nieobecny.

Sparsowane ciało

php
$request->payload(?string $key = null, mixed $default = null): mixed

Zwraca sparsowane ciało żądania. Ciało jest parsowane zgodnie z nagłówkiem Content-Type:

Content-Type Zwraca
application/x-www-form-urlencoded Tablicę asocjacyjną wartości pól
multipart/form-data Tablicę asocjacyjną wartości pól tekstowych
application/json Zdekodowaną tablicę lub wartość skalarną; null dla nieprawidłowego JSON-a
Dowolna inna wartość null

payload() nie jest ograniczony do żądań POST. Działa z PUT, PATCH i każdą inną metodą, która wysyła ciało. Sparsowany wynik jest buforowany przy pierwszym wywołaniu i ponownie wykorzystywany przez cały czas trwania żądania.

Wywołanie Zwraca
$request->payload() Całe sparsowane ciało
$request->payload('email') Wartość pojedynczego pola lub null, jeśli nieobecne
$request->payload('email', '') Wartość pojedynczego pola lub '', jeśli nieobecne
php
<?php // JSON request: POST /api/users // Content-Type: application/json // Body: {"name": "Alice", "role": "admin"} $name = $request->payload('name'); // "Alice" $role = $request->payload('role'); // "admin" $data = $request->payload(); // ["name" => "Alice", "role" => "admin"]

Nagłówki

php
$request->header(string $name, ?string $default = null): ?string

Zwraca surową wartość nagłówka. Nazwy nagłówków nie rozróżniają wielkości liter. Dla nagłówków wielowartościowych (Accept, X-Forwarded-For) cała linia nagłówka jest zwracana jako pojedynczy ciąg znaków. Parsowanie leży po Twojej stronie.

php
$request->hasHeader(string $name): bool

Zwraca true, jeśli wskazany nagłówek jest obecny.

php
$request->headers(): array

Zwraca wszystkie nagłówki jako tablicę asocjacyjną. Każdy klucz to nazwa nagłówka w otrzymanej postaci (bez normalizacji), a każda wartość to surowy ciąg nagłówka.

php
<?php $accept = $request->header('Accept'); // "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" if ($request->hasHeader('Authorization')) { $token = $request->header('Authorization'); } $all = $request->headers(); // ["Content-Type" => "application/json", "Accept" => "...", ...]

Ciasteczka

php
$request->cookie(string $name, ?string $default = null): ?string

Zwraca wartość pojedynczego ciasteczka lub $default, jeśli ciasteczko nie jest obecne.

php
$request->cookies(): array

Zwraca wszystkie ciasteczka jako tablicę asocjacyjną par nazwa-wartość.

php
<?php $theme = $request->cookie('theme', 'light'); // "dark" or "light" $session = $request->cookie('session'); // null if absent $all = $request->cookies(); // ["theme" => "dark", ...]

Surowe ciało

php
$request->body(): string

Zwraca surowe bajty ciała żądania. To odpowiednik file_get_contents('php://input') w OxPHP. W przeciwieństwie do payload(), body() nie jest buforowany. Każde wywołanie trafia do bazowej struktury danych.

php
$request->contentType(): ?string

Zwraca wartość nagłówka Content-Type lub null, jeśli jest nieobecny.

php
<?php // Read raw body for signature verification $raw = $request->body(); $signature = $request->header('X-Hub-Signature-256'); $valid = hash_hmac('sha256', $raw, $secret) === $signature;

body() i payload() są niezależne. Możesz wywołać oba w tym samym żądaniu.

Przesyłane pliki

php
$request->file(string $name): ?UploadedFileInterface

Zwraca przesłany plik dla podanej nazwy pola lub null, jeśli pole nie jest obecne. Dla pól tablicowych (name="photos[]") zwraca pierwszy plik.

php
$request->files(?string $name = null): array
Wywołanie Zwraca
$request->files() Wszystkie przesłane pliki jako płaską tablicę obiektów UploadedFileInterface
$request->files('photos') Wszystkie pliki dla pola photos (obsługuje name="photos[]")
php
<?php $avatar = $request->file('avatar'); if ($avatar && $avatar->isValid()) { $mime = $avatar->type(); // Detected from file contents, not the client claim $name = $avatar->name(); // Original filename $avatar->moveTo('/var/uploads/' . basename($name)); } // Multiple files $photos = $request->files('photos'); // UploadedFileInterface[] foreach ($photos as $photo) { if ($photo->isValid()) { $photo->moveTo('/var/uploads/' . basename($photo->name())); } }

Klient

php
$request->ip(): string

Zwraca adres IP klienta. Gdy TRUSTED_PROXIES jest skonfigurowany, a peer żądania należy do zaufanego zbioru, jest to skrajnie prawy niezaufany adres z X-Forwarded-For lub z Forwarded (RFC 7239). W przeciwnym razie jest to IP bezpośredniego peera, zwykle Twojego load balancera, a nie klienta końcowego.

Surowy nagłówek X-Forwarded-For pozostaje dostępny przez $request->header('X-Forwarded-For') na potrzeby zaawansowanych przypadków, ale ręczne parsowanie go rzadko bywa poprawne (skrajnie lewy kontra skrajnie prawy, brak sprawdzenia zaufania na podstawie CIDR). Zamiast tego skonfiguruj TRUSTED_PROXIES. Zobacz Zaufane proxy.

Pomiar czasu

php
$request->startTime(bool $asFloat = false): int|float

Zwraca znacznik czasu Unix wskazujący, kiedy to żądanie zostało odebrane.

Wywołanie Zwraca
$request->startTime() Sekundy jako liczbę całkowitą: 1711234567
$request->startTime(true) Liczbę zmiennoprzecinkową z dokładnością poniżej sekundy: 1711234567.3412
php
<?php $elapsed = microtime(true) - $request->startTime(true); error_log(sprintf("Request took %.3fs so far", $elapsed));

Atrybuty

php
$request->attributes(): AttributesInterface

Zwraca modyfikowalny kontener atrybutów dla bieżącego żądania. Używaj atrybutów, aby współdzielić dane między middleware, obsługami tras i innym kodem w obrębie tego samego żądania bez sięgania po zmienne globalne.

php
<?php // In authentication middleware $request->attributes()->set('user', $authenticatedUser); // In the route handler $user = $request->attributes()->get('user');

Atrybuty istnieją w obrębie żądania i są resetowane przy każdym nowym żądaniu w trybie worker. Podczas korzystania z Fiberów atrybuty są współdzielone przez wszystkie Fibery działające na tym samym wątku worker dla tego samego żądania. Ponieważ Fibery PHP są kooperacyjne, współbieżny dostęp nie jest możliwy.

Sesja

php
$request->session(): ?SessionInterface

Zwraca widok tylko do odczytu na $_SESSION. Zwraca null, jeśli session_start() nie zostało wywołane. Zarządzanie sesją (uruchamianie, zapisywanie, niszczenie, zapisywanie wartości) odbywa się za pomocą standardowych funkcji sesji PHP.

php
<?php session_start(); $session = $request->session(); $userId = $session->get('user_id'); $isAdmin = $session->get('is_admin', false); // Write session data using standard PHP functions $_SESSION['last_seen'] = time();

SessionInterface

SessionInterface to widok tylko do odczytu na aktywną sesję.

php
namespace OxPHP\Http; interface SessionInterface { public function id(): string; public function name(): string; public function get(string $key, mixed $default = null): mixed; public function has(string $key): bool; public function all(): array; }
Metoda Opis
id() ID sesji
name() Nazwa sesji (domyślnie: "PHPSESSID")
get(key, default) Pojedyncza wartość sesji lub $default, jeśli klucz jest nieobecny
has(key) true, jeśli klucz istnieje w $_SESSION
all() Wszystkie dane sesji jako tablica

Wartości sesji odzwierciedlają bieżący stan $_SESSION w momencie wywołania, a nie stan z chwili, gdy session() zostało wywołane po raz pierwszy.

UploadedFileInterface

UploadedFileInterface reprezentuje pojedynczy przesłany plik.

php
namespace OxPHP\Http; interface UploadedFileInterface { public function name(): string; public function clientType(): string; public function type(): string; public function size(): int; public function tmpPath(): string; public function error(): int; public function isValid(): bool; public function moveTo(string $destination): bool; }
Metoda Opis
name() Oryginalna nazwa pliku wysłana przez klienta
clientType() Typ MIME zadeklarowany przez klienta — nie ufaj tej wartości przy decyzjach dotyczących bezpieczeństwa
type() Typ MIME ustalony na podstawie faktycznej zawartości pliku za pomocą wykrywania magicznych bajtów. Zwraca "application/octet-stream", gdy typu nie da się ustalić. Buforowany przy pierwszym wywołaniu.
size() Rozmiar pliku w bajtach
tmpPath() Ścieżka do pliku tymczasowego na dysku
error() Jedna ze stałych UPLOAD_ERR_*
isValid() true, gdy error() ma wartość UPLOAD_ERR_OK
moveTo(path) Przenosi plik do $path. Wywołuje type() przed przeniesieniem. Zwraca false, jeśli plik jest nieprawidłowy lub przeniesienie się nie powiedzie.

Zawsze sprawdzaj isValid() przed użyciem przesłanego pliku. Używaj type() zamiast clientType() przy podejmowaniu decyzji wrażliwych na bezpieczeństwo:

php
<?php $file = $request->file('document'); if (!$file || !$file->isValid()) { http_response_code(400); echo json_encode(['error' => 'Upload failed or missing']); return; } $detectedMime = $file->type(); $allowed = ['application/pdf', 'image/jpeg', 'image/png']; if (!in_array($detectedMime, $allowed, true)) { http_response_code(415); echo json_encode(['error' => "File type not allowed: $detectedMime"]); return; } $file->moveTo('/var/uploads/' . bin2hex(random_bytes(8)) . '.pdf');

AttributesInterface

AttributesInterface to jedyna modyfikowalna część obiektu żądania. Jest przeznaczony do przechowywania metadanych w obrębie żądania — uwierzytelnionego użytkownika, rozwiązanych parametrów trasy, ustawień regionalnych, flag funkcji — do których dostęp potrzebuje wiele części aplikacji.

php
namespace OxPHP\Http; interface AttributesInterface { public function get(string $key, mixed $default = null): mixed; public function set(string $key, mixed $value): void; public function has(string $key): bool; public function remove(string $key): void; public function all(): array; }
Metoda Opis
get(key, default) Zwraca wartość dla $key lub $default, jeśli nieobecna
set(key, value) Zapisuje wartość
has(key) true, jeśli klucz został ustawiony
remove(key) Usuwa klucz
all() Wszystkie atrybuty jako tablicę asocjacyjną

Wyjątki

Wywołanie oxphp_http_request() poza kontekstem aktywnego żądania rzuca wyjątek z przestrzeni nazw OxPHP\Http\Exception.

php
namespace OxPHP\Http\Exception; class NoActiveRequestException extends \RuntimeException {} class AsyncContextException extends NoActiveRequestException {} class WorkerIdleException extends NoActiveRequestException {}
Wyjątek Kiedy jest rzucany
NoActiveRequestException Brak aktywnego żądania HTTP: CLI, MINIT, po zamknięciu lub Fiber, który przeżył swoje żądanie
AsyncContextException Wewnątrz wywołania zwrotnego oxphp_async() — workery asynchroniczne działają na osobnych wątkach bez kontekstu żądania
WorkerIdleException Tryb worker, między żądaniami — worker czeka na kolejne żądanie

AsyncContextException i WorkerIdleException rozszerzają NoActiveRequestException, więc przechwycenie klasy bazowej obsługuje wszystkie przypadki.

php
<?php try { $request = oxphp_http_request(); } catch (\OxPHP\Http\Exception\AsyncContextException $e) { // Inside oxphp_async() — no request context here } catch (\OxPHP\Http\Exception\WorkerIdleException $e) { // Worker is between requests — do not call oxphp_http_request() here } catch (\OxPHP\Http\Exception\NoActiveRequestException $e) { // Any other case with no active request }

W normalnym kodzie obsługującym żądania to try/catch nie jest potrzebne. Zabezpieczenie wyjątkiem przydaje się w kodzie inicjalizacyjnym, który może działać poza kontekstem żądania.

SUPERGLOBALS_ENABLED

bash
SUPERGLOBALS_ENABLED=true # default — full backward compatibility SUPERGLOBALS_ENABLED=false # superglobals are empty arrays

Domyślnie OxPHP wypełnia $_GET, $_POST, $_COOKIE, $_FILES i $_SERVER jak zwykle. W tym trybie obiektowe API HTTP jest dostępne obok superglobalnych.

Ustawienie SUPERGLOBALS_ENABLED=false sprawia, że te tablice są puste, co eliminuje koszt ich budowania dla każdego żądania. Poniższe wciąż działają niezależnie od tego ustawienia:

Funkcja Zachowanie przy SUPERGLOBALS_ENABLED=false
oxphp_http_request() Zawsze dostępne
php://input Dostępne (to strumień, a nie superglobalna)
$_SESSION Dostępne (zarządzane przez moduł sesji PHP)
header(), headers_list() Dostępne (funkcje wyjścia SAPI)
session_start(), session_*() Dostępne (natywne funkcje PHP)
$_GET, $_POST, $_COOKIE, $_FILES, $_SERVER Puste tablice

Użyj oxphp_superglobals_enabled(), aby sprawdzić bieżące ustawienie w czasie działania:

php
<?php if (!oxphp_superglobals_enabled()) { $method = oxphp_http_request()->method(); } else { $method = $_SERVER['REQUEST_METHOD']; }

Tryb worker

W trybie worker dla każdego przychodzącego żądania tworzony jest nowy obiekt Request. Obiekt poprzedniego żądania staje się nieważny po zakończeniu żądania. Nie przechowuj do niego referencji między żądaniami.

worker.php
<?php // worker.php require __DIR__ . '/vendor/autoload.php'; $app = new MyApp\Application(); oxphp_worker(function () use ($app) { $request = oxphp_http_request(); $app->handle($request); });

Wszystkie bufory na obiekcie Request (sparsowane nagłówki, ciasteczka, parametry zapytania, payload) są automatycznie czyszczone, gdy rozpoczyna się kolejne żądanie.

Wsparcie w IDE

Zainstaluj pakiet stubów, aby uzyskać autouzupełnianie i sprawdzanie typów w PhpStorm, VS Code lub dowolnym edytorze obsługującym LSP:

bash
composer require --dev oxphp/stubs

Pakiet stubów dostarcza:

text
oxphp-stubs/ ├── OxPHP/Http/ │ ├── RequestInterface.php │ ├── SessionInterface.php │ ├── UploadedFileInterface.php │ ├── AttributesInterface.php │ ├── Request.php │ ├── Session.php │ ├── UploadedFile.php │ ├── Attributes.php │ └── Exception/ │ ├── NoActiveRequestException.php │ ├── AsyncContextException.php │ └── WorkerIdleException.php └── functions.php

Nie dodaje żadnej zależności w czasie działania. Pakiet jest tylko dla require-dev.

Przykłady

Tryb tradycyjny

php
<?php $request = oxphp_http_request(); $method = $request->method(); // "GET" $path = $request->path(); // "/api/articles" $page = $request->query('page', 1); // "2" or 1 (default) // Authorization header if (!$request->hasHeader('Authorization')) { http_response_code(401); echo json_encode(['error' => 'Unauthorized']); exit; } $token = $request->header('Authorization'); // Structured logging with request metadata error_log(sprintf( '[%s] %s %s from %s', oxphp_request_id(), $method, $path, $request->ip() ));

POST z ciałem JSON

php
<?php $request = oxphp_http_request(); if (!$request->isMethod('POST')) { http_response_code(405); exit; } $email = $request->payload('email'); $password = $request->payload('password'); if (!$email || !$password) { http_response_code(400); echo json_encode(['error' => 'email and password are required']); exit; } // payload() handles JSON, form-urlencoded, and multipart // No manual json_decode() or $_POST check needed $user = authenticate($email, $password); header('Content-Type: application/json'); echo json_encode(['token' => $user->generateToken()]);

Atrybuty w middleware

php
<?php // auth-middleware.php function authenticate_request(\OxPHP\Http\RequestInterface $request): void { $token = $request->header('Authorization'); if (!$token) { http_response_code(401); exit; } $user = verify_token(str_replace('Bearer ', '', $token)); if (!$user) { http_response_code(403); exit; } $request->attributes()->set('user', $user); } // route-handler.php $request = oxphp_http_request(); authenticate_request($request); $user = $request->attributes()->get('user'); echo json_encode(['id' => $user->id, 'name' => $user->name]);

Tryb worker z sesją

worker.php
<?php // worker.php require __DIR__ . '/vendor/autoload.php'; oxphp_worker(function () { $request = oxphp_http_request(); if ($request->path() === '/login' && $request->isMethod('POST')) { $username = $request->payload('username'); $password = $request->payload('password'); if (verify_credentials($username, $password)) { session_start(); $_SESSION['user'] = $username; $_SESSION['authenticated'] = true; header('Location: /dashboard'); } else { http_response_code(401); echo 'Invalid credentials'; } return; } if ($request->path() === '/dashboard') { session_start(); $session = $request->session(); if (!$session || !$session->get('authenticated')) { header('Location: /login'); return; } echo 'Welcome, ' . htmlspecialchars($session->get('user')); } });

Zobacz też

  • Superglobalne — jak OxPHP wypełnia $_SERVER, $_GET, $_POST, $_COOKIE i $_FILES
  • Funkcje PHP — pełne odniesienie do oxphp_http_request(), oxphp_superglobals_enabled() i wszystkich pozostałych wbudowanych funkcji
  • Tryb worker — trwałe procesy PHP i cykl życia żądania
  • Odniesienie konfiguracjiSUPERGLOBALS_ENABLED i inne zmienne środowiskowe