本文目录导读:

在 PHP 中,输入验证是确保数据安全性和完整性的关键步骤,以下是 PHP 输入验证的完整指南,包含常见类型、函数、示例和最佳实践。
核心验证函数
过滤器函数(推荐)
PHP 内置的过滤器是最安全、最简洁的方式。
// 验证并过滤整数 $age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT); // 如果验证失败,返回 false // 验证并过滤邮箱 $email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL); // 验证并过滤 URL $url = filter_input(INPUT_GET, 'url', FILTER_VALIDATE_URL); // 验证 IP 地址 $ip = filter_input(INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP);
常用判断函数
// 检查是否为空
if (empty($_POST['username'])) {
echo "用户名不能为空";
}
// 检查字符串长度
if (strlen($_POST['password']) < 8) {
echo "密码至少8位";
}
// 检查是否在范围内
if ($_POST['age'] < 18 || $_POST['age'] > 120) {
echo "年龄不合法";
}
常见输入类型验证
文本/字符串验证
function validateUsername($username) {
// 去首尾空格
$username = trim($username);
// 检查长度(2-20个字符)
if (strlen($username) < 2 || strlen($username) > 20) {
return false;
}
// 只允许字母、数字、下划线、中文
if (!preg_match('/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]+$/u', $username)) {
return false;
}
return $username;
}
邮箱验证
function validateEmail($email) {
// 使用过滤器
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
return false;
}
// 额外检查域名是否有效(可选)
$domain = explode('@', $email)[1];
if (!checkdnsrr($domain, 'MX') && !checkdnsrr($domain, 'A')) {
return false;
}
return $email;
}
数字验证
function validateNumber($input, $min = null, $max = null) {
// 验证是否为数字
if (!is_numeric($input)) {
return false;
}
// 转为整数或浮点数
$number = $input + 0;
// 范围检查
if ($min !== null && $number < $min) return false;
if ($max !== null && $number > $max) return false;
return $number;
}
URL 验证
function validateUrl($url) {
// 基本验证
if (filter_var($url, FILTER_VALIDATE_URL) === false) {
return false;
}
// 只允许 http/https 协议
$parsed = parse_url($url);
if (!in_array($parsed['scheme'], ['http', 'https'])) {
return false;
}
return $url;
}
表单验证完整示例
<?php
$errors = [];
$data = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 用户名
$username = trim($_POST['username'] ?? '');
if (empty($username)) {
$errors['username'] = '用户名不能为空';
} elseif (!preg_match('/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]{2,20}$/u', $username)) {
$errors['username'] = '用户名格式不正确(2-20位字母/数字/中文/下划线)';
} else {
$data['username'] = $username;
}
// 邮箱
$email = trim($_POST['email'] ?? '');
if (empty($email)) {
$errors['email'] = '邮箱不能为空';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = '邮箱格式不正确';
} else {
$data['email'] = $email;
}
// 密码
$password = $_POST['password'] ?? '';
$confirm = $_POST['confirm_password'] ?? '';
if (empty($password)) {
$errors['password'] = '密码不能为空';
} elseif (strlen($password) < 8) {
$errors['password'] = '密码至少8位';
} elseif ($password !== $confirm) {
$errors['confirm_password'] = '两次密码不一致';
} else {
$data['password'] = password_hash($password, PASSWORD_DEFAULT);
}
// 年龄
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 120]
]);
if ($age === false) {
$errors['age'] = '年龄必须在1-120之间';
} else {
$data['age'] = $age;
}
// 如果没有错误,处理数据
if (empty($errors)) {
// 保存到数据库或进行其他操作
header('Location: success.php');
exit;
}
}
?>
安全最佳实践
防止 XSS(跨站脚本攻击)
// 输出时使用 htmlspecialchars echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8'); // 或者使用 filter_var $safe_input = filter_var($user_input, FILTER_SANITIZE_STRING);
防止 SQL 注入
// 使用预处理语句(推荐)
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute([':email' => $email]);
// 使用 mysqli 的 real_escape_string
$safe_email = $mysqli->real_escape_string($email);
防止文件上传漏洞
function validateUploadedFile($file) {
// 检查文件类型
$allowed_types = ['image/jpeg', 'image/png', 'image/gif'];
if (!in_array($file['type'], $allowed_types)) {
return false;
}
// 检查文件大小(2MB)
if ($file['size'] > 2 * 1024 * 1024) {
return false;
}
// 验证文件扩展名
$extension = pathinfo($file['name'], PATHINFO_EXTENSION);
if (!in_array(strtolower($extension), ['jpg', 'jpeg', 'png', 'gif'])) {
return false;
}
// 使用 getimagesize 验证图像文件
if (!getimagesize($file['tmp_name'])) {
return false;
}
return true;
}
创建可重用的验证类
class Validator {
private $data = [];
private $errors = [];
public function __construct($data) {
$this->data = $data;
}
public function required($field, $label = '') {
if (empty($this->data[$field])) {
$this->errors[$field] = ($label ?: $field) . '不能为空';
}
return $this;
}
public function email($field) {
if (!empty($this->data[$field]) && !filter_var($this->data[$field], FILTER_VALIDATE_EMAIL)) {
$this->errors[$field] = '邮箱格式不正确';
}
return $this;
}
public function minLength($field, $min) {
if (!empty($this->data[$field]) && strlen($this->data[$field]) < $min) {
$this->errors[$field] = "{$field}至少需要{$min}个字符";
}
return $this;
}
public function maxLength($field, $max) {
if (!empty($this->data[$field]) && strlen($this->data[$field]) > $max) {
$this->errors[$field] = "{$field}不能超过{$max}个字符";
}
return $this;
}
public function int($field, $min = null, $max = null) {
$options = [];
if ($min !== null) $options['min_range'] = $min;
if ($max !== null) $options['max_range'] = $max;
if (!empty($this->data[$field])) {
$value = filter_var($this->data[$field], FILTER_VALIDATE_INT, ['options' => $options]);
if ($value === false) {
$this->errors[$field] = "{$field}必须是有效的整数";
}
}
return $this;
}
public function validate() {
return empty($this->errors);
}
public function getErrors() {
return $this->errors;
}
}
// 使用示例
$validator = new Validator($_POST);
$isValid = $validator
->required('username', '用户名')
->minLength('username', 2)
->maxLength('username', 20)
->required('email', '邮箱')
->email('email')
->required('age', '年龄')
->int('age', 1, 120)
->validate();
if (!$isValid) {
print_r($validator->getErrors());
}
- 始终验证:不要信任任何用户输入
- 使用内置函数:PHP 的过滤器函数是最安全的选择
- 输出时转义:使用
htmlspecialchars防止 XSS - 使用预处理语句:防止 SQL 注入
- 验证+清理:验证数据是否符合要求,同时清理不安全的内容
- 考虑服务器端验证:不要依赖客户端验证(JavaScript 可以被禁用)
验证在服务器端始终是必要的,客户端验证只是辅助用户体验。