主题
超全局变量
超全局变量(superglobals)是 PHP 预先准备好的数组,在脚本任何地方都能直接用,包括函数内部,不必写 global。它们用来读取请求参数、服务器信息和会话数据。
变量定义 里提过:跨函数共享优先用参数和返回值;和「当前这次 HTTP 请求」相关的数据,则从超全局里读。作用域的完整规则见 变量的作用域。
先看 $_GET。用内置服务器才能在浏览器里试(终端直接 php 文件.php 时,查询参数是空的):
sh
php -S localhost:8000浏览器打开 http://localhost:8000/hello.php?name=小明,对应脚本:
php
<?php
$name = $_GET["name"] ?? "游客";
echo "你好,", htmlspecialchars($name, ENT_QUOTES, "UTF-8"), "\n";一览
| 变量 | 来源 | 典型用途 |
|---|---|---|
$_GET | URL 查询字符串 | ?name=小明 这类参数 |
$_POST | 请求体(表单 POST) | 登录、提交表单 |
$_REQUEST | GET + POST + Cookie 的混合 | 不推荐,来源含糊 |
$_SERVER | 服务器 / 请求元数据 | 路径、方法、Host |
$_COOKIE | 浏览器 Cookie | 记住偏好(非敏感) |
$_SESSION | 服务器上的会话 | 登录状态 |
$_FILES | 上传的文件 | 头像、附件 |
$_ENV | 环境变量 | 配置、密钥(更推荐 getenv) |
$GLOBALS | 所有全局变量 | 调试用,业务代码少用 |
它们都是关联数组,读写规则和 数组 相同:缺键用 ??,调试用 var_dump() / print_r()。
先分清:命令行还是浏览器
| 运行方式 | $_GET / $_POST | 适合练什么 |
|---|---|---|
php 文件.php | 一般是空数组 | 语法、数组、循环 |
php -S localhost:8000 再访问 URL | 有真实请求数据 | 超全局、表单 |
下面涉及 URL、表单的例子,都默认你已在项目目录执行 php -S localhost:8000。
$_GET
URL 里 ? 后面的键值对会进 $_GET。多个参数用 & 连接:
http://localhost:8000/search.php?q=php&page=2php
<?php
$q = $_GET["q"] ?? "";
$page = (int) ($_GET["page"] ?? 1);
echo "关键词:", htmlspecialchars($q, ENT_QUOTES, "UTF-8"), "\n";
echo "页码:", $page, "\n";注意:
- 值永远是字符串(缺省时你自己给的整数除外)。需要数字请显式转换,如
(int) - 会出现在地址栏、浏览器历史、服务器日志里,不要放密码
- 键不存在时 PHP 8 会 Warning,所以用
??,不要直接写$_GET["q"]
$_POST
HTML 表单 method="post" 提交的字段进 $_POST,不会出现在 URL 里,适合登录、留言、改数据。
form.php:
php
<?php
$username = $_POST["username"] ?? "";
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>登录练习</title>
</head>
<body>
<?php if ($username !== ""): ?>
<p>你好,<?= htmlspecialchars($username, ENT_QUOTES, "UTF-8") ?></p>
<?php endif; ?>
<form method="post" action="">
<label>用户名 <input name="username"></label>
<button type="submit">提交</button>
</form>
</body>
</html>要点:
- 表单控件的
name才是$_POST的键,和id无关 action=""表示提交到当前页面;也可以写成另一个 PHP 文件- 同样是字符串;没勾选的 checkbox 不会出现在
$_POST里 - 刷新页面可能重复提交 POST,正式项目会用「处理完再跳转」(PRG)。练习阶段知道有这回事即可
GET 和 POST 都能传参,选择上:
| GET | POST | |
|---|---|---|
| 出现在 URL | 是 | 否 |
| 可被收藏、分享 | 是 | 否 |
| 适合 | 搜索、筛选、分页 | 登录、写入、敏感字段 |
| 长度 | 受 URL 限制 | 可更大(仍有服务器限制) |
输出前一定要转义
超全局里的值来自用户,不可信任。塞进 HTML 前用 htmlspecialchars,否则别人可以注入脚本(XSS):
php
<?php
$name = $_GET["name"] ?? "";
echo htmlspecialchars($name, ENT_QUOTES, "UTF-8");命令行 echo 练习可以不转义;只要进浏览器页面,就转义。
$_REQUEST
$_REQUEST 混合了 GET、POST、Cookie,具体谁覆盖谁取决于 php.ini 的 request_order。同一个键可能来自三种地方,读代码时看不出来。
php
<?php
// 不推荐
$id = $_REQUEST["id"] ?? "";本指南不用 $_REQUEST。要 URL 参数就 $_GET,要表单就 $_POST,来源写明白。
$_SERVER
请求和服务器的元数据。常用键:
| 键 | 含义 | 例子 |
|---|---|---|
REQUEST_METHOD | HTTP 方法 | GET、POST |
REQUEST_URI | 路径 + 查询字符串 | /hello.php?name=小明 |
SCRIPT_NAME | 当前脚本路径 | /hello.php |
QUERY_STRING | ? 后面那一段 | name=小明 |
HTTP_HOST | 主机名 | localhost:8000 |
HTTP_USER_AGENT | 浏览器标识 | 各异 |
REMOTE_ADDR | 客户端 IP | 代理后可能不真实 |
SERVER_NAME | 服务器配置的主机名 | localhost |
HTTPS | 是否 HTTPS | 有时是 "on",有时不存在 |
php
<?php
$method = $_SERVER["REQUEST_METHOD"] ?? "GET";
if ($method === "POST") {
echo "这是 POST 提交\n";
} else {
echo "这是 ", htmlspecialchars($method, ENT_QUOTES, "UTF-8"), " 请求\n";
}不同 SAPI(内置服务器、Apache、Nginx+php-fpm、CLI)下,部分键可能缺失或值不同。读之前同样用 ??。
不要用 HTTP_USER_AGENT 当安全依据,它可以被随便伪造。
$_COOKIE
Cookie 是浏览器存的一小段数据,之后每次请求都会带上。读取用 $_COOKIE,设置要用 setcookie(),不能只写 $_COOKIE["k"] = ...(那样只改当前请求内存里的数组,不会送到浏览器)。
php
<?php
setcookie("theme", "dark", [
"expires" => time() + 86400 * 30,
"path" => "/",
"httponly" => true,
"samesite" => "Lax",
]);
$theme = $_COOKIE["theme"] ?? "light";
echo htmlspecialchars($theme, ENT_QUOTES, "UTF-8"), "\n";注意:
- 本次
setcookie之后,下一次请求才能在$_COOKIE里看到新值 - 不要把密码、令牌明文放进普通 Cookie;登录状态用 Session
httponly让 JS 读不到,能减轻 XSS 偷 Cookie 的风险
$_SESSION
Session 把数据存在服务器,浏览器只拿一个会话 ID(通常在 Cookie 里)。适合登录用户 ID、购物车等。
必须在输出 HTML 之前调用 session_start():
php
<?php
session_start();
$_SESSION["user"] = "小明";
$_SESSION["count"] = ($_SESSION["count"] ?? 0) + 1;
echo "你好,", htmlspecialchars($_SESSION["user"], ENT_QUOTES, "UTF-8"), "\n";
echo "这是第 ", $_SESSION["count"], " 次访问\n";注销某一项:unset($_SESSION["user"]);
整段会话作废:session_destroy();(还要清 Cookie,正式登出会一起做)。
$_SESSION 在 session_start() 之前不存在可用状态。有输出(包括 BOM、空行)再 session_start() 会失败,所以 <?php 从文件第一字节开始,前面不要空行。
$_FILES
表单加 enctype="multipart/form-data" 且有 <input type="file"> 时,文件信息在 $_FILES,不在 $_POST。
html
<form method="post" enctype="multipart/form-data">
<input type="file" name="avatar">
<button type="submit">上传</button>
</form>php
<?php
if (($_SERVER["REQUEST_METHOD"] ?? "") === "POST") {
$file = $_FILES["avatar"] ?? null;
if ($file && ($file["error"] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_OK) {
$tmp = $file["tmp_name"];
$name = basename($file["name"]);
// 正式环境要检查大小、MIME、扩展名,并换一个随机文件名
echo htmlspecialchars($name, ENT_QUOTES, "UTF-8"), " 已传到临时目录\n";
}
}每个文件是一个小数组,常见键:
| 键 | 含义 |
|---|---|
name | 用户本机文件名(不可信) |
type | 浏览器声称的 MIME(不可信) |
tmp_name | 服务器上的临时路径 |
error | 错误码,UPLOAD_ERR_OK 表示成功 |
size | 字节数 |
保存时用 move_uploaded_file($tmp, $dest),不要 copy 普通路径。文件上传涉及类型伪造和目录穿越,练习阶段先看懂结构;上线前必须做白名单校验。
$GLOBALS
$GLOBALS 的键是当前全局作用域里的变量名,值是那个变量。超全局自己也会出现在里面。
php
<?php
$site = "PHP Guide";
function show(): void
{
echo $GLOBALS["site"], "\n";
}
show();能用,但会让函数偷偷依赖外部变量,难以测试。本指南函数里仍优先传参;$GLOBALS 留给调试或极少数引导代码。
在函数里写 global $site; 和读 $GLOBALS["site"] 是同一类做法,效果类似,都不作为默认风格。
$_ENV
环境变量。是否自动填进 $_ENV 取决于 php.ini 的 variables_order 里有没有 E,所以同一段代码在不同机器上可能是空的。
读取更稳妥的方式:
php
<?php
$appEnv = getenv("APP_ENV") ?: "local";
echo $appEnv, "\n";PHP 8.2+ 也可用 $_SERVER 里部分环境键,但仍不统一。密钥、数据库密码放环境变量,不要写进仓库、不要塞进 $_GET。
安全要点(先记这几条)
- 所有超全局输入都不可信,输出到 HTML 用
htmlspecialchars - 做数字、枚举时先约束:
(int)、match、白名单,不要直接拿来拼 SQL 或文件路径 - 密码走 POST + HTTPS;不要放进 GET、日志、Cookie 明文
- 不用
$_REQUEST;不用用户输入当文件路径或回调函数名 - Session 必须先
session_start();登录状态放 Session,不放普通 Cookie 明文
过滤可以用 filter_input,和手动 $_GET["id"] ?? "" 再转换是同一思路:
php
<?php
$id = filter_input(INPUT_GET, "id", FILTER_VALIDATE_INT);
if ($id === false || $id === null) {
echo "id 无效\n";
} else {
echo $id, "\n";
}初学先掌握 ?? + 显式转换 + 转义,再逐步换成过滤器。
书写建议
- 缺键一律
??,PHP 8 直接取会 Warning - GET 做读和筛选,POST 做提交;两者不要混在一个键上靠
$_REQUEST兜 - 进 HTML 的值全部转义;进整数运算的值先
(int) var_dump($_GET)、var_dump($_SERVER)是最好的老师,但不要把 dump 留在正式页面上- 函数需要请求数据时,在入口取出、校验,再当普通参数传入,不要在深层函数里直接摸
$_GET
练习
- 写
greet.php,用$_GET["name"]打问候;没传name时显示「游客」。用内置服务器访问带参数和不带参数的 URL。 - 写一个 POST 表单,提交
title和content,在同一页转义后显示出来。 var_dump当前请求的REQUEST_METHOD、REQUEST_URI、SCRIPT_NAME,对照地址栏理解每个键。- 用 Session 做访问计数:每刷新一次加 1 并显示;想一想为什么关掉浏览器再打开,有的环境会计数还在(会话 Cookie 未过期)。