スーパーグローバル
OxPHP は、スクリプトが実行される前にすべての標準 PHP スーパーグローバルを設定します。これは、従来のサーバー構成で PHP 開発者が期待する動作と一致します。値はコードの最初の行から利用でき、初期化は不要です。
$_SERVER
OxPHP は、CGI/1.1 仕様に従って、受信した HTTP リクエストから $_SERVER を構築します。まずプロセスの環境変数がインポートされ、その後に CGI 変数が設定されるため、リクエスト固有の値は衝突する環境変数のキーを常に上書きします。
標準変数
| 変数 | 説明 | 例 |
|---|---|---|
SCRIPT_FILENAME |
実行される PHP スクリプトへの絶対ファイルシステムパス | /var/www/html/public/index.php |
DOCUMENT_ROOT |
DOCUMENT_ROOT 環境変数で設定される Web ルートディレクトリ |
/var/www/html/public |
SERVER_SOFTWARE |
サーバー識別子(実行中の OxPHP バージョンを含む) | OxPHP/0.11.0 |
SERVER_PROTOCOL |
ネゴシエートされた HTTP プロトコルバージョン | HTTP/2 |
REQUEST_METHOD |
HTTP メソッド | GET |
REQUEST_URI |
クエリ文字列を含む完全な URI | /app?page=2 |
SCRIPT_NAME |
DOCUMENT_ROOT からの相対パスで表した、実行されるスクリプトのパス。Framework モードではフロントコントローラーであり、リクエスト URI ではありません |
/index.php |
DOCUMENT_URI |
SCRIPT_NAME のエイリアス。nginx/PHP-FPM との互換性のため |
/index.php |
PHP_SELF |
PATH_INFO が存在する場合は SCRIPT_NAME に PATH_INFO を加えたもの。存在しない場合は SCRIPT_NAME と等しくなります |
/index.php/user/42 |
QUERY_STRING |
URI のクエリ部分(存在しない場合は空文字列) | page=2 |
SERVER_NAME |
Host ヘッダーのホスト名 |
example.com |
SERVER_PORT |
Host ヘッダーのポート |
8080 |
REMOTE_ADDR |
クライアントの IP アドレス | 172.17.0.1 |
REMOTE_PORT |
クライアントのポート番号 | 54321 |
HTTPS |
接続が TLS を使用する場合は "on" に設定され、そうでない場合は存在しません |
on |
REQUEST_SCHEME |
TLS 接続の場合は "https"、そうでない場合は "http" |
https |
CONTENT_TYPE |
Content-Type ヘッダーの値(HTTP_ プレフィックスなし) |
application/json |
CONTENT_LENGTH |
Content-Length ヘッダーの値(HTTP_ プレフィックスなし) |
128 |
REQUEST_TIME |
リクエストが開始された Unix タイムスタンプ(整数) | 1738800000 |
REQUEST_TIME_FLOAT |
マイクロ秒精度の Unix タイムスタンプ | 1738800000.123456 |
GATEWAY_INTERFACE |
CGI バージョン文字列 | CGI/1.1 |
Host ヘッダーが存在しない場合、SERVER_NAME はデフォルトで localhost になり、SERVER_PORT はデフォルトで 80(TLS の場合は 443)になります。
HTTP リクエストヘッダー
すべての HTTP リクエストヘッダーは、HTTP_ プレフィックスを付けて $_SERVER に追加されます。ヘッダー名は CGI/1.1 の慣例に従い、大文字に変換され、ダッシュはアンダースコアに置き換えられます。
Accept: text/html -> HTTP_ACCEPT
X-Forwarded-For: 1.2.3.4 -> HTTP_X_FORWARDED_FOR
Authorization: Bearer abc -> HTTP_AUTHORIZATION
Cookie: session=xyz -> HTTP_COOKIEContent-Type と Content-Length は、CGI 仕様の要件に従い、HTTP_ プレフィックスなしで CONTENT_TYPE および CONTENT_LENGTH として現れます。
リバースプロキシの背後
TRUSTED_PROXIES が設定されていて、リクエストのピアが信頼済みセットに含まれる場合、OxPHP は転送ヘッダー(X-Forwarded-* または RFC 7239 の Forwarded)から次の $_SERVER キーを書き換えます。
| 変数 | ピアが信頼済みの場合の値 | それ以外の場合の値 |
|---|---|---|
REMOTE_ADDR |
X-Forwarded-For / Forwarded の最も右側にある信頼されていないアドレス |
直接ピアの IP |
REMOTE_PORT |
Forwarded: for=ip:port から取得したクライアントの送信元ポート、それ以外の場合は 0 |
直接ピアのポート |
HTTPS |
X-Forwarded-Proto: https の場合は "on" |
ピア接続が TLS の場合にのみ設定されます |
REQUEST_SCHEME |
X-Forwarded-Proto から取得した "https" / "http" |
実際の TLS 状態に基づく |
SERVER_NAME |
X-Forwarded-Host のホスト部分 |
Host ヘッダーのホスト部分 |
SERVER_PORT |
X-Forwarded-Port、なければ X-Forwarded-Host のポート部分、なければスキームに応じて 443/80 |
Host のポート部分、または 443/80 |
生の HTTP_X_FORWARDED_FOR、HTTP_X_FORWARDED_PROTO、HTTP_X_FORWARDED_HOST、HTTP_X_FORWARDED_PORT、HTTP_FORWARDED の各キーは $_SERVER にそのまま残ります。書き換えられた値と元のヘッダーの両方が利用できます。
信頼済みプロキシの背後では、プロキシが RFC 7239 の Forwarded: for=ip:port を送信しない限り、REMOTE_PORT は "0" になります。X-Forwarded-For も最も右側の信頼されていないものを選択する方式も、クライアントの送信元ポートを持たないため、合成される値は推測されるのではなくゼロにされます。
TRUSTED_PROXIES が設定されていない場合、書き換えは行われず、REMOTE_ADDR は常に直接ピア、つまり通常はエンドクライアントではなくロードバランサーになります。X-Forwarded-For を手動で解析するのはエラーが起きやすく(左端か右端か、CIDR の信頼チェックがないなど)、TRUSTED_PROXIES を設定することをお勧めします。信頼アルゴリズムと設定構文については、信頼済みプロキシを参照してください。
トレースコンテキスト変数
分散トレーシングが有効な場合、OxPHP は $_SERVER にトレースコンテキスト変数を追加します。
| 変数 | 説明 | 例 |
|---|---|---|
OXPHP_TRACE_ID |
現在のリクエストの W3C トレース ID | 4bf92f3577b34da6a3ce929d0e0e4736 |
OXPHP_SPAN_ID |
OxPHP サーバースパンのスパン ID | 00f067aa0ba902b7 |
OXPHP_PARENT_SPAN_ID |
アップストリームサービスからの親スパン ID(ルートの場合は空) | b9c7c989f97918e1 |
これらの変数は、有効な traceparent ヘッダーが届いた場合、または OxPHP が新しいトレースを生成した場合にのみ存在します。トレーシングが設定されていない場合、これらのキーは存在しません。
PHP-FPM との違い
次の変数は、標準的な PHP-FPM の構成と比べて動作が異なります。
| 変数 | 動作 |
|---|---|
SERVER_ADDR |
設定されません。OxPHP はローカルサーバーの IP アドレスを設定しません。 |
PATH_INFO |
自動的に設定されます。下記の PATH_INFO の動作を参照してください。 |
PATH_TRANSLATED |
設定されません。 |
PHP_AUTH_USER / PHP_AUTH_PW / AUTH_TYPE |
Authorization ヘッダーからは抽出されません。$_SERVER['HTTP_AUTHORIZATION'] を直接読み取ってください。 |
REDIRECT_STATUS |
設定されません。OxPHP は内部リダイレクト機構を使用しません。 |
例
<?php
$method = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];
$ip = $_SERVER['REMOTE_ADDR'];
$host = $_SERVER['SERVER_NAME'];
$scheme = $_SERVER['REQUEST_SCHEME']; // "http" or "https"
// Read a custom header
$token = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
// REMOTE_ADDR is already the real client IP when TRUSTED_PROXIES is configured.
// Without it, REMOTE_ADDR is the direct peer (usually a load balancer).
$clientIp = $_SERVER['REMOTE_ADDR'];
// Check TLS without checking the port
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
// Secure connection
}PATH_INFO の動作
$_SERVER['PATH_INFO'] は、有効なルーティングモードに基づいて自動的に設定されます。フィーチャーフラグはありません。以前の SPLIT_PATH_INFO_ENABLED 環境変数は削除されました。
| ルーティングモード | 設定されるタイミング | 値 |
|---|---|---|
Traditional(ENTRY_FILE 未設定) |
URI に .php/ が含まれ、スクリプトプレフィックスがディスク上に存在する場合のみ |
スクリプトセグメントより後ろの末尾部分 |
Framework(ENTRY_FILE=index.php) |
リクエストが末尾セグメント付きでエントリーファイルを明示的に指定した場合のみ(/index.php/extra) |
エントリーファイルより後ろの末尾部分、例: /news |
SPA(ENTRY_FILE=index.html) |
設定されません。PHP は正確な .php ファイルに対してのみ実行され、PATH_INFO はありません |
— |
SCRIPT_NAME は常に実行されるスクリプト(ドキュメントルートからの相対で解決されたファイル)を指すため、通常のルーティングでは PATH_INFO は SCRIPT_NAME がリクエストパスの文字どおりのプレフィックスである場合にのみ存在します。リクエストが、それ自体では指定していないフロントコントローラーに書き換えられる場合(アプリケーションルート、ディレクトリインデックス、静的ファイルのミス時のフォールバック)、PATH_INFO は存在せず、元のパスは REQUEST_URI に格納されます。(PHP_DENY_PATHS のフォールバックは意図的な例外です。フォールバックスクリプトがルーティングに使えるよう、PATH_INFO を元のサニタイズ済み URI に設定します。)
Traditional モードの例
OxPHP は URI を左から右へスキャンし、ディスク上の実際のファイルに対応する最初の .php セグメントを探します。それより後ろのすべてが PATH_INFO になります。
| リクエスト URI | ディスク上のファイル | SCRIPT_NAME |
PATH_INFO |
PHP_SELF |
|---|---|---|---|---|
/app.php/user/42 |
app.php が存在 |
/app.php |
/user/42 |
/app.php/user/42 |
/index.php/api/v2/users |
index.php が存在 |
/index.php |
/api/v2/users |
/index.php/api/v2/users |
/app.php |
app.php が存在 |
/app.php |
(なし) | /app.php |
/missing.php/foo |
ファイルが見つからない | /index.php にフォールバック |
— | フォールバックに依存 |
Framework モードの例
静的ファイル以外のすべてのリクエストは index.php に書き換えられます。PATH_INFO は、リクエストが末尾セグメント付きでエントリーファイルを明示的に指定した場合にのみ設定されます。アプリケーションルートの場合、元のパスは REQUEST_URI から読み取られます。
| リクエスト URI | SCRIPT_NAME |
PATH_INFO |
|---|---|---|
/api/users |
/index.php |
(なし) |
/about.php |
/index.php |
(なし) |
/index.php/news/local |
/index.php |
/news/local |
/index.php |
/index.php |
(なし) |
PATH_TRANSLATED は設定されません。これは実際にはほとんど使われず、nginx や PHP-FPM でもデフォルトでは設定されません。
$_GET
クエリ文字列パラメーターは、リクエスト URI から自動的に解析されます。
<?php
// Request: GET /search?q=oxphp&page=2
$query = $_GET['q']; // "oxphp"
$page = $_GET['page']; // "2"配列構文も期待どおりに動作します。
<?php
// Request: GET /filter?tags[]=php&tags[]=async
$tags = $_GET['tags']; // ["php", "async"]filter_input()、filter_input_array()、filter_has_var() は $_GET、$_POST、$_COOKIE を読みません。filter 拡張はパース済み入力の独自のコピーを保持しており、永続的なワーカーではそのコピーはすべてのリクエストによって埋められます — したがって、すべてのリクエストによって返却もされなければなりません。さもないと、あるクライアントのクエリ値、セッション Cookie、ボディのフィールドが、そのワーカーが以降に処理するすべてのリクエストから読めたままになってしまいます。OxPHP は各リクエストの開始時にこれを返却するため、これら 3 つの関数は、問い合わせているリクエストのためだけに答え、他のリクエストのためには答えません。
ワーカーモードは 1 つの制限を加えます。リクエストが一時停止し(sleep()、await、フックされた呼び出し)、その間に別のリクエストがそのワーカーで実行されると、ストレージはそのリクエストのものになります。再開後の読み取りは、他人の入力ではなく null を返し、自分のリクエストが持っていたコピーはその時点で失われています。別のリクエストがそこで開始または再開するだけで十分であり、完了する必要はありません。$_GET、$_POST、$_COOKIE は中断をまたいでリクエストと共に移動するため影響を受けません。したがって、それらを読むか、中断する前に filter 関数を読んでください。
1 つの呼び出しだけは、一時停止そのものが許されません。フィールドごとの定義配列を渡された filter_input_array() はフィールドごとに 1 回ストレージを読むため、I/O を行う FILTER_CALLBACK は、ワーカーを別のリクエストへ渡す代わりに、その間ワーカーを占有したまま実行されます。また、そのようなコールバック内での明示的な Fiber::suspend() はスローします。待機自体はなくなりません — リクエストではなくワーカースレッドが待つのです — ので、遅いコールバックはその後ろに並んでいるすべてのものにとってのレイテンシとして現れ、QUEUE_WAIT_TIMEOUT_MS を過ぎると、それらのキュー内リクエストは切り捨てられます。それがどれだけ続きうるかを決めるのは、サーバーではなくコールバックの通信相手です。ストリームラッパーは default_socket_timeout(初期設定で 60 秒)で諦めますが、mysqlnd は mysqlnd.net_read_timeout(初期設定で 1 日)待ちます。そのような呼び出しには明示的なタイムアウトを与えてください — あるいは、より良いのは、データベースやキャッシュに到達するバリデーションを、filter_input_array() が値を返した後にその値に対して実行することです。
$_POST
OxPHP は、フォーム送信用の 2 つの標準的なコンテンツタイプをサポートします。
application/x-www-form-urlencoded— 標準的な HTML フォームデータmultipart/form-data— フォームフィールドと組み合わせたファイルアップロード
<?php
// Request: POST /login
// Content-Type: application/x-www-form-urlencoded
// Body: username=admin&password=secret
$username = $_POST['username']; // "admin"
$password = $_POST['password']; // "secret"JSON やその他のコンテンツタイプの場合は、代わりに php://input を使用してください。
<?php
// Request: POST /api/users
// Content-Type: application/json
// Body: {"name":"Alice","email":"[email protected]"}
$data = json_decode(file_get_contents('php://input'), true);
$name = $data['name']; // "Alice"
$email = $data['email']; // "[email protected]"filter_input(INPUT_POST, …) は $_POST ではなく、filter 拡張が持つボディの独自のコピーを読みます — そのコピーが何であり、どれだけ存続するかについては $_GET の下の注記を参照してください。
$_COOKIE
Cookie は、Cookie リクエストヘッダーから解析されます。
<?php
// Request with: Cookie: session=abc123; theme=dark
$session = $_COOKIE['session']; // "abc123"
$theme = $_COOKIE['theme']; // "dark"__oxp_ プレフィックスの付いた Cookie は、OxPHP の内部プラグイン用に予約されています。これらは PHP に到達する前に Cookie ヘッダーから取り除かれ、$_COOKIE には現れません。
filter_input(INPUT_COOKIE, …) は $_COOKIE ではなく、filter 拡張が持つ Cookie の独自のコピーを読みます — そのコピーが何であり、どれだけ存続するかについては $_GET の下の注記を参照してください。
$_FILES
multipart/form-data で送信されたファイルアップロードは、標準の PHP 構造で $_FILES 配列を設定します。
<?php
// $_FILES['avatar'] structure:
// [
// 'name' => 'photo.jpg', // Original filename sent by the client
// 'type' => 'image/jpeg', // MIME type declared by the client
// 'tmp_name' => '/tmp/phpAb12Cd', // Temporary file path on the server
// 'error' => 0, // UPLOAD_ERR_OK (0 means no error)
// 'size' => 204800, // File size in bytes
// ]
if ($_FILES['avatar']['error'] === UPLOAD_ERR_OK) {
$tmp = $_FILES['avatar']['tmp_name'];
$name = basename($_FILES['avatar']['name']);
move_uploaded_file($tmp, "/uploads/$name");
}$_REQUEST
$_REQUEST は、$_GET、$_POST、そして場合によっては $_COOKIE をマージした配列で、request_order INI ディレクティブ(デフォルト: "GP" — GET、次に POST)に従って PHP が構築します。マージ自体は PHP のルールに従い、変更されません。
<?php
// GET /form?action=preview with POST body: action=submit
$action = $_REQUEST['action']; // "submit" (POST overrides GET with default order)$_REQUEST はリクエストごとに再構築されます。PHP は通常、これを言及するスクリプトが最初に読み込まれたときに一度だけ遅延構築します — 永続的なワーカーでは、それは以降のすべてのリクエストが最初のリクエストのパラメータを読むことを意味してしまいます。OxPHP は代わりに再構築を強制するため、マージされた配列は常に処理中のリクエストを記述します。
$_ENV
$_ENV はプロセス環境を保持します。従来モードでは PHP-FPM とまったく同じように振る舞います。PHP は variables_order に従い、リクエストごとに環境から再投入します。
ワーカーモードはこれを固定します。 ワーカーは一度だけブートストラップし、.env ローダー(vlucas/phpdotenv、symfony/dotenv、Laravel の Env)はプロセス環境に触れることなく、その値を $_ENV へ直接書き込みます。したがって $_ENV をリクエストごとに再投入すると、2 番目のリクエスト以降でアプリケーションの設定が消されてしまいます。そのためワーカーモードでは、この配列は一度存在すればワーカーの生存期間を通じて保持され、ブートストラップがそこに書き込んだものは、そのワーカーが処理するすべてのリクエストから見えたままになります。
<?php
// bootstrap, before oxphp_worker()
Dotenv\Dotenv::createImmutable(__DIR__)->load(); // writes into $_ENV
oxphp_worker(function () {
echo $_ENV['DATABASE_URL']; // still there on request 10_000
});filter_input(INPUT_ENV, …)、filter_input_array(INPUT_ENV)、filter_has_var(INPUT_ENV, …) は、ワーカーモードではプロセス環境を読みます。$_ENV を読むわけではないため、ブートストラップがそこへ書き込んだ値はその中に含まれません。これは PHP がどこでも示す挙動です。$_ENV への書き込みはその配列に独自のコピーを持たせる一方、filter 拡張はエンジンが取得した環境のスナップショットを読み続けるからです。ワーカーモードはひとつのひねりを加えます。そのスナップショットは、ワーカー上で $_ENV が最初に構築されたときに取られたものであるため、その後に行われた putenv() の呼び出しもその中にはありません。getenv() は生きた環境を読むため影響を受けません。$_ENV はプロセスの値に加えてブートストラップが追加したものを保持します。これらはすべて INPUT_ENV だけの話です。INPUT_GET、INPUT_POST、INPUT_COOKIE は、上の $_GET の下の注記で説明した、filter 拡張内部の独自のストレージを読みます。
この固定は PHP のデフォルトである auto_globals_jit=1 に依存しています。auto_globals_jit=0 の場合、PHP はどの拡張も介入できないうちに、リクエストごとに $_ENV をプロセス環境から再投入するため、.env ローダーの値はワーカーモードで生き残りません。
php://input
生のリクエストボディは、php://input ストリームを通じて利用できます。これは、JSON ペイロード、XML、またはフォーム送信以外のあらゆるコンテンツタイプを読み取るための標準的な方法です。
<?php
$body = file_get_contents('php://input');
$data = json_decode($body, true);php://input は巻き戻し可能で、同じリクエスト内で複数回読み取ることができます。
php://input は multipart/form-data リクエストでは空です。その場合は $_POST と $_FILES を使用してください。
スーパーグローバルの無効化
SUPERGLOBALS_ENABLED=false を設定すると、$_GET、$_POST、$_COOKIE、$_FILES、$_SERVER の設定が無効になります。無効にすると、これらの配列は空になります。代わりに HTTP リクエスト API(oxphp_http_request())を使用して、リクエストデータにアクセスしてください。
SUPERGLOBALS_ENABLED=false # superglobals are empty arrays次のものは、この設定に関係なく利用可能なままです。
| 対象 | 理由 |
|---|---|
$_SESSION |
SAPI ではなく、PHP のセッションモジュールによって管理されます |
php://input |
スーパーグローバルではなく、ストリームです |
header()、headers_list() など |
スーパーグローバルではなく、SAPI 関数です |
session_start() およびその他の session_*() 関数 |
ネイティブの PHP 関数です |
oxphp_http_request() |
常に利用可能 — 推奨される代替手段です |
現在の設定は実行時に確認できます。
if (!oxphp_superglobals_enabled()) {
$request = oxphp_http_request();
$page = $request->query('page', 1);
}関連情報
- HTTP リクエスト API -- スーパーグローバルの代替となる、型付きで遅延ロードされるリクエストオブジェクト
- PHP 関数 --
oxphp_request_id()、oxphp_worker_id()、その他の拡張関数 - ワーカーモード -- ワーカーのリクエスト間でスーパーグローバルがどのように更新されるか
- 設定リファレンス --
DOCUMENT_ROOTおよびその他のサーバー設定変数