本文目录导读:

在PHP中,API参数过滤和解析是安全开发的重要环节,以下是几种常见且推荐的解析方法:
基础过滤方法
使用 filter_var() 和 filter_input()
<?php
// 获取并过滤单个参数
$email = filter_input(INPUT_GET, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 120]
]);
// 使用 filter_var 过滤已有变量
$username = $_POST['username'] ?? '';
$username = filter_var($username, FILTER_SANITIZE_STRING);
批量过滤
<?php
$filters = [
'name' => FILTER_SANITIZE_STRING,
'email' => FILTER_VALIDATE_EMAIL,
'age' => [
'filter' => FILTER_VALIDATE_INT,
'options' => ['min_range' => 1, 'max_range' => 150]
],
'website' => FILTER_VALIDATE_URL
];
$result = filter_input_array(INPUT_POST, $filters);
使用自定义过滤函数
<?php
class APIParameterFilter {
/**
* 解析和过滤API参数
*/
public static function parse(array $params, array $rules): array {
$filtered = [];
foreach ($rules as $key => $rule) {
$value = $params[$key] ?? $rule['default'] ?? null;
if ($value === null && ($rule['required'] ?? false)) {
throw new InvalidArgumentException("Missing required parameter: {$key}");
}
if ($value !== null) {
$value = self::applyFilter($value, $rule);
}
$filtered[$key] = $value;
}
return $filtered;
}
private static function applyFilter($value, array $rule) {
switch ($rule['type'] ?? 'string') {
case 'int':
$value = filter_var($value, FILTER_VALIDATE_INT);
if ($value === false && $value !== 0) {
throw new InvalidArgumentException("Invalid integer: {$value}");
}
break;
case 'float':
$value = filter_var($value, FILTER_VALIDATE_FLOAT);
if ($value === false) {
throw new InvalidArgumentException("Invalid float: {$value}");
}
break;
case 'email':
$value = filter_var($value, FILTER_VALIDATE_EMAIL);
if ($value === false) {
throw new InvalidArgumentException("Invalid email: {$value}");
}
break;
case 'url':
$value = filter_var($value, FILTER_VALIDATE_URL);
if ($value === false) {
throw new InvalidArgumentException("Invalid URL: {$value}");
}
break;
case 'string':
default:
// 清理和截断字符串
$value = strip_tags($value);
$maxLength = $rule['max_length'] ?? 255;
$value = mb_substr($value, 0, $maxLength, 'UTF-8');
break;
}
// 应用额外的验证
if (isset($rule['enum']) && !in_array($value, $rule['enum'])) {
throw new InvalidArgumentException("Invalid value for parameter");
}
return $value;
}
}
// 使用示例
try {
$rules = [
'username' => [
'type' => 'string',
'required' => true,
'max_length' => 50,
'pattern' => '/^[a-zA-Z0-9_]+$/'
],
'email' => [
'type' => 'email',
'required' => true
],
'age' => [
'type' => 'int',
'default' => 18,
'min' => 0,
'max' => 150
],
'role' => [
'type' => 'string',
'enum' => ['admin', 'user', 'guest']
]
];
$params = $_POST;
$filteredParams = APIParameterFilter::parse($params, $rules);
} catch (InvalidArgumentException $e) {
http_response_code(400);
echo json_encode(['error' => $e->getMessage()]);
}
使用第三方库
Respect\Validation(推荐)
<?php
require 'vendor/autoload.php';
use Respect\Validation\Validator as v;
// 定义验证规则
$rules = [
'username' => v::alnum()->length(3, 20)->setName('用户名'),
'email' => v::email()->setName('邮箱'),
'age' => v::intVal()->between(1, 150)->setName('年龄'),
'password' => v::stringType()->length(6, 32)->setName('密码')
];
// 验证数据
$input = $_POST;
foreach ($rules as $field => $validator) {
try {
$validator->assert($input[$field] ?? '');
} catch (\Respect\Validation\Exceptions\NestedValidationException $e) {
$errors[] = $e->getMessage();
}
}
if (!empty($errors)) {
http_response_code(400);
echo json_encode(['errors' => $errors]);
}
RESTful API 参数解析
<?php
class RESTParameterParser {
public static function parseRequest(): array {
$method = $_SERVER['REQUEST_METHOD'];
$params = [];
switch ($method) {
case 'GET':
$params = $_GET;
break;
case 'POST':
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (strpos($contentType, 'application/json') !== false) {
// JSON body
$body = file_get_contents('php://input');
$params = json_decode($body, true) ?? [];
} else {
// Form data
$params = $_POST;
}
break;
case 'PUT':
case 'PATCH':
case 'DELETE':
$body = file_get_contents('php://input');
// 尝试解析JSON
$params = json_decode($body, true);
// 如果是表单编码
if ($params === null) {
parse_str($body, $params);
}
break;
}
// URL参数覆盖
$params = array_merge($params, $_GET);
return self::sanitizeAll($params);
}
private static function sanitizeAll(array $params): array {
$clean = [];
foreach ($params as $key => $value) {
$clean[$key] = self::sanitizeValue($value);
}
return $clean;
}
private static function sanitizeValue($value) {
if (is_array($value)) {
return array_map([self::class, 'sanitizeValue'], $value);
}
// 移除空字符
$value = str_replace("\0", '', $value);
// HTML实体转义
$value = htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
return $value;
}
}
// 使用
$params = RESTParameterParser::parseRequest();
完整的API验证示例
<?php
class APISecurity {
// 允许的HTTP方法
const ALLOWED_METHODS = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'];
// 速率限制
private static $rateLimit = [];
public static function validateRequest(): array {
// 1. 验证HTTP方法
$method = $_SERVER['REQUEST_METHOD'];
if (!in_array($method, self::ALLOWED_METHODS)) {
throw new \Exception('Method not allowed', 405);
}
// 2. 速率限制
self::checkRateLimit();
// 3. CSRF保护(对于POST/PUT/DELETE)
if (in_array($method, ['POST', 'PUT', 'DELETE', 'PATCH'])) {
self::validateCSRF();
}
// 4. 解析和过滤参数
$params = self::parseParameters($method);
// 5. SQL注入防护
$params = self::preventSQLInjection($params);
// 6. XSS防护
$params = self::preventXSS($params);
return $params;
}
private static function checkRateLimit(): void {
$ip = $_SERVER['REMOTE_ADDR'];
$time = time();
$limit = 100; // 每分钟请求数
$window = 60; // 时间窗口(秒)
// 简化示例:实际应该使用Redis或数据库
self::$rateLimit[$ip] = self::$rateLimit[$ip] ?? ['count' => 0, 'start' => $time];
if ($time - self::$rateLimit[$ip]['start'] > $window) {
self::$rateLimit[$ip] = ['count' => 0, 'start' => $time];
}
self::$rateLimit[$ip]['count']++;
if (self::$rateLimit[$ip]['count'] > $limit) {
throw new \Exception('Rate limit exceeded', 429);
}
}
private static function validateCSRF(): void {
$token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
$sessionToken = $_SESSION['csrf_token'] ?? '';
if (empty($token) || $token !== $sessionToken) {
throw new \Exception('Invalid CSRF token', 403);
}
}
private static function parseParameters(string $method): array {
$params = [];
switch ($method) {
case 'GET':
$params = $_GET;
break;
case 'POST':
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
if (strpos($contentType, 'application/json') !== false) {
$body = file_get_contents('php://input');
$params = json_decode($body, true) ?? [];
} else {
$params = $_POST;
}
break;
default:
$body = file_get_contents('php://input');
$params = json_decode($body, true) ?? [];
// 也解析查询字符串
$params = array_merge($_GET, $params);
}
return $params;
}
private static function preventSQLInjection(array $params): array {
// 使用参数化查询是最好的,这里仅做基本清理
foreach ($params as $key => $value) {
if (is_string($value)) {
// 移除危险的SQL字符
$value = str_replace(
["'", '"', ';', '--', '/*', '*/', 'xp_'],
'',
$value
);
$params[$key] = $value;
}
}
return $params;
}
private static function preventXSS(array $params): array {
array_walk_recursive($params, function(&$value) {
if (is_string($value)) {
$value = htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
});
return $params;
}
}
// 使用示例
try {
$safeParams = APISecurity::validateRequest();
// 处理业务逻辑...
} catch (\Exception $e) {
http_response_code($e->getCode() ?: 500);
echo json_encode(['error' => $e->getMessage()]);
}
最佳实践建议
- 始终使用白名单验证:只接受预期格式的数据
- 输入验证:验证数据类型、长度、范围
- 输出编码:防止XSS攻击
- 使用参数化查询:防止SQL注入
- 限制请求大小:防止DoS攻击
- 实施速率限制:保护API免受过载
选择哪种方法取决于你的项目需求,对于生产环境,建议使用成熟的第三方库如 Respect\Validation 或 Symfony Validator。