超全局变量
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.10.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 不带 HTTP_ 前缀——分别为 CONTENT_TYPE 和 CONTENT_LENGTH——这是 CGI 规范的要求。
反向代理之后
当配置了 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 的端口部分,否则按 scheme 取 443/80 |
Host 的端口部分,或 443/80 |
原始的 HTTP_X_FORWARDED_FOR、HTTP_X_FORWARDED_PROTO、HTTP_X_FORWARDED_HOST、HTTP_X_FORWARDED_PORT 和 HTTP_FORWARDED 键会原封不动地保留在 $_SERVER 中——重写后的值和原始请求头都可以获取。
在可信代理之后,REMOTE_PORT 为 "0",除非代理发送了 RFC 7239 Forwarded: for=ip:port——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 服务器 span 的 Span ID | 00f067aa0ba902b7 |
OXPHP_PARENT_SPAN_ID |
来自上游服务的父 span ID(若为根则为空) | b9c7c989f97918e1 |
只有在收到有效的 traceparent 请求头,或 OxPHP 生成了一个新的 trace 时,这些变量才会存在。如果未配置追踪,这些键将不存在。
与 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 始终标识被执行的脚本(相对于文档根目录解析出的文件),因此在正常路由下,只有当 SCRIPT_NAME 是请求路径的字面前缀时,PATH_INFO 才存在。当请求被重写到一个它并未指名的前端控制器时(应用路由、目录索引、静态文件未命中回退),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"]$_POST
OxPHP 支持表单提交的两种标准内容类型:
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]"$_COOKIE
Cookie 会从 Cookie 请求头中解析。
<?php
// Request with: Cookie: session=abc123; theme=dark
$session = $_COOKIE['session']; // "abc123"
$theme = $_COOKIE['theme']; // "dark"带有 __oxp_ 前缀的 Cookie 保留给 OxPHP 内部插件使用。它们会在 Cookie 请求头到达 PHP 之前被剥离,不会出现在 $_COOKIE 中。
$_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 合并后的数组,由 PHP 根据 request_order INI 指令构建(默认为 "GP"——先 GET,后 POST)。OxPHP 不会改变这一行为。
<?php
// GET /form?action=preview with POST body: action=submit
$action = $_REQUEST['action']; // "submit" (POST overrides GET with default order)php://input
原始请求体可通过 php://input 流获取。这是读取 JSON 负载(请求体)、XML 或除表单提交之外任何内容类型的标准方式。
<?php
$body = file_get_contents('php://input');
$data = json_decode($body, true);php://input 可倒回(rewindable),在同一请求内可多次读取。
对于 multipart/form-data 请求,php://input 为空。这类请求请使用 $_POST 和 $_FILES。
禁用超全局变量
设置 SUPERGLOBALS_ENABLED=false 可禁用对 $_GET、$_POST、$_COOKIE、$_FILES 和 $_SERVER 的填充。禁用后,这些数组为空。请改用 HTTP 请求 API(oxphp_http_request())来访问请求数据。
SUPERGLOBALS_ENABLED=false # superglobals are empty arrays无论此设置如何,以下内容始终可用:
| 内容 | 原因 |
|---|---|
$_SESSION |
由 PHP 的会话模块管理,而非 SAPI |
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及其他服务器配置变量