处理用户提交的表单是 PHP 最常见的任务,也是最容易埋坑的地方。核心原则只有两条:输入要验证,输出要转义。这篇文章用一组内置安全函数演示标准做法。

1. 接收表单数据

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name  = trim($_POST['name'] ?? '');
    $email = trim($_POST['email'] ?? '');
}

用 ?? 提供默认值、trim() 清理首尾空白,能避免未定义索引的警告。

2. 验证:filter_var()

<?php
$email = '[email protected]';

if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
    echo '邮箱格式正确';
}

$age = '25';
if (filter_var($age, FILTER_VALIDATE_INT, [
    'options' => ['min_range' => 1, 'max_range' => 120],
])) {
    echo '年龄合法';
}

filter_var() 内置了邮箱、URL、整数等常用验证器,验证失败返回 false,比手写正则直观得多。前端校验可以被绕过,服务端验证永远不能省。

3. 输出转义:htmlspecialchars()

任何来自用户的数据,输出到 HTML 之前都要转义,这是防 XSS 的基本功。

<?php
$comment = '<b>你好</b><script>alert(1)</script>';

echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
// 输出:&lt;b&gt;你好&lt;/b&gt;&lt;script&gt;alert(1)&lt;/script&gt;

记住口诀:存原文,出转义。数据库里保存原始内容,渲染到页面时再做转义,两边都干净。

4. 密码绝不明文:password_hash() 与 password_verify()

<?php
// 注册时:生成带盐的哈希
$hash = password_hash('mySecret123', PASSWORD_DEFAULT);

// 登录时:验证密码
if (password_verify('mySecret123', $hash)) {
    echo '密码正确';
}

password_hash() 自动加盐,同一个密码每次生成的哈希都不同;验证永远交给 password_verify(),不要自己写字符串比较逻辑。

5. 一个完整的迷你示例

<?php
$errors = [];

$name  = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');

if ($name === '') {
    $errors[] = '请填写昵称';
}

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = '邮箱格式不正确';
}

if ($errors === []) {
    echo '验证通过,欢迎你,' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
} else {
    echo implode(';', $errors);
}

小结

  • 接收数据:$_POST 配合 ?? 与 trim()
  • 验证:filter_var(),服务端验证不能省
  • 输出:htmlspecialchars() 转义,防 XSS
  • 密码:password_hash() 加盐存储,password_verify() 验证
  • 数据库:一律使用 PDO 预处理语句,杜绝拼接 SQL

这些都是 PHP 内置的安全处理函数,把这套流程用熟,表单代码就稳了。