PHP 表单验证

PHP 表单验证中文讲解

什么是 PHP 表单验证?

PHP 表单验证是指在服务器端对用户通过 HTML 表单提交的数据进行检查和处理,以确保数据的完整性有效性安全性。验证可以防止无效数据、恶意输入(如 SQL 注入或 XSS 攻击)以及不符合业务逻辑的数据进入系统。表单验证是 PHP Web 开发中的关键环节,广泛应用于用户注册、登录、搜索等场景。

为什么需要表单验证?

  • 数据完整性:确保必填字段不为空,数据格式正确(如邮箱、电话)。
  • 安全性:防止恶意输入,如脚本注入或 SQL 注入。
  • 用户体验:通过清晰的错误提示帮助用户纠正输入错误。
  • 业务逻辑:确保数据符合应用需求(如年龄限制、唯一用户名)。

核心验证方法

PHP 提供多种内置函数和工具来验证表单数据,结合逻辑判断实现健壮的验证流程。以下是常见验证方法和场景:

  1. 检查必填字段
    使用 empty()isset() 判断字段是否为空:
   <?php
   if (empty($_POST['name'])) {
       $errors[] = "姓名不能为空";
   }
  1. 验证数据格式
    使用 filter_var() 或正则表达式验证特定格式:
  • 邮箱格式
    php $email = $_POST['email']; if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $errors[] = "无效的邮箱格式"; }
  • 数字范围
    php $age = $_POST['age']; if (!filter_var($age, FILTER_VALIDATE_INT) || $age < 18 || $age > 120) { $errors[] = "年龄必须是 18-120 之间的整数"; }
  1. 清理输入数据
    使用 filter_var()htmlspecialchars() 清理输入,防止 XSS 攻击:
   $name = filter_var($_POST['name'], FILTER_SANITIZE_STRING);
   $name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
  1. 正则表达式验证
    检查复杂格式,如电话号码:
   $phone = $_POST['phone'];
   if (!preg_match("/^1[3-9]\d{9}$/", $phone)) {
       $errors[] = "无效的手机号码";
   }
  1. 文件上传验证
    检查文件类型、大小等:
   if (isset($_FILES['file']) && $_FILES['file']['error'] === UPLOAD_ERR_OK) {
       $allowed = ['jpg', 'png'];
       $ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
       if (!in_array($ext, $allowed)) {
           $errors[] = "只允许 JPG 或 PNG 文件";
       }
       if ($_FILES['file']['size'] > 2 * 1024 * 1024) {
           $errors[] = "文件大小不能超过 2MB";
       }
   }

完整示例:表单验证

以下是一个完整的用户注册表单验证示例,包括 HTML 和 PHP 代码:

  1. HTML 表单 (register.html):
   <!DOCTYPE html>
   <html>
   <head>
       <meta charset="UTF-8">
       <title>用户注册</title>
   </head>
   <body>
       <form action="register.php" method="post">
           <label for="name">姓名:</label>
           <input type="text" id="name" name="name" value="<?php echo isset($_POST['name']) ? htmlspecialchars($_POST['name']) : ''; ?>">
           <br>
           <label for="email">邮箱:</label>
           <input type="email" id="email" name="email" value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email']) : ''; ?>">
           <br>
           <label for="password">密码:</label>
           <input type="password" id="password" name="password">
           <br>
           <input type="submit" value="注册">
       </form>
   </body>
   </html>
  1. PHP 验证脚本 (register.php):
   <?php
   // 初始化错误数组
   $errors = [];
   $data = [];

   // 检查请求方法
   if ($_SERVER['REQUEST_METHOD'] === 'POST') {
       // 获取并清理输入
       $name = filter_var($_POST['name'] ?? '', FILTER_SANITIZE_STRING);
       $email = filter_var($_POST['email'] ?? '', FILTER_SANITIZE_EMAIL);
       $password = $_POST['password'] ?? '';

       // 验证必填字段
       if (empty($name)) {
           $errors[] = "姓名不能为空";
       }
       if (empty($email)) {
           $errors[] = "邮箱不能为空";
       } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
           $errors[] = "无效的邮箱格式";
       }
       if (empty($password)) {
           $errors[] = "密码不能为空";
       } elseif (strlen($password) < 6) {
           $errors[] = "密码长度至少为 6 位";
       }

       // 如果没有错误,处理数据
       if (empty($errors)) {
           // 模拟保存到数据库(使用 PDO 防 SQL 注入)
           try {
               $pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass");
               $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
               $stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (:name, :email, :password)");
               $stmt->execute([
                   'name' => $name,
                   'email' => $email,
                   'password' => password_hash($password, PASSWORD_DEFAULT) // 加密密码
               ]);
               echo "注册成功!";
           } catch (PDOException $e) {
               $errors[] = "数据库错误: " . $e->getMessage();
           }
       }
   }

   // 显示错误
   if (!empty($errors)) {
       echo "<ul>";
       foreach ($errors as $error) {
           echo "<li>$error</li>";
       }
       echo "</ul>";
   }
   ?>

安全性注意事项

  1. 防止 XSS 攻击
  • 使用 htmlspecialchars() 转义输出。
  • 清理输入数据:filter_var($input, FILTER_SANITIZE_STRING)
  1. 防止 SQL 注入
  • 使用 PDO 或 MySQLi 的预处理语句,避免直接拼接 SQL 查询。
  • 示例:
    php $stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email"); $stmt->execute(['email' => $email]);
  1. CSRF 保护
  • 添加 CSRF 令牌验证:
    php session_start(); if (empty($_SESSION['csrf_token'])) { $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); } ?> ¨K17K <?php if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) { die("CSRF 验证失败"); }
  1. 密码安全
  • 使用 password_hash() 加密密码,验证时用 password_verify()
    php $password = $_POST['password']; $hashed = password_hash($password, PASSWORD_DEFAULT); // 验证 if (password_verify($password, $hashed)) { echo "密码正确"; }

最佳实践

  • 集中验证逻辑:将验证规则封装在函数或类中,提高复用性:
  function validateEmail($email) {
      return filter_var($email, FILTER_VALIDATE_EMAIL) ? true : false;
  }
  • 回显输入:验证失败时,使用 htmlspecialchars() 回显用户输入,避免数据丢失ਸ

System: 丢失,防止 XSS 攻击。

  • 错误提示友好:提供具体的错误信息,引导用户更正输入。
  • 客户端验证结合:在客户端使用 JavaScript 进行初步验证,减轻服务器负担,但不要完全依赖。
  • 使用过滤器:优先使用 PHP 的 filter_var() 函数,简单高效。
  • 表单结构:确保 name 属性唯一,方便 PHP 获取数据。

参考资源

总结

PHP 表单验证是确保用户输入安全、有效和符合业务逻辑的关键步骤。通过检查必填字段、验证数据格式、清理输入和防范安全威胁(如 XSS、SQL 注入、CSRF),开发者可以构建健壮的 Web 应用。结合客户端验证和最佳实践,表单处理既安全又用户友好,是 PHP 开发的核心技能。

类似文章

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注