Продвинутая работа с API на PHP: от запросов до безопасности

Современные приложения редко живут изолированно. API — это мост между вашим бэкендом, фронтендом, мобильными приложениями и сторонними сервисами. Разбираем production-ready подходы к созданию API на PHP.

PHP API разработка

Основы RESTful API

REST — архитектурный стиль, который использует HTTP методы для операций с ресурсами.

  • GET — получение ресурса (список или один элемент)
  • POST — создание нового ресурса
  • PUT — полное обновление ресурса
  • PATCH — частичное обновление
  • DELETE — удаление ресурса

Правильные URL: GET /users, GET /users/123, POST /users, PUT /users/123, DELETE /users/123.

Структура современного PHP API

api/
├── index.php // точка входа, роутинг
├── .htaccess // перенаправление всех запросов на index.php
├── config/
│ └── database.php // подключение к БД
├── src/
│ ├── Controllers/ // обработка запросов
│ ├── Models/ // работа с БД
│ ├── Middleware/ // аутентификация, CORS, rate limiting
│ └── Helpers/ // вспомогательные функции
└── vendor/ // composer зависимости

Базовый роутер (без фреймворков)

<?php
// index.php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path = str_replace('/api', '', $path);
$segments = explode('/', trim($path, '/'));

$resource = $segments[0] ?? null;
$id = $segments[1] ?? null;

switch ($resource) {
    case 'users':
        $controller = new UserController();
        if ($method === 'GET' && $id) {
            $controller->show($id);
        } elseif ($method === 'GET') {
            $controller->index();
        } elseif ($method === 'POST') {
            $controller->store();
        } elseif ($method === 'PUT' && $id) {
            $controller->update($id);
        } elseif ($method === 'DELETE' && $id) {
            $controller->destroy($id);
        }
        break;
    default:
        http_response_code(404);
        echo json_encode(['error' => 'Not Found']);
}

JWT аутентификация

JSON Web Token — современный стандарт авторизации. Токен содержит информацию о пользователе и подпись.

// composer require firebase/php-jwt
use Firebase\JWT\JWT;
use Firebase\JWT\Key;

class AuthMiddleware {
    private static $secret = 'your-secret-key-here';
    
    public static function generateToken($userId, $email) {
        $payload = [
            'user_id' => $userId,
            'email' => $email,
            'iat' => time(),
            'exp' => time() + 3600 // 1 час
        ];
        return JWT::encode($payload, self::$secret, 'HS256');
    }
    
    public static function authenticate() {
        $headers = getallheaders();
        $authHeader = $headers['Authorization'] ?? '';
        $token = str_replace('Bearer ', '', $authHeader);
        
        try {
            $decoded = JWT::decode($token, new Key(self::$secret, 'HS256'));
            return (array) $decoded;
        } catch (Exception $e) {
            http_response_code(401);
            echo json_encode(['error' => 'Unauthorized']);
            exit;
        }
    }
}
API безопасность

Обработка ошибок и валидация

// Пример контроллера с валидацией
class UserController {
    public function store() {
        $input = json_decode(file_get_contents('php://input'), true);
        
        $errors = [];
        if (empty($input['email'])) {
            $errors['email'] = 'Email is required';
        }
        if (strlen($input['password'] ?? '') < 8) {
            $errors['password'] = 'Password must be at least 8 characters';
        }
        
        if (!empty($errors)) {
            http_response_code(422);
            echo json_encode(['errors' => $errors]);
            return;
        }
        
        // Сохранение в БД...
    }
}

Rate Limiting (защита от DDoS и брутфорса)

// Простой rate limiter через Redis или файлы
function rateLimit($key, $maxRequests = 60, $timeWindow = 60) {
    $ip = $_SERVER['REMOTE_ADDR'];
    $cacheKey = "rate_limit_{$key}_{$ip}";
    
    // Используем APC или Redis. Для примера — файл
    $file = sys_get_temp_dir() . '/' . md5($cacheKey);
    $data = file_exists($file) ? json_decode(file_get_contents($file), true) : ['count' => 0, 'reset' => time() + $timeWindow];
    
    if (time() > $data['reset']) {
        $data = ['count' => 0, 'reset' => time() + $timeWindow];
    }
    
    $data['count']++;
    file_put_contents($file, json_encode($data));
    
    if ($data['count'] > $maxRequests) {
        http_response_code(429);
        echo json_encode(['error' => 'Too Many Requests']);
        exit;
    }
}

Кэширование ответов API

// Кэширование GET-запросов на 5 минут
function cacheGet($key, $ttl = 300, $callback) {
    $cacheFile = sys_get_temp_dir() . '/api_cache_' . md5($key);
    
    if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $ttl) {
        $data = file_get_contents($cacheFile);
        echo $data;
        return;
    }
    
    $result = $callback();
    $json = json_encode($result);
    file_put_contents($cacheFile, $json);
    echo $json;
}

// Использование
cacheGet('users_list', 300, function() {
    // Тяжёлый запрос к БД
    return User::getAll();
});

CORS (Cross-Origin Resource Sharing)

Без правильных CORS-заголовков ваш API не сможет вызывать фронтенд с другого домена.

// Настройка CORS для всех запросов
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    header('Access-Control-Allow-Origin: https://my-frontend.com');
    header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE');
    header('Access-Control-Allow-Headers: Content-Type, Authorization');
    http_response_code(200);
    exit;
}

Версионирование API

Со временем API меняется. Не ломайте старых клиентов — используйте версионирование.

  • Через URL: /api/v1/users, /api/v2/users
  • Через заголовок: Accept: application/vnd.myapi.v1+json

Заключение: Современный API — это больше, чем просто обработка запросов. Это безопасность, кэширование, rate limiting, документация (OpenAPI/Swagger) и мониторинг. Начните с малого: реализуйте CRUD для одной сущности, добавьте JWT-аутентификацию и rate limiting. Постепенно усложняйте. Production-ready API требует внимания к деталям, но результат стоит усилий.