HTTP リクエスト API

OxPHP は HTTP リクエストデータにアクセスするためのオブジェクト指向 API を提供します。$_GET$_POST$_COOKIE$_FILES$_SERVER を読み取る代わりに、Request オブジェクトのメソッドを呼び出すことで、要求したものだけを過不足なく取得できます。

目次

概要

oxphp_http_request() は、現在のワーカースレッドに保存されている HTTP リクエストデータへの読み取り専用プロキシを返します。データは遅延して取得されます。$request->header('Accept') のような単一のメソッド呼び出しは、Rust 側のデータ構造に直接アクセスし、その値だけを返します。$request->headers() のような配列全体を返す呼び出しは、配列を一度だけ構築し、リクエストの処理中は PHP オブジェクト内にキャッシュします。

スーパーグローバルの代わりにこれを使う理由

  • JSON ボディのパースが組み込まれています。 $request->payload()application/jsonapplication/x-www-form-urlencodedmultipart/form-data を追加のコードなしでパースします。
  • 配列キーのタイプミスがありません。 $request->method()$_SERVER['REQUEST_METHOD'] よりもタイプミスしにくくなっています。
  • ファイルアップロードの型検出。 $request->file('avatar')->type() は、クライアントが申告した値ではなく、ファイルの実際の内容から判定した MIME タイプを返します。
  • テストしやすい。 動作がインターフェースで定義されているため、ユニットテストでモック実装を注入できます。
  • スーパーグローバルは引き続き利用可能です。 SUPERGLOBALS_ENABLED=false の設定は任意です。オブジェクト API はどちらの場合でも動作します。

Request オブジェクトの取得

php
<?php $request = oxphp_http_request();

oxphp_http_request() は、アクティブな HTTP リクエスト内で実行されているスクリプトのどこからでも、oxphp_worker() のコールバック内を含めて呼び出せます。

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

RequestInterface のメソッド

URI とメソッド

php
$request->method(): string

HTTP メソッドを大文字で返します("GET""POST""PUT""PATCH""DELETE" など)。

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

大文字・小文字を区別しないメソッドチェックです。

php
$request->path(): string

クエリ文字列を含まない URI パスを返します("/users/42")。

php
$request->fullUri(): string

スキーム、ホスト、(標準以外の場合の)ポート、パス、クエリ文字列を含む完全な URI を返します("https://example.com:8080/users/42?page=2")。標準ポート(HTTP は 80、HTTPS は 443)は省略されます。

php
$request->scheme(): string

"https" または "http" を返します。

php
$request->isSecure(): bool

スキームが "https" のとき true を返します。

php
$request->host(): string

Host ヘッダーから取得したホスト名です。ヘッダーが存在しない場合(Host ヘッダーのない HTTP/1.0 リクエストなど)は空文字列を返します。

php
$request->port(): int

Host ヘッダーから取得したポートです。明示的に指定されていない場合は、スキームに応じたデフォルト値(HTTP は 80、HTTPS は 443)を返します。

リバースプロキシの背後で運用する場合

TRUSTED_PROXIES に接続元(peer)が含まれている場合、scheme()isSecure()host()port()X-Forwarded-ProtoX-Forwarded-Host を尊重します。信頼済みプロキシが設定されていない場合は、直接接続の情報を反映します。

php
$request->queryString(): ?string

先頭の ? を含まない生のクエリ文字列です。クエリ文字列がない場合は null を返します。

プロトコル

php
$request->httpProtocol(): string

完全なプロトコル文字列です("HTTP/1.1" または "HTTP/2")。

php
$request->httpProtocolVersion(): string

バージョン番号のみです("1.1" または "2")。

クエリパラメータ

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

クエリ文字列のパラメータにアクセスします。

呼び出し 戻り値
$request->query() すべてのパラメータを配列として返す(ネストされた配列を含む)
$request->query('page') page の値。存在しない場合は null
$request->query('page', 1) page の値。存在しない場合は 1

ブラケット記法(?tags[]=php&tags[]=async)はネストされた配列にパースされます。

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

見つかった値は常に文字列です。キーが存在しない場合、$default はそのまま返されます。

パース済みボディ

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

パースされたリクエストボディを返します。ボディは Content-Type ヘッダーに従ってパースされます。

Content-Type 戻り値
application/x-www-form-urlencoded フィールド値の連想配列
multipart/form-data テキストフィールド値の連想配列
application/json デコードされた配列またはスカラー値。不正な JSON の場合は null
上記以外の値 null

payload() は POST リクエストに限りません。PUT、PATCH をはじめ、ボディを送信するあらゆるメソッドで動作します。パース結果は最初の呼び出し時にキャッシュされ、リクエストのライフタイム全体で再利用されます。

呼び出し 戻り値
$request->payload() パースされたボディ全体
$request->payload('email') 単一のフィールド値。存在しない場合は null
$request->payload('email', '') 単一のフィールド値。存在しない場合は ''
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"]

ヘッダー

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

生のヘッダー値を返します。ヘッダー名は大文字・小文字を区別しません。複数の値を持つヘッダー(AcceptX-Forwarded-For)の場合、ヘッダー行全体が単一の文字列として返されます。パースは呼び出し側の責任です。

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

指定したヘッダーが存在する場合に true を返します。

php
$request->headers(): array

すべてのヘッダーを連想配列として返します。各キーは受信したままのヘッダー名(正規化なし)で、各値は生のヘッダー文字列です。

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

単一の Cookie の値を返します。Cookie が存在しない場合は $default を返します。

php
$request->cookies(): array

すべての Cookie を名前と値のペアの連想配列として返します。

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

生のボディ

php
$request->body(): string

生のリクエストボディのバイト列を返します。これは OxPHP における file_get_contents('php://input') に相当します。payload() とは異なり、body() はキャッシュされません。呼び出しのたびに基盤となるデータ構造にアクセスします。

php
$request->contentType(): ?string

Content-Type ヘッダーの値を返します。存在しない場合は null を返します。

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()payload() は独立しています。同じリクエスト内で両方を呼び出せます。

ファイルアップロード

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

指定したフィールド名のアップロードファイルを返します。フィールドが存在しない場合は null を返します。配列フィールド(name="photos[]")の場合は最初のファイルを返します。

php
$request->files(?string $name = null): array
呼び出し 戻り値
$request->files() すべてのアップロードファイルを UploadedFileInterface のフラットな配列として返す
$request->files('photos') photos フィールドのすべてのファイル(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())); } }

クライアント

php
$request->ip(): string

クライアントの IP アドレスを返します。TRUSTED_PROXIES が設定されていて、リクエストの接続元が信頼済みの集合に含まれる場合、これは X-Forwarded-For または RFC 7239 の Forwarded に含まれる、最も右側の信頼されていないアドレスになります。そうでない場合は直接の接続元 IP であり、通常はエンドクライアントではなくロードバランサーの IP です。

生の X-Forwarded-For ヘッダーは高度なユースケースのために $request->header('X-Forwarded-For') で引き続き利用できますが、手動でパースして正しく処理できることはまれです(最も左か最も右か、CIDR による信頼チェックの欠如など)。代わりに TRUSTED_PROXIES を設定してください。信頼済みプロキシを参照してください。

タイミング

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

このリクエストを受信した時刻の Unix タイムスタンプを返します。

呼び出し 戻り値
$request->startTime() 整数の秒数: 1711234567
$request->startTime(true) 秒未満の精度を持つ浮動小数点数: 1711234567.3412
php
<?php $elapsed = microtime(true) - $request->startTime(true); error_log(sprintf("Request took %.3fs so far", $elapsed));

属性

php
$request->attributes(): AttributesInterface

現在のリクエストのための、変更可能な属性コンテナを返します。属性を使うと、グローバル変数を使わずに、同じリクエスト内のミドルウェア、ルートハンドラー、その他のコード間でデータを共有できます。

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

属性はリクエストごとに管理され、ワーカーモードでは新しいリクエストのたびにリセットされます。ファイバーを使用する場合、属性は同じリクエストに対して同じワーカースレッド上で実行されているすべてのファイバー間で共有されます。PHP のファイバーは協調的(cooperative)であるため、並行アクセスは発生しません。

セッション

php
$request->session(): ?SessionInterface

$_SESSION の読み取り専用ビューを返します。session_start() が呼び出されていない場合は null を返します。セッション管理(開始、保存、破棄、値の書き込み)には標準の 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 はアクティブなセッションの読み取り専用ビューです。

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; }
メソッド 説明
id() セッション ID
name() セッション名(デフォルト: "PHPSESSID"
get(key, default) 単一のセッション値。キーが存在しない場合は $default
has(key) $_SESSION にキーが存在する場合は true
all() すべてのセッションデータを配列として返す

セッションの値は、session() が最初に呼び出された時点の状態ではなく、呼び出し時点の $_SESSION の現在の状態を反映します。

UploadedFileInterface

UploadedFileInterface は単一のアップロードファイルを表します。

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; }
メソッド 説明
name() クライアントが送信した元のファイル名
clientType() クライアントが申告した MIME タイプ — セキュリティ上の判断でこの値を信頼してはいけません
type() マジックバイト検出を用いて、ファイルの実際の内容から判定した MIME タイプ。タイプを判定できない場合は "application/octet-stream" を返します。最初の呼び出し時にキャッシュされます。
size() バイト単位のファイルサイズ
tmpPath() ディスク上の一時ファイルへのパス
error() UPLOAD_ERR_* 定数のいずれか
isValid() error()UPLOAD_ERR_OK のとき true
moveTo(path) ファイルを $path に移動します。移動前に type() を呼び出します。ファイルが無効な場合や移動に失敗した場合は false を返します。

アップロードファイルを使用する前に、必ず isValid() を確認してください。セキュリティに関わる判断を行う際は、clientType() ではなく type() を使用してください。

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 はリクエストオブジェクトの中で唯一変更可能な部分です。認証済みユーザー、解決されたルートパラメータ、ロケール、機能フラグなど、アプリケーションの複数の箇所からアクセスする必要があるリクエストごとのメタデータを格納するためのものです。

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; }
メソッド 説明
get(key, default) $key の値を返す。存在しない場合は $default
set(key, value) 値を格納する
has(key) キーが設定されている場合は true
remove(key) キーを削除する
all() すべての属性を連想配列として返す

例外

アクティブなリクエストコンテキストの外で oxphp_http_request() を呼び出すと、OxPHP\Http\Exception 名前空間の例外がスローされます。

php
namespace OxPHP\Http\Exception; class NoActiveRequestException extends \RuntimeException {} class AsyncContextException extends NoActiveRequestException {} class WorkerIdleException extends NoActiveRequestException {}
例外 スローされるタイミング
NoActiveRequestException アクティブな HTTP リクエストがない場合: CLI、MINIT、シャットダウン後、またはリクエストより長く存続するファイバー
AsyncContextException oxphp_async() コールバックの内部 — 非同期ワーカーはリクエストコンテキストを持たない別のスレッドで実行されます
WorkerIdleException ワーカーモードで、リクエストとリクエストの合間 — ワーカーは次のリクエストを待機しています

AsyncContextExceptionWorkerIdleException はどちらも NoActiveRequestException を継承しているため、基底クラスをキャッチすればすべてのケースを処理できます。

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 }

通常のリクエスト処理コードでは、この try/catch は必要ありません。この例外ガードは、リクエストコンテキストの外で実行される可能性のあるブートストラップコードで役立ちます。

SUPERGLOBALS_ENABLED

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

デフォルトでは、OxPHP は $_GET$_POST$_COOKIE$_FILES$_SERVER を通常どおり設定します。このモードでは、HTTP オブジェクト API がスーパーグローバルと並行して利用できます。

SUPERGLOBALS_ENABLED=false を設定すると、これらの配列は空になり、リクエストごとにそれらを構築するコストがなくなります。以下は、この設定に関係なく引き続き動作します。

機能 SUPERGLOBALS_ENABLED=false のときの動作
oxphp_http_request() 常に利用可能
php://input 利用可能(スーパーグローバルではなくストリームであるため)
$_SESSION 利用可能(PHP のセッションモジュールが管理)
header(), headers_list() 利用可能(SAPI の出力関数)
session_start(), session_*() 利用可能(ネイティブの PHP 関数)
$_GET, $_POST, $_COOKIE, $_FILES, $_SERVER 空の配列

実行時に現在の設定を確認するには oxphp_superglobals_enabled() を使用します。

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

ワーカーモード

ワーカーモードでは、受信したリクエストごとに新しい Request オブジェクトが生成されます。前のリクエストのオブジェクトは、そのリクエストが完了すると無効になります。リクエストとリクエストの間でそのオブジェクトへの参照を保持しないでください。

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

Request オブジェクト上のすべてのキャッシュ(パース済みヘッダー、Cookie、クエリパラメータ、ペイロード)は、次のリクエストが始まると自動的にクリアされます。

IDE サポート

PhpStorm、VS Code、または LSP に対応した任意のエディタで補完と型チェックを利用するには、スタブパッケージをインストールします。

bash
composer require --dev oxphp/stubs

スタブパッケージは以下を提供します。

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

実行時の依存関係は追加されません。このパッケージは require-dev 専用です。

従来モード

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

JSON ボディを伴う POST

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

ミドルウェアの属性

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

セッションを伴うワーカーモード

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

関連項目

  • スーパーグローバル — OxPHP が $_SERVER$_GET$_POST$_COOKIE$_FILES をどのように設定するか
  • PHP 関数oxphp_http_request()oxphp_superglobals_enabled()、その他すべての組み込み関数の完全なリファレンス
  • ワーカーモード — 永続的な PHP プロセスとリクエストのライフサイクル
  • 設定リファレンスSUPERGLOBALS_ENABLED とその他の環境変数