Skip to content

超全局变量

超全局变量(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";

一览

变量来源典型用途
$_GETURL 查询字符串?name=小明 这类参数
$_POST请求体(表单 POST)登录、提交表单
$_REQUESTGET + 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=2
php
<?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 都能传参,选择上:

GETPOST
出现在 URL
可被收藏、分享
适合搜索、筛选、分页登录、写入、敏感字段
长度受 URL 限制可更大(仍有服务器限制)

输出前一定要转义

超全局里的值来自用户,不可信任。塞进 HTML 前用 htmlspecialchars,否则别人可以注入脚本(XSS):

php
<?php

$name = $_GET["name"] ?? "";
echo htmlspecialchars($name, ENT_QUOTES, "UTF-8");

命令行 echo 练习可以不转义;只要进浏览器页面,就转义。

$_REQUEST

$_REQUEST 混合了 GET、POST、Cookie,具体谁覆盖谁取决于 php.inirequest_order。同一个键可能来自三种地方,读代码时看不出来。

php
<?php

// 不推荐
$id = $_REQUEST["id"] ?? "";

本指南不用 $_REQUEST。要 URL 参数就 $_GET,要表单就 $_POST,来源写明白。

$_SERVER

请求和服务器的元数据。常用键:

含义例子
REQUEST_METHODHTTP 方法GETPOST
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设置要用 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,正式登出会一起做)。

$_SESSIONsession_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.inivariables_order 里有没有 E,所以同一段代码在不同机器上可能是空的

读取更稳妥的方式:

php
<?php

$appEnv = getenv("APP_ENV") ?: "local";
echo $appEnv, "\n";

PHP 8.2+ 也可用 $_SERVER 里部分环境键,但仍不统一。密钥、数据库密码放环境变量,不要写进仓库、不要塞进 $_GET

安全要点(先记这几条)

  1. 所有超全局输入都不可信,输出到 HTML 用 htmlspecialchars
  2. 做数字、枚举时先约束:(int)match、白名单,不要直接拿来拼 SQL 或文件路径
  3. 密码走 POST + HTTPS;不要放进 GET、日志、Cookie 明文
  4. 不用 $_REQUEST;不用用户输入当文件路径或回调函数名
  5. 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

练习

  1. greet.php,用 $_GET["name"] 打问候;没传 name 时显示「游客」。用内置服务器访问带参数和不带参数的 URL。
  2. 写一个 POST 表单,提交 titlecontent,在同一页转义后显示出来。
  3. var_dump 当前请求的 REQUEST_METHODREQUEST_URISCRIPT_NAME,对照地址栏理解每个键。
  4. 用 Session 做访问计数:每刷新一次加 1 并显示;想一想为什么关掉浏览器再打开,有的环境会计数还在(会话 Cookie 未过期)。

上一篇:数组运算符
下一篇:变量的作用域

基于 VitePress 构建的 PHP 基础学习指南