API de requête HTTP

OxPHP fournit une API orientée objet pour accéder aux données de requête HTTP. Au lieu de lire $_GET, $_POST, $_COOKIE, $_FILES et $_SERVER, vous appelez des méthodes sur un objet Request qui renvoie exactement ce que vous demandez, ni plus ni moins.

Table des matières

Vue d'ensemble

oxphp_http_request() renvoie un proxy en lecture seule vers les données de requête HTTP stockées dans le thread du worker courant. Les données sont récupérées de manière paresseuse. Un appel de méthode unique comme $request->header('Accept') accède directement à la structure de données côté Rust et renvoie uniquement cette valeur. Les appels renvoyant le tableau complet, comme $request->headers(), construisent le tableau une seule fois et le mettent en cache dans l'objet PHP pour la durée de la requête.

Pourquoi l'utiliser plutôt que les superglobales ?

  • L'analyse du corps JSON est intégrée. $request->payload() analyse application/json, application/x-www-form-urlencoded et multipart/form-data sans code supplémentaire.
  • Pas de fautes de frappe dans les clés de tableau. $request->method() est plus difficile à mal orthographier que $_SERVER['REQUEST_METHOD'].
  • Type des fichiers téléversés détecté. $request->file('avatar')->type() renvoie le type MIME déterminé à partir du contenu réel du fichier, et non la valeur fournie par le client.
  • Testable. Comme le comportement est défini par des interfaces, vous pouvez injecter des implémentations mock dans les tests unitaires.
  • Les superglobales restent disponibles. Définir SUPERGLOBALS_ENABLED=false est facultatif. L'API objet fonctionne dans tous les cas.

Obtenir l'objet Request

php
<?php $request = oxphp_http_request();

Appelez oxphp_http_request() n'importe où dans un script s'exécutant à l'intérieur d'une requête HTTP active, y compris dans le callback oxphp_worker() :

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

Méthodes de RequestInterface

URI et méthode

php
$request->method(): string

Renvoie la méthode HTTP en majuscules : "GET", "POST", "PUT", "PATCH", "DELETE", etc.

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

Vérification de méthode insensible à la casse.

php
$request->path(): string

Le chemin de l'URI sans la chaîne de requête : "/users/42".

php
$request->fullUri(): string

L'URI complète, comprenant le schéma, l'hôte, un port non standard optionnel, le chemin et la chaîne de requête : "https://example.com:8080/users/42?page=2". Les ports standard (80 pour HTTP, 443 pour HTTPS) sont omis.

php
$request->scheme(): string

"https" ou "http".

php
$request->isSecure(): bool

true lorsque le schéma est "https".

php
$request->host(): string

Nom d'hôte issu de l'en-tête Host. Renvoie une chaîne vide lorsque l'en-tête est absent (requêtes HTTP/1.0 sans en-tête Host).

php
$request->port(): int

Port issu de l'en-tête Host. Lorsqu'il n'est pas explicitement présent, renvoie la valeur par défaut du schéma : 80 pour HTTP, 443 pour HTTPS.

Derrière un proxy inverse

scheme(), isSecure(), host() et port() respectent X-Forwarded-Proto et X-Forwarded-Host lorsque TRUSTED_PROXIES inclut le pair. Sans proxys de confiance, ils reflètent la connexion directe.

php
$request->queryString(): ?string

La chaîne de requête brute sans le ? initial. Renvoie null lorsqu'il n'y a pas de chaîne de requête.

Protocole

php
$request->httpProtocol(): string

La chaîne de protocole complète : "HTTP/1.1" ou "HTTP/2".

php
$request->httpProtocolVersion(): string

Le numéro de version uniquement : "1.1" ou "2".

Paramètres de la chaîne de requête

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

Accès aux paramètres de la chaîne de requête.

Appel Renvoie
$request->query() Tous les paramètres sous forme de tableau, y compris les tableaux imbriqués
$request->query('page') La valeur de page, ou null si absente
$request->query('page', 1) La valeur de page, ou 1 si absente

La notation entre crochets (?tags[]=php&tags[]=async) est analysée en tableaux imbriqués :

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"]]

Les valeurs trouvées sont toujours des chaînes. $default est renvoyé tel quel lorsque la clé est absente.

Corps analysé

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

Renvoie le corps de requête analysé. Le corps est analysé en fonction de l'en-tête Content-Type :

Content-Type Renvoie
application/x-www-form-urlencoded Tableau associatif des valeurs de champ
multipart/form-data Tableau associatif des valeurs des champs texte
application/json Tableau ou scalaire décodé ; null si le JSON est invalide
Toute autre valeur null

payload() n'est pas limité aux requêtes POST. Il fonctionne avec PUT, PATCH et toute autre méthode qui envoie un corps. Le résultat analysé est mis en cache au premier appel et réutilisé pendant toute la durée de la requête.

Appel Renvoie
$request->payload() L'intégralité du corps analysé
$request->payload('email') La valeur d'un seul champ, ou null si absente
$request->payload('email', '') La valeur d'un seul champ, ou '' si absente
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"]

En-têtes

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

Renvoie la valeur brute de l'en-tête. Les noms d'en-tête sont insensibles à la casse. Pour les en-têtes à valeurs multiples (Accept, X-Forwarded-For), la ligne d'en-tête complète est renvoyée sous forme d'une seule chaîne. L'analyse est à votre charge.

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

Renvoie true si l'en-tête nommé est présent.

php
$request->headers(): array

Renvoie tous les en-têtes sous forme de tableau associatif. Chaque clé est le nom de l'en-tête tel que reçu (sans normalisation), et chaque valeur est la chaîne d'en-tête brute.

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" => "...", ...]

Cookies

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

Renvoie la valeur d'un cookie unique, ou $default si le cookie n'est pas présent.

php
$request->cookies(): array

Renvoie tous les cookies sous forme de tableau associatif de paires nom-valeur.

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

Corps brut

php
$request->body(): string

Renvoie les octets bruts du corps de la requête. C'est l'équivalent OxPHP de file_get_contents('php://input'). Contrairement à payload(), body() n'est pas mis en cache. Chaque appel accède à la structure de données sous-jacente.

php
$request->contentType(): ?string

Renvoie la valeur de l'en-tête Content-Type, ou null si absent.

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() et payload() sont indépendants. Vous pouvez appeler les deux dans la même requête.

Téléversement de fichiers

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

Renvoie le fichier téléversé pour le nom de champ donné, ou null si le champ n'est pas présent. Pour les champs de type tableau (name="photos[]"), renvoie le premier fichier.

php
$request->files(?string $name = null): array
Appel Renvoie
$request->files() Tous les fichiers téléversés sous forme de tableau plat de UploadedFileInterface
$request->files('photos') Tous les fichiers du champ photos (prend en charge 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())); } }

Client

php
$request->ip(): string

Renvoie l'adresse IP du client. Lorsque TRUSTED_PROXIES est configuré et que le pair de la requête fait partie de l'ensemble de confiance, il s'agit de l'adresse non fiable la plus à droite issue de X-Forwarded-For ou de Forwarded (RFC 7239). Sinon, il s'agit de l'IP du pair direct, généralement votre équilibreur de charge, et non le client final.

L'en-tête brut X-Forwarded-For reste accessible via $request->header('X-Forwarded-For') pour les cas avancés, mais l'analyser manuellement est rarement correct (adresse la plus à gauche vs la plus à droite, absence de vérification de confiance par CIDR). Configurez plutôt TRUSTED_PROXIES. Voir Proxys de confiance.

Chronométrage

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

Renvoie l'horodatage Unix correspondant au moment où cette requête a été reçue.

Appel Renvoie
$request->startTime() Secondes entières : 1711234567
$request->startTime(true) Flottant avec précision inférieure à la seconde : 1711234567.3412
php
<?php $elapsed = microtime(true) - $request->startTime(true); error_log(sprintf("Request took %.3fs so far", $elapsed));

Attributs

php
$request->attributes(): AttributesInterface

Renvoie le conteneur d'attributs mutable pour la requête courante. Utilisez les attributs pour partager des données entre les middlewares, les gestionnaires de route et tout autre code de la même requête, sans recourir à des variables globales.

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

Les attributs sont propres à chaque requête et sont réinitialisés à chaque nouvelle requête en mode worker. Lorsque vous utilisez des Fibers, les attributs sont partagés entre toutes les Fibers s'exécutant sur le même thread de worker pour la même requête. Comme les Fibers PHP sont coopératives, un accès concurrent n'est pas possible.

Session

php
$request->session(): ?SessionInterface

Renvoie une vue en lecture seule de $_SESSION. Renvoie null si session_start() n'a pas été appelé. La gestion de la session (démarrage, sauvegarde, destruction, écriture de valeurs) utilise les fonctions de session PHP standard.

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 est une vue en lecture seule de la session active.

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; }
Méthode Description
id() L'ID de session
name() Le nom de la session (par défaut : "PHPSESSID")
get(key, default) Une seule valeur de session, ou $default si la clé est absente
has(key) true si la clé existe dans $_SESSION
all() Toutes les données de session sous forme de tableau

Les valeurs de session reflètent l'état courant de $_SESSION au moment de l'appel, et non l'état au moment où session() a été appelé pour la première fois.

UploadedFileInterface

UploadedFileInterface représente un seul fichier téléversé.

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; }
Méthode Description
name() Nom de fichier d'origine envoyé par le client
clientType() Type MIME déclaré par le client — ne faites pas confiance à cette valeur pour les décisions de sécurité
type() Type MIME déterminé à partir du contenu réel du fichier via la détection par octets magiques. Renvoie "application/octet-stream" lorsque le type ne peut pas être déterminé. Mis en cache au premier appel.
size() Taille du fichier en octets
tmpPath() Chemin du fichier temporaire sur le disque
error() L'une des constantes UPLOAD_ERR_*
isValid() true lorsque error() vaut UPLOAD_ERR_OK
moveTo(path) Déplace le fichier vers $path. Appelle type() avant le déplacement. Renvoie false si le fichier est invalide ou si le déplacement échoue.

Vérifiez toujours isValid() avant d'utiliser un fichier téléversé. Utilisez type() plutôt que clientType() pour les décisions sensibles à la sécurité :

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 est la seule partie mutable de l'objet requête. Elle est conçue pour stocker des métadonnées propres à la requête — utilisateur authentifié, paramètres de route résolus, locale, indicateurs de fonctionnalités — auxquelles plusieurs parties de l'application doivent accéder.

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; }
Méthode Description
get(key, default) Renvoie la valeur de $key, ou $default si absente
set(key, value) Stocke une valeur
has(key) true si la clé a été définie
remove(key) Supprime la clé
all() Tous les attributs sous forme de tableau associatif

Exceptions

Appeler oxphp_http_request() en dehors d'un contexte de requête active lève une exception du namespace OxPHP\Http\Exception.

php
namespace OxPHP\Http\Exception; class NoActiveRequestException extends \RuntimeException {} class AsyncContextException extends NoActiveRequestException {} class WorkerIdleException extends NoActiveRequestException {}
Exception Cas de levée
NoActiveRequestException Aucune requête HTTP active : CLI, MINIT, après l'arrêt, ou une Fiber qui survit à sa requête
AsyncContextException À l'intérieur d'un callback oxphp_async() — les workers asynchrones s'exécutent sur des threads séparés, sans contexte de requête
WorkerIdleException Mode worker, entre deux requêtes — le worker attend la requête suivante

AsyncContextException et WorkerIdleException étendent toutes deux NoActiveRequestException, donc capturer la classe de base gère tous les cas.

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 }

Dans le code normal de traitement des requêtes, vous n'avez pas besoin de ce try/catch. La protection par exception est utile dans le code d'amorçage susceptible de s'exécuter en dehors d'un contexte de requête.

SUPERGLOBALS_ENABLED

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

Par défaut, OxPHP remplit $_GET, $_POST, $_COOKIE, $_FILES et $_SERVER comme d'habitude. L'API objet HTTP est disponible aux côtés des superglobales dans ce mode.

Définir SUPERGLOBALS_ENABLED=false rend ces tableaux vides, ce qui élimine le coût de leur construction à chaque requête. Les éléments suivants fonctionnent toujours, quel que soit ce réglage :

Fonctionnalité Comportement avec SUPERGLOBALS_ENABLED=false
oxphp_http_request() Toujours disponible
php://input Disponible (c'est un flux, pas une superglobale)
$_SESSION Disponible (géré par le module de session de PHP)
header(), headers_list() Disponible (fonctions de sortie SAPI)
session_start(), session_*() Disponible (fonctions PHP natives)
$_GET, $_POST, $_COOKIE, $_FILES, $_SERVER Tableaux vides

Utilisez oxphp_superglobals_enabled() pour vérifier le réglage courant à l'exécution :

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

Mode worker

En mode worker, un nouvel objet Request est créé pour chaque requête entrante. L'objet de la requête précédente devient invalide une fois la requête terminée. Ne conservez pas de référence vers celui-ci entre les requêtes.

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

Tous les caches de l'objet Request (en-têtes analysés, cookies, paramètres de requête, payload) sont vidés automatiquement lorsque la requête suivante commence.

Prise en charge des IDE

Installez le paquet de stubs pour obtenir l'autocomplétion et la vérification de types dans PhpStorm, VS Code, ou tout éditeur compatible LSP :

bash
composer require --dev oxphp/stubs

Le paquet de stubs fournit :

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

Aucune dépendance d'exécution n'est ajoutée. Le paquet est uniquement en require-dev.

Exemples

Mode traditionnel

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 avec corps 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()]);

Attributs de 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]);

Mode worker avec session

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')); } });

Voir aussi

  • Superglobales — comment OxPHP remplit $_SERVER, $_GET, $_POST, $_COOKIE et $_FILES
  • Fonctions PHP — référence complète de oxphp_http_request(), oxphp_superglobals_enabled() et de toutes les autres fonctions intégrées
  • Mode worker — processus PHP persistants et cycle de vie de la requête
  • Référence de configurationSUPERGLOBALS_ENABLED et autres variables d'environnement