在接收表单数据时进行合法性检验是确保应用安全的关键步骤。下面详细介绍如何在 PHP 类中实现全面的数据验证。

1. 基本验证方法

1.1 使用 filter_var 函数

class UserValidator {
    public function validateEmail($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }
    
    public function validateUrl($url) {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }
    
    public function sanitizeInput($input) {
        return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
    }
}

1.2 常用验证规则

class InputValidator {
    // 验证必填字段
    public function required($value) {
        return !empty(trim($value));
    }
    
    // 验证最小长度
    public function minLength($value, $min) {
        return strlen(trim($value)) >= $min;
    }
    
    // 验证最大长度
    public function maxLength($value, $max) {
        return strlen(trim($value)) <= $max;
    }
    
    // 验证数字范围
    public function between($value, $min, $max) {
        return $value >= $min && $value <= $max;
    }
    
    // 验证正则表达式
    public function regex($value, $pattern) {
        return preg_match($pattern, $value) === 1;
    }
}

2. 完整的表单验证类实现

class FormValidator {
    private $data;
    private $errors = [];
    private $rules = [];
    
    public function __construct(array $data) {
        $this->data = $data;
    }
    
    public function setRules(array $rules) {
        $this->rules = $rules;
    }
    
    public function validate() {
        foreach ($this->rules as $field => $ruleSet) {
            $value = $this->data[$field] ?? null;
            
            foreach ($ruleSet as $rule => $param) {
                if ($rule === 'required' && !$this->validateRequired($value)) {
                    $this->addError($field, "$field 是必填字段");
                    break;
                }
                
                if ($rule === 'email' && !$this->validateEmail($value)) {
                    $this->addError($field, "$field 必须是有效的邮箱地址");
                    break;
                }
                
                if ($rule === 'min' && !$this->validateMinLength($value, $param)) {
                    $this->addError($field, "$field 至少需要 $param 个字符");
                    break;
                }
                
                if ($rule === 'max' && !$this->validateMaxLength($value, $param)) {
                    $this->addError($field, "$field 不能超过 $param 个字符");
                    break;
                }
                
                if ($rule === 'numeric' && !is_numeric($value)) {
                    $this->addError($field, "$field 必须是数字");
                    break;
                }
                
                // 可以添加更多验证规则...
            }
        }
        
        return empty($this->errors);
    }
    
    private function validateRequired($value) {
        return !empty(trim($value ?? ''));
    }
    
    private function validateEmail($value) {
        return filter_var($value, FILTER_VALIDATE_EMAIL) !== false;
    }
    
    private function validateMinLength($value, $min) {
        return strlen(trim($value ?? '')) >= $min;
    }
    
    private function validateMaxLength($value, $max) {
        return strlen(trim($value ?? '')) <= $max;
    }
    
    private function addError($field, $message) {
        $this->errors[$field] = $message;
    }
    
    public function getErrors() {
        return $this->errors;
    }
    
    public function getValidatedData() {
        $cleanData = [];
        
        foreach ($this->data as $key => $value) {
            if (is_string($value)) {
                $cleanData[$key] = htmlspecialchars(trim($value), ENT_QUOTES, 'UTF-8');
            } else {
                $cleanData[$key] = $value;
            }
        }
        
        return $cleanData;
    }
}

3. 使用示例

// 表单提交处理
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $validator = new FormValidator($_POST);
    
    // 设置验证规则
    $validator->setRules([
        'username' => [
            'required' => true,
            'min' => 4,
            'max' => 20
        ],
        'email' => [
            'required' => true,
            'email' => true
        ],
        'password' => [
            'required' => true,
            'min' => 8
        ],
        'age' => [
            'numeric' => true
        ]
    ]);
    
    if ($validator->validate()) {
        // 获取经过验证和清理的数据
        $cleanData = $validator->getValidatedData();
        
        // 处理数据(如存入数据库)
        // ...
        
        echo "表单验证通过!";
    } else {
        // 显示错误信息
        echo "验证错误:";
        print_r($validator->getErrors());
    }
}

4. 高级验证技巧

4.1 自定义验证规则

class CustomValidator extends FormValidator {
    // 验证手机号码
    public function validatePhone($value) {
        return preg_match('/^1[3-9]\d{9}$/', $value) === 1;
    }
    
    // 验证密码强度
    public function validatePasswordStrength($value) {
        return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/', $value) === 1;
    }
}

4.2 数据库唯一性验证

class UserRegistrationValidator extends FormValidator {
    private $db;
    
    public function __construct(array $data, PDO $db) {
        parent::__construct($data);
        $this->db = $db;
    }
    
    // 验证用户名是否已存在
    public function validateUsernameUnique($username) {
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM users WHERE username = ?");
        $stmt->execute([$username]);
        return $stmt->fetchColumn() === 0;
    }
    
    // 验证邮箱是否已注册
    public function validateEmailUnique($email) {
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM users WHERE email = ?");
        $stmt->execute([$email]);
        return $stmt->fetchColumn() === 0;
    }
}

5. 安全注意事项

  1. 输入过滤

    • 使用 htmlspecialchars() 防止 XSS 攻击

    • 使用 trim() 去除多余空格

  2. 数据库安全

    • 永远使用预处理语句防止 SQL 注入

    • 密码使用 password_hash() 存储

  3. 文件上传验证

    • 检查文件类型 (mime_content_type)

    • 检查文件大小

    • 重命名上传的文件

  4. CSRF 防护

    • 使用令牌验证表单来源

  5. 错误处理

    • 不要向用户显示详细的错误信息

    • 记录错误日志

6. 完整实战示例

class UserRegistration {
    private $db;
    private $validator;
    
    public function __construct(PDO $db) {
        $this->db = $db;
    }
    
    public function register(array $data) {
        $this->validator = new FormValidator($data);
        
        $this->validator->setRules([
            'username' => [
                'required' => true,
                'min' => 4,
                'max' => 20
            ],
            'email' => [
                'required' => true,
                'email' => true
            ],
            'password' => [
                'required' => true,
                'min' => 8
            ],
            'password_confirm' => [
                'required' => true,
                'matches' => 'password'
            ]
        ]);
        
        if (!$this->validator->validate()) {
            return ['success' => false, 'errors' => $this->validator->getErrors()];
        }
        
        $cleanData = $this->validator->getValidatedData();
        
        // 检查用户名和邮箱是否已存在
        if ($this->usernameExists($cleanData['username'])) {
            return ['success' => false, 'errors' => ['username' => '用户名已存在']];
        }
        
        if ($this->emailExists($cleanData['email'])) {
            return ['success' => false, 'errors' => ['email' => '邮箱已注册']];
        }
        
        // 创建用户
        $hashedPassword = password_hash($cleanData['password'], PASSWORD_DEFAULT);
        
        try {
            $stmt = $this->db->prepare("INSERT INTO users (username, email, password) VALUES (?, ?, ?)");
            $stmt->execute([
                $cleanData['username'],
                $cleanData['email'],
                $hashedPassword
            ]);
            
            return ['success' => true, 'user_id' => $this->db->lastInsertId()];
        } catch (PDOException $e) {
            // 记录错误日志
            error_log("注册失败: " . $e->getMessage());
            return ['success' => false, 'errors' => ['system' => '注册失败,请稍后再试']];
        }
    }
    
    private function usernameExists($username) {
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM users WHERE username = ?");
        $stmt->execute([$username]);
        return $stmt->fetchColumn() > 0;
    }
    
    private function emailExists($email) {
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM users WHERE email = ?");
        $stmt->execute([$email]);
        return $stmt->fetchColumn() > 0;
    }
}

通过以上方法,你可以在 PHP 类中实现对表单数据的全面验证,确保数据的合法性和应用的安全性。根据项目需求,你可以扩展验证规则或创建更复杂的验证逻辑。