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
- Uzyskiwanie obiektu Request
- Metody RequestInterface
- SessionInterface
- UploadedFileInterface
- AttributesInterface
- Wyjątki
- SUPERGLOBALS_ENABLED
- Tryb worker
- Wsparcie w IDE
- Przykłady
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()parsujeapplication/json,application/x-www-form-urlencodedorazmultipart/form-databez 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=falsejest opcjonalne. Obiektowe API działa niezależnie.
Uzyskiwanie obiektu Request
<?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
oxphp_worker(function () {
$request = oxphp_http_request();
$method = $request->method();
// ...
});Metody RequestInterface
URI i metoda
$request->method(): stringZwraca metodę HTTP wielkimi literami: "GET", "POST", "PUT", "PATCH", "DELETE" itd.
$request->isMethod(string $method): boolSprawdzenie metody bez rozróżniania wielkości liter.
$request->path(): stringŚcieżka URI bez ciągu zapytania: "/users/42".
$request->fullUri(): stringKompletny 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.
$request->scheme(): string"https" lub "http".
$request->isSecure(): booltrue, gdy schematem jest "https".
$request->host(): stringNazwa hosta z nagłówka Host. Zwraca pusty ciąg znaków, gdy nagłówek jest nieobecny (żądania HTTP/1.0 bez nagłówka Host).
$request->port(): intPort z nagłówka Host. Gdy nie jest wprost obecny, zwraca wartość domyślną dla schematu: 80 dla HTTP, 443 dla HTTPS.
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.
$request->queryString(): ?stringSurowy ciąg zapytania bez wiodącego ?. Zwraca null, gdy nie ma ciągu zapytania.
Protokół
$request->httpProtocol(): stringPełny ciąg protokołu: "HTTP/1.1" lub "HTTP/2".
$request->httpProtocolVersion(): stringSam numer wersji: "1.1" lub "2".
Parametry zapytania
$request->query(?string $key = null, mixed $default = null): mixedDostę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:
// 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
$request->payload(?string $key = null, mixed $default = null): mixedZwraca 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
// 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
$request->header(string $name, ?string $default = null): ?stringZwraca 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.
$request->hasHeader(string $name): boolZwraca true, jeśli wskazany nagłówek jest obecny.
$request->headers(): arrayZwraca 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
$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
$request->cookie(string $name, ?string $default = null): ?stringZwraca wartość pojedynczego ciasteczka lub $default, jeśli ciasteczko nie jest obecne.
$request->cookies(): arrayZwraca wszystkie ciasteczka jako tablicę asocjacyjną par nazwa-wartość.
<?php
$theme = $request->cookie('theme', 'light'); // "dark" or "light"
$session = $request->cookie('session'); // null if absent
$all = $request->cookies(); // ["theme" => "dark", ...]Surowe ciało
$request->body(): stringZwraca 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.
$request->contentType(): ?stringZwraca wartość nagłówka Content-Type lub null, jeśli jest nieobecny.
<?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
$request->file(string $name): ?UploadedFileInterfaceZwraca przesłany plik dla podanej nazwy pola lub null, jeśli pole nie jest obecne. Dla pól tablicowych (name="photos[]") zwraca pierwszy plik.
$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
$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
$request->ip(): stringZwraca 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
$request->startTime(bool $asFloat = false): int|floatZwraca 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
$elapsed = microtime(true) - $request->startTime(true);
error_log(sprintf("Request took %.3fs so far", $elapsed));Atrybuty
$request->attributes(): AttributesInterfaceZwraca 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
// 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
$request->session(): ?SessionInterfaceZwraca 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
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ę.
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.
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
$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.
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.
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
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
SUPERGLOBALS_ENABLED=true # default — full backward compatibility
SUPERGLOBALS_ENABLED=false # superglobals are empty arraysDomyś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
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.
<?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:
composer require --dev oxphp/stubsPakiet stubów dostarcza:
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.phpNie dodaje żadnej zależności w czasie działania. Pakiet jest tylko dla require-dev.
Przykłady
Tryb tradycyjny
<?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
$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
// 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ą
<?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,$_COOKIEi$_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 konfiguracji —
SUPERGLOBALS_ENABLEDi inne zmienne środowiskowe