PHP filter_input_array() 函数

定义和用法

filter_input_array() 函数用于从外部环境批量获取多个变量,并对它们进行过滤。

这个函数是 filter_input() 的批量版本,可以一次性处理多个输入变量,非常适合表单数据的批量验证和清理。

提示:使用这个函数可以大大简化表单验证代码,提高代码的可维护性和安全性。

语法

filter_input_array(int $type, array|int $options = FILTER_DEFAULT, bool $add_empty = true): array|false|null

参数值

参数 描述
$type 输入类型。必须是以下常量之一:
  • INPUT_GET
  • INPUT_POST
  • INPUT_COOKIE
  • INPUT_SERVER
  • INPUT_ENV
$options

过滤器配置数组过滤器ID

可以是以下两种形式之一:

  1. 过滤器ID(整数):所有输入变量使用相同的过滤器
  2. 配置数组:为每个变量指定不同的过滤器配置

配置数组的键是变量名,值可以是:

  • 过滤器ID(整数)
  • 过滤器配置数组

$add_empty 是否包含空值(可选)。默认为 true
  • true:在结果中包含缺失的变量,值为 null
  • false:在结果中排除缺失的变量

配置数组格式

$options 参数为数组时,可以使用以下格式:

$options = [
    'field1' => FILTER_SANITIZE_STRING,
    'field2' => [
        'filter'  => FILTER_VALIDATE_INT,
        'options' => ['min_range' => 1, 'max_range' => 100],
        'flags'   => FILTER_REQUIRE_SCALAR
    ],
    'field3' => [
        'filter' => FILTER_VALIDATE_EMAIL
    ],
    // ... 更多字段
];

返回值

  • 成功时:返回包含过滤后值的关联数组
  • 变量不存在时:根据 $add_empty 参数决定是否包含 null
  • 发生错误时:返回 false
  • 没有输入变量时:返回 null

示例

示例 1:基本用法 - 批量过滤 GET 参数

<?php
// URL: example.com?name=John&age=25&email=john@example.com

$filters = [
    'name'  => FILTER_SANITIZE_STRING,
    'age'   => FILTER_VALIDATE_INT,
    'email' => FILTER_VALIDATE_EMAIL,
    'page'  => FILTER_VALIDATE_INT  // 这个参数不存在
];

$result = filter_input_array(INPUT_GET, $filters);

echo "<pre>";
print_r($result);
echo "</pre>";

// 检查各个字段
if ($result['name'] !== null) {
    echo "姓名: " . htmlspecialchars($result['name']) . "<br>";
}

if ($result['age'] !== false && $result['age'] !== null) {
    echo "年龄: " . $result['age'] . "<br>";
} else {
    echo "年龄无效<br>";
}

if ($result['email'] !== false && $result['email'] !== null) {
    echo "邮箱: " . htmlspecialchars($result['email']) . "<br>";
} else {
    echo "邮箱无效<br>";
}

// 不存在的字段值为 null
if ($result['page'] === null) {
    echo "page 参数不存在<br>";
}
?>
输出示例:
Array
(
    [name] => John
    [age] => 25
    [email] => john@example.com
    [page] =>
)
姓名: John
年龄: 25
邮箱: john@example.com
page 参数不存在

示例 2:表单数据批量验证

<?php
// 表单提交数据验证示例
$filters = [
    'username' => [
        'filter'  => FILTER_SANITIZE_STRING,
        'flags'   => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH
    ],
    'email' => FILTER_VALIDATE_EMAIL,
    'age' => [
        'filter'  => FILTER_VALIDATE_INT,
        'options' => [
            'min_range' => 1,
            'max_range' => 120,
            'default'   => 0  // 验证失败时的默认值
        ]
    ],
    'website' => [
        'filter' => FILTER_VALIDATE_URL,
        'flags'  => FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED
    ],
    'accept_terms' => FILTER_VALIDATE_BOOLEAN,
    'interests' => [
        'filter' => FILTER_SANITIZE_STRING,
        'flags'  => FILTER_REQUIRE_ARRAY  // 处理数组输入
    ]
];

$data = filter_input_array(INPUT_POST, $filters, false); // false 表示不包含空值

if ($data === false) {
    echo "数据处理失败!";
    exit;
}

// 验证结果
$errors = [];
$validData = [];

foreach ($data as $field => $value) {
    if ($value === false) {
        $errors[] = "$field 验证失败";
    } elseif ($value === null) {
        $errors[] = "$field 未提供";
    } else {
        $validData[$field] = $value;
    }
}

if (empty($errors)) {
    echo "<div class='alert alert-success'>所有数据验证通过!</div>";
    echo "<pre>" . print_r($validData, true) . "</pre>";
} else {
    echo "<div class='alert alert-danger'>发现错误:</div>";
    echo "<ul>";
    foreach ($errors as $error) {
        echo "<li>$error</li>";
    }
    echo "</ul>";
}
?>

示例 3:使用相同的过滤器处理所有字段

<?php
// 对GET请求的所有参数应用相同的过滤器
// URL: example.com?q=search&sort=date&order=asc

// 所有字段都使用字符串清理过滤器
$cleanedData = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);

echo "清理后的GET参数:<br>";
foreach ($cleanedData as $key => $value) {
    if ($value !== null) {
        echo "$key: " . htmlspecialchars($value) . "<br>";
    }
}

// 也可以使用更严格的清理
$strictFilters = filter_input_array(INPUT_GET,
    FILTER_SANITIZE_STRING,
    FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH
);

echo "<hr>严格清理后的数据:<br>";
print_r($strictFilters);
?>

示例 4:处理数组输入(如复选框)

<?php
// 处理多个复选框数据
// 表单中的复选框:<input type="checkbox" name="hobbies[]" value="reading">

$filters = [
    'name' => FILTER_SANITIZE_STRING,
    'hobbies' => [
        'filter' => FILTER_SANITIZE_STRING,
        'flags'  => FILTER_REQUIRE_ARRAY  // 重要:告诉过滤器这是一个数组
    ],
    'categories' => [
        'filter' => FILTER_VALIDATE_INT,
        'flags'  => FILTER_REQUIRE_ARRAY | FILTER_FLAG_ARRAY_FILTER  // 验证数组中的每个元素
    ]
];

// 模拟POST数据
$_POST = [
    'name' => 'John Doe',
    'hobbies' => ['reading', 'swimming', 'coding'],
    'categories' => [1, 2, 5, 10]
];

$result = filter_input_array(INPUT_POST, $filters);

echo "<h4>处理结果:</h4>";
echo "姓名: " . htmlspecialchars($result['name']) . "<br>";

echo "爱好: ";
if (is_array($result['hobbies'])) {
    echo implode(', ', array_map('htmlspecialchars', $result['hobbies']));
}
echo "<br>";

echo "分类ID: ";
if (is_array($result['categories'])) {
    echo implode(', ', $result['categories']);
}
?>

示例 5:完整用户注册表单处理

<?php
// 用户注册表单的完整处理
class RegistrationForm {
    private $filters = [
        'username' => [
            'filter' => FILTER_SANITIZE_STRING,
            'flags' => FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH,
            'validation' => function($value) {
                if (strlen($value) < 3) {
                    return '用户名至少需要3个字符';
                }
                if (strlen($value) > 20) {
                    return '用户名不能超过20个字符';
                }
                return true;
            }
        ],
        'email' => [
            'filter' => FILTER_VALIDATE_EMAIL,
            'validation' => function($value) {
                // 可以在这里添加额外的邮箱验证逻辑
                return true;
            }
        ],
        'password' => [
            'filter' => FILTER_UNSAFE_RAW, // 不进行过滤,稍后使用密码哈希
            'validation' => function($value) {
                if (strlen($value) < 8) {
                    return '密码至少需要8个字符';
                }
                return true;
            }
        ],
        'confirm_password' => [
            'filter' => FILTER_UNSAFE_RAW,
            'validation' => null // 将在主验证中处理
        ],
        'age' => [
            'filter' => FILTER_VALIDATE_INT,
            'options' => ['min_range' => 13, 'max_range' => 120]
        ],
        'accept_terms' => FILTER_VALIDATE_BOOLEAN
    ];

    public function process() {
        if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
            return ['success' => false, 'message' => '无效的请求方法'];
        }

        // 第一步:过滤输入
        $filterConfig = [];
        foreach ($this->filters as $field => $config) {
            if (is_array($config) && isset($config['filter'])) {
                $filterConfig[$field] = [
                    'filter' => $config['filter'],
                    'options' => $config['options'] ?? null,
                    'flags' => $config['flags'] ?? 0
                ];
            } else {
                $filterConfig[$field] = $config;
            }
        }

        $data = filter_input_array(INPUT_POST, $filterConfig, false);

        if ($data === false) {
            return ['success' => false, 'message' => '数据过滤失败'];
        }

        // 第二步:验证数据
        $errors = [];
        $validData = [];

        foreach ($data as $field => $value) {
            $config = $this->filters[$field];

            if ($value === false) {
                $errors[$field] = $field . ' 格式无效';
            } elseif ($value === null && $field !== 'confirm_password') {
                $errors[$field] = $field . ' 是必填字段';
            } else {
                // 执行自定义验证
                if (is_array($config) && isset($config['validation'])) {
                    $validationResult = $config['validation']($value);
                    if ($validationResult !== true) {
                        $errors[$field] = $validationResult;
                    } else {
                        $validData[$field] = $value;
                    }
                } else {
                    $validData[$field] = $value;
                }
            }
        }

        // 检查密码确认
        if (isset($validData['password'], $data['confirm_password']) &&
            $validData['password'] !== $data['confirm_password']) {
            $errors['confirm_password'] = '两次输入的密码不一致';
            unset($validData['password']);
        }

        // 检查服务条款
        if (!isset($validData['accept_terms']) || $validData['accept_terms'] !== true) {
            $errors['accept_terms'] = '必须接受服务条款';
        }

        // 返回结果
        if (empty($errors)) {
            // 在实际应用中,这里可以保存到数据库
            unset($validData['confirm_password']);
            unset($validData['accept_terms']);

            // 对密码进行哈希处理
            if (isset($validData['password'])) {
                $validData['password_hash'] = password_hash($validData['password'], PASSWORD_DEFAULT);
                unset($validData['password']);
            }

            return [
                'success' => true,
                'message' => '注册成功!',
                'data' => $validData
            ];
        } else {
            return [
                'success' => false,
                'message' => '请修正以下错误',
                'errors' => $errors,
                'data' => $validData
            ];
        }
    }
}

// 使用示例
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $form = new RegistrationForm();
    $result = $form->process();

    if ($result['success']) {
        echo "<div class='alert alert-success'>" . $result['message'] . "</div>";
        echo "<pre>用户数据: " . print_r($result['data'], true) . "</pre>";
    } else {
        echo "<div class='alert alert-danger'>" . $result['message'] . "</div>";
        echo "<ul>";
        foreach ($result['errors'] as $field => $error) {
            echo "<li><strong>$field</strong>: $error</li>";
        }
        echo "</ul>";
    }
}
?>

注意事项

  • 过滤器配置:复杂的过滤器配置可能需要嵌套数组结构
  • 数组输入:处理数组输入时,必须使用 FILTER_REQUIRE_ARRAY 标志
  • 性能考虑:对于大量数据,使用 filter_input_array() 比多次调用 filter_input() 更高效
  • 错误处理:函数返回 false 表示发生错误,返回 null 表示没有输入数据
  • 空值处理:注意 $add_empty 参数的行为,默认包含缺失字段的 null
  • 安全建议:即使使用了过滤器,输出到HTML时仍应使用 htmlspecialchars()
  • 密码处理:密码字段通常使用 FILTER_UNSAFE_RAW 然后进行哈希处理

与 filter_input() 的比较

方面 filter_input_array() filter_input()
处理数量 批量处理多个变量 单个处理一个变量
代码简洁性 批量配置,代码更简洁 每个变量需要单独调用
配置复杂性 配置较复杂,需要数组结构 配置简单,直接传递参数
性能 处理多个变量时性能更好 处理单个变量时更直接
适用场景 表单处理、批量数据验证 单个参数验证、简单场景
数组处理 内置支持数组输入处理 需要循环处理数组

最佳实践

  1. 始终定义明确的过滤器配置:为每个字段指定具体的验证规则
  2. 结合自定义验证:过滤器无法满足所有验证需求,需要结合自定义验证逻辑
  3. 错误处理:妥善处理过滤失败和验证失败的场景
  4. 安全输出:即使数据已经过滤,输出时仍要进行适当的编码
  5. 记录日志:重要的验证失败应该记录日志,方便调试和监控
  6. 用户体验:提供清晰的错误信息,指导用户修正输入

浏览器支持

该函数是 PHP 后端函数,与浏览器无关。需要 PHP 5.2.0 或更高版本。