PHP 表单处理

这是 PHP 真正的杀手锏。处理 HTTP 表单是 PHP 设计的初衷之一——内置 $_GET$_POST$_REQUEST 超全局变量,无需任何框架就能接收、验证、处理用户提交的数据。这一章是 PHP Web 开发的入门关键。

1. HTTP 请求方法:GET 与 POST

提交表单主要有两种 HTTP 方法,选哪种取决于数据的性质和用途:

GET vs POST:

GET
- 数据在 URL:?name=xiaoming&age=25
- 长度限制(浏览器约 2KB)
- 可收藏、可分享(URL 包含全部参数)
- 不安全(密码会出现在 URL 和日志里)
- 幂等:重复提交结果相同(适合查询)
- 典型:搜索、筛选、分页

POST
- 数据在请求体
- 无长度限制(理论上)
- 不可收藏(URL 不含数据)
- 相对安全(不会出现在 URL)
- 非幂等:重复提交会产生多次结果
- 典型:登录、注册、提交订单、上传文件

2. 接收数据:$_GET / $_POST

PHP 把表单数据自动放到超全局数组里,直接读就行:

<?php
// GET:数据放在 URL 查询字符串里
// 访问 page.php?name=xiaoming&age=25
echo $_GET["name"];          // xiaoming
echo $_GET["age"];           // 25

// POST:数据放在 HTTP 请求体里(不在 URL 显示)
echo $_POST["username"];
echo $_POST["password"];

// $_REQUEST = $_GET + $_POST + $_COOKIE(少用,有歧义)

// 用 ?? 提供默认值,避免未定义警告
$name = $_GET["name"] ?? "匿名";

// REQUEST_METHOD 判断请求类型
if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // 处理表单提交
    $name = trim($_POST["name"] ?? "");
}

几个关键点:

3. 完整表单处理流程

一个完整的表单处理包含 取值 → 验证 → 显示错误 → 粘性 四步。下面是注册表单的完整示例:

<?php
// 处理注册表单(完整示例)
$errors = [];
$name = $email = "";

if ($_SERVER["REQUEST_METHOD"] === "POST") {
    // 1. 取值 + trim + 默认值
    $name = trim($_POST["name"] ?? "");
    $email = trim($_POST["email"] ?? "");

    // 2. 验证
    if ($name === "") {
        $errors[] = "姓名不能为空";
    } elseif (mb_strlen($name) > 50) {
        $errors[] = "姓名不能超过 50 字";
    }

    if ($email === "") {
        $errors[] = "邮箱不能为空";
    } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = "邮箱格式不正确";
    }

    // 3. 通过验证则处理
    if (empty($errors)) {
        // 写入数据库、发邮件、跳转...
        header("Location: /success.php");
        exit;
    }
}
?>
<form method="post">
    <p>
        姓名: <input type="text" name="name"
               value="<?= htmlspecialchars($name) ?>">
    </p>
    <p>
        邮箱: <input type="email" name="email"
               value="<?= htmlspecialchars($email) ?>">
    </p>
    <?php foreach ($errors as $e): ?>
        <p style="color:red"><?= htmlspecialchars($e) ?></p>
    <?php endforeach; ?>
    <button type="submit">注册</button>
</form>

注意几个防御性写法:

4. filter_var / filter_input:内置过滤器

PHP 内置了强大的过滤器,比手写正则更可靠:

<?php
// filter_input:从指定来源取并过滤
// 来源:INPUT_GET / INPUT_POST / INPUT_COOKIE / INPUT_SERVER
$name = filter_input(INPUT_POST, "name", FILTER_SANITIZE_FULL_SPECIAL_CHARS);
$age  = filter_input(INPUT_POST, "age", FILTER_VALIDATE_INT);

// filter_var:过滤已有变量
$email = "test@example.com";
if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
    echo "邮箱合法";
}

// 常用过滤器
filter_var($url, FILTER_VALIDATE_URL);        // 验证 URL
filter_var($ip, FILTER_VALIDATE_IP);          // 验证 IP
filter_var($s, FILTER_SANITIZE_FULL_SPECIAL_CHARS); // 转义特殊字符
filter_var($i, FILTER_VALIDATE_INT, ["min_range" => 0, "max_range" => 150]);

// 验证整数范围
$age = filter_input(INPUT_POST, "age", FILTER_VALIDATE_INT, [
    "options" => ["min_range" => 0, "max_range" => 150]
]);

优先用 filter_var,不要手写正则。原因:正则容易写漏、性能差;filter_var 用 C 实现,经过充分测试,而且语义清晰。

5. 粘性表单(Sticky Form)

"粘性"指表单提交失败后,用户已填的数据保留。这是好的用户体验,新手常忽略:

<?php
// "粘性表单":提交失败时保留用户已输入的数据
// 提升用户体验,避免重新填写所有字段

$selected = $_POST["city"] ?? "";
?>
<select name="city">
    <option value="bj" <?= $selected === "bj" ? "selected" : "" ?>>北京</option>
    <option value="sh" <?= $selected === "sh" ? "selected" : "" ?>>上海</option>
    <option value="gz" <?= $selected === "gz" ? "selected" : "" ?>>广州</option>
</select>

<?php
// 多选 checkbox
$hobbies = $_POST["hobbies"] ?? [];
?>
<label>
    <input type="checkbox" name="hobbies[]" value="read"
        <?= in_array("read", $hobbies) ? "checked" : "" ?>> 阅读
</label>

几个常用技巧:

6. 安全:三道防线

"永远不要相信用户输入"——这是 Web 安全的第一定律。下面是 PHP 表单的三大防御:

<?php
// 永远不要相信用户输入!三大防御:

// 1. htmlspecialchars:输出到 HTML 时转义,防 XSS
echo htmlspecialchars($userInput);
// <script> 变 &lt;script&gt;,浏览器不再执行

// 2. strip_tags:去掉 HTML 标签
$plain = strip_tags($dirtyHtml);

// 3. 数据库用 PDO 预处理(第 14 章),永远不要拼接 SQL

// 4. CSRF 防护(表单加 token,第 12/16 章会讲)
session_start();
$token = bin2hex(random_bytes(32));
$_SESSION["csrf_token"] = $token;
// 表单里:<input type="hidden" name="csrf" value="<?= $token">

7. 文件上传(简述)

上传文件用 enctype="multipart/form-data",数据放在 $_FILES(不是 $_POST)。这部分内容较多,放在第 15 章单独讲。

8. 实战要点清单

小结

这一章你掌握了 PHP 表单处理的完整流程:GET/POST 区别、$_GET/$_POST、验证、粘性、过滤、XSS 防御。下一篇会话管理——让用户"登录一次就记住"。

← 上一篇 PHP 字符串

下一篇 PHP 会话管理

✈️💬