PHPAPI过滤参数怎么解析

wen PHP项目 4

本文目录导读:

PHPAPI过滤参数怎么解析

  1. 基础过滤方法
  2. 使用自定义过滤函数
  3. 使用第三方库
  4. RESTful API 参数解析
  5. 完整的API验证示例
  6. 最佳实践建议

在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()]);
}

最佳实践建议

  1. 始终使用白名单验证:只接受预期格式的数据
  2. 输入验证:验证数据类型、长度、范围
  3. 输出编码:防止XSS攻击
  4. 使用参数化查询:防止SQL注入
  5. 限制请求大小:防止DoS攻击
  6. 实施速率限制:保护API免受过载

选择哪种方法取决于你的项目需求,对于生产环境,建议使用成熟的第三方库如 Respect\Validation 或 Symfony Validator。

抱歉,评论功能暂时关闭!