PHP 表单处理与数据验证:从入门到安全防范

小飞兽 PHP 12 次阅读 2026-07-16

表单处理流程

一个安全的表单处理流程:接收→验证→过滤→处理→响应。任何一个环节都不能省略。

一、接收表单数据

1. 超全局变量

$_GET['username']   // GET请求
$_POST['username']  // POST请求
$_REQUEST['username'] // 同时支持GET和POST
$_FILES['avatar']   // 文件上传
$_SERVER['REQUEST_METHOD'] // 'GET' 或 'POST'

2. 判断请求方式

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'] ?? '';
} else {
    $username = '';
}

二、基本验证

3. 必填项检查

$errors = [];
if (empty($_POST['username'])) $errors[] = '用户名不能为空';
if (empty($_POST['email'])) $errors[] = '邮箱不能为空';
if (!empty($errors)) { foreach ($errors as $e) echo "

$e

"; exit; }

4. 邮箱格式验证

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

5. 长度限制

if (mb_strlen($username) < 3) $errors[] = '用户名至少3个字符';
if (mb_strlen($username) > 20) $errors[] = '用户名最多20个字符';

6. 数字范围

$age = (int)($_POST['age'] ?? 0);
if ($age < 18 || $age > 100) $errors[] = '年龄必须在18-100之间';

三、安全防范

7. XSS 跨站脚本攻击防范

// 危险!直接输出用户输入
echo $_POST['comment'];

// 正确:转义后再输出
$comment = htmlspecialchars($_POST['comment'], ENT_QUOTES, 'UTF-8');
echo $comment;


8. SQL 注入防范


永远不要把用户输入直接拼进SQL:


// 错误:直接拼SQL(极危险!)
$sql = "SELECT * FROM users WHERE name = '" . $_POST['name'] . "'";

// 正确:使用PDO预处理
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = :name');
$stmt->execute(['name' => $_POST['name']]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);


9. CSRF 跨站请求伪造防范


session_start();
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// 表单:echo '';
// 验证:if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) { die('CSRF验证失败'); }

10. 密码安全存储


// 哈希存储(永远不要存明文!)
$hash = password_hash($_POST['password'], PASSWORD_DEFAULT);

// 验证
if (password_verify($_POST['password'], $hash)) {
// 登录成功
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
$newHash = password_hash($_POST['password'], PASSWORD_DEFAULT);
// 更新数据库
}
}


四、文件上传处理


11. 安全文件上传


$file = $_FILES['avatar'];

// 1. 检查上传错误
if ($file['error'] !== UPLOAD_ERR_OK) { die('文件上传失败'); }

// 2. 检查文件大小(最大2MB)
if ($file['size'] > 2 * 1024 * 1024) { die('文件超过2MB限制'); }

// 3. 检查MIME类型(不要信任扩展名)
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file['tmp_name']);
$allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($mimeType, $allowed)) { die('只允许图片'); }

// 4. 生成随机文件名
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$newName = bin2hex(random_bytes(16)) . '.' . $ext;

// 5. 移动文件
move_uploaded_file($file['tmp_name'], __DIR__ . '/uploads/' . $newName);


五、完整验证类示例


class FormValidator
{
private array $errors = [];
private array $data = [];

public function __construct(private array $rules) {}

public function validate(array $input): bool
{
foreach ($this->rules as $field => $ruleSet) {
$value = $input[$field] ?? null;
$rules = explode('|', $ruleSet);
foreach ($rules as $rule) {
[$name, $param] = array_pad(explode(':', $rule, 2), 2, null);
$this->applyRule($field, $value, $name, $param);
}
if ($value !== null) {
$this->data[$field] = is_string($value) ? trim($value) : $value;
}
}
return empty($this->errors);
}

private function applyRule(string $f, mixed $v, string $r, ?string $p): void
{
switch ($r) {
case 'required':
if (empty($v)) $this->errors[$f][] = "{$f}不能为空"; break;
case 'email':
if ($v && !filter_var($v, FILTER_VALIDATE_EMAIL))
$this->errors[$f][] = "{$f}邮箱格式不正确"; break;
case 'min':
if (mb_strlen($v) < (int)$p)
$this->errors[$f][] = "{$f}至少{$p}个字符"; break;
case 'max':
if (mb_strlen($v) > (int)$p)
$this->errors[$f][] = "{$f}最多{$p}个字符"; break;
}
}

public function getErrors(): array { return $this->errors; }
public function getData(): array { return $this->data; }
}

// 使用
$v = new FormValidator([
'username' => 'required|min:3|max:20',
'email' => 'required|email',
'password' => 'required|min:6',
]);

if ($v->validate($_POST)) {
$data = $v->getData();
// 入库...
} else {
print_r($v->getErrors());
}


六、常用辅助函数


$value = trim($_POST['value']);        // 去首尾空格
$id = (int)($_GET['id'] ?? 0); // 整数化
$output = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); // 防XSS
$intro = mb_substr($_POST['intro'], 0, 200); // 限制长度
$content = strip_tags($_POST['content']); // 去除HTML标签

总结



    • 永远不相信用户输入——所有数据都要验证

    • 输出时转义(htmlspecialchars)比输入时过滤更好

    • SQL用预处理语句,彻底杜绝注入

    • 密码用password_hash(),不要手写加密

    • CSRF Token是表单安全的标配

  • 文件上传要验证MIME类型、限制大小、随机命名