Веб-сервисы на PHP: от простого REST к сложным интеграциям

Раздел: PHP -> Веб-разработка на PHP

Создание веб-сервисов на PHP

Веб-сервисы позволяют приложениям обмениваться данными через HTTP. PHP предоставляет множество инструментов для их построения – от встроенных функций до мощных фреймворков. Рассмотрим наиболее эффективные и альтернативные подходы.

Основное решение: микрофреймворк Slim для REST API

Slim – легковесный фреймворк, идеально подходящий для быстрой разработки RESTful веб-сервисов. Он предоставляет маршрутизацию, middleware и удобную работу с PSR-7 сообщениями.

Как создать простой REST API на Slim, возвращающий JSON?

composer require slim/slim:^4
composer require slim/http

App path php (работа с путями файлов в php)

Создаём файл public/index.php:

<?php
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Slim\Factory\AppFactory;

require __DIR__ . '/../vendor/autoload.php';

$app = AppFactory::create();

$app->get('/api/hello/{name}', function (Request $request, Response $response, array $args) {
    $name = htmlspecialchars($args['name']);
    $data = ['message' => "Hello, $name"];
    $response->getBody()->write(json_encode($data));
    return $response->withHeader('Content-Type', 'application/json');
});

$app->run();

App php domain (работа с доменами в php)

Запустите встроенный сервер: php -S localhost:8080 -t public. Теперь GET-запрос к /api/hello/Max вернёт {"message":"Hello, Max"}.

Типичные проблемы и решения:

  • Ошибка 404 при запросе – убедитесь, что сервер настроен на директорию public и все запросы направляются на index.php (через .htaccess или nginx config).
  • Проблемы с CORS – добавьте middleware для заголовка Access-Control-Allow-Origin. Slim поддерживает slim/cors.
  • Неправильная сериализация – используйте json_encode с флагами JSON_UNESCAPED_UNICODE для поддержки UTF-8.

Вариант 1: Веб-сервис на чистом PHP без фреймворков

Как обработать URL и вернуть JSON, используя только встроенные возможности PHP?

<?php
// index.php
header('Content-Type: application/json; charset=utf-8');

$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// Простейшая маршрутизация
if ($path === '/api/status' && $method === 'GET') {
    echo json_encode(['status' => 'OK', 'time' => time()]);
} else {
    http_response_code(404);
    echo json_encode(['error' => 'Not Found']);
}

Http user agent php (получение user-agent в php)

Возможные сложности:

  • Отсутствие нормализации входных данных – параметры из $_GET и $_POST требуют фильтрации через filter_input или htmlspecialchars.
  • Обработка тела запроса – для PUT/PATCH данные приходят в php://input, их нужно разобрать через file_get_contents('php://input') и декодировать из JSON.
  • Сложность поддержки – при росте числа эндпоинтов код становится нечитаемым; рекомендуется хотя бы выделить маршруты в отдельный файл.

Вариант 2: Веб-сервис на Symfony (HTTP Foundation + Routing)

Как использовать компоненты Symfony для создания более структурированного API без полного фреймворка?

composer require symfony/http-foundation symfony/runtime
# composer.json
{
    "autoload": {
        "psr-4": { "App\\": "src/" }
    }
}

Config app php (конфигурация php приложения)

Создаём контроллер src/Controller/ApiController.php:

<?php
namespace App\Controller;

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;

class ApiController
{
    public function status(Request $request): JsonResponse
    {
        return new JsonResponse(['status' => 'running']);
    }
}

создание скриптов php (создание скриптов php)

Ошибки конфигурации:

  • Автозагрузка не работает – выполните composer dump-autoload и проверьте пространство имён.
  • Маршруты не обрабатываются – вручную подключите Router или используйте Symfony FrameworkBundle для полноценного приложения. В простом варианте придётся самостоятельно сопоставлять URI.

Вариант 3: Веб-сервис на Laravel (или Lumen)

Как построить полнофункциональный REST API с помощью Laravel, включая аутентификацию и Eloquent?

composer create-project laravel/laravel example-api
php artisan make:controller Api/UserController --resource --api

App php route (маршрутизация в php приложении)

Пример контроллера:

<?php
namespace App\Http\Controllers\Api;

use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class UserController extends Controller
{
    public function index()
    {
        return User::all();
    }

    public function show($id)
    {
        $user = User::find($id);
        if (!$user) return response()->json(['error' => 'User not found'], 404);
        return $user;
    }
}

Php create html (создание html в php)

Добавьте маршрут в routes/api.php:

Route::apiResource('users', 'Api\UserController');

Default php app (настройки по умолчанию в php приложении)

Распространённые трудности:

  • Медленная работа при большом количестве запросов – используйте кеширование (Redis) и пагинацию.
  • Неверные заголовки ответа – Laravel автоматически добавляет Content-Type: application/json при возврате массивов или коллекций через response()->json().
  • Проблемы с аутентификацией – в Laravel 11 используется Sanctum или Passport; для простого API достаточно токенов в заголовке Bearer.

Вариант 4: SOAP-сервис на PHP

Как реализовать классический SOAP веб-сервис с WSDL?

<?php
class Calculator
{
    public function add($a, $b)
    {
        return $a + $b;
    }
}

$options = ['uri' => 'http://example.com/soap'];
$server = new SoapServer(null, $options);
$server->setClass('Calculator');
$server->handle();

Но для корректной генерации WSDL рекомендуется использовать библиотеки типа php-soap-ext или WSDL-генераторы.

Сложности SOAP:

  • Громоздкая структура – требуется XML-сериализация, что медленнее JSON.
  • Трудности с отладкой – сообщения об ошибках обычно скрыты; используйте SoapServer::setPersistence() и логи.
  • Сложность с WSDL – создание вручную требует времени; альтернатива – фреймворки вроде zend-soap.
- App php link (создание ссылок в php приложении)
- App controller php (создание контроллера в php приложении)
- Php веб страница (веб-страница на php)

Расширенные примеры создания PHP веб-сервисов

Пример 1: REST API с аутентификацией JWT на Slim

Установите пакет firebase/php-jwt и создайте middleware.

Пример
composer require firebase/php-jwt
Пример
<?php
// middleware/AuthMiddleware.php
namespace App\Middleware;

use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as Handler;
use Slim\Psr7\Response;

class AuthMiddleware
{
    private $secretKey = 'your-secret-key-here';

    public function __invoke(Request $request, Handler $handler): Response
    {
        $authHeader = $request->getHeaderLine('Authorization');
        if (empty($authHeader) || !str_starts_with($authHeader, 'Bearer ')) {
            $response = new Response();
            $response->getBody()->write(json_encode(['error' => 'Unauthorized']));
            return $response->withStatus(401)->withHeader('Content-Type', 'application/json');
        }

        $token = substr($authHeader, 7);
        try {
            $decoded = JWT::decode($token, new Key($this->secretKey, 'HS256'));
            $request = $request->withAttribute('user_id', $decoded->sub);
            return $handler->handle($request);
        } catch (\Exception $e) {
            $response = new Response();
            $response->getBody()->write(json_encode(['error' => 'Token invalid']));
            return $response->withStatus(401)->withHeader('Content-Type', 'application/json');
        }
    }
}

Примените middleware к защищённым маршрутам:

Пример
$app->get('/api/profile', function ($request, $response) {
    $userId = $request->getAttribute('user_id');
    // ... получение данных пользователя
    $data = ['id' => $userId, 'name' => 'John'];
    $response->getBody()->write(json_encode($data));
    return $response->withHeader('Content-Type', 'application/json');
})->add(new \App\Middleware\AuthMiddleware());

Результат GET-запроса с неправильным токеном:

{"error":"Token invalid"}

Пример 2: Обработка входящих JSON-данных в чистом PHP

Создайте эндпоинт для создания пользователя:

Пример
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['REQUEST_URI'] === '/api/users') {
    $input = json_decode(file_get_contents('php://input'), true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        http_response_code(400);
        echo json_encode(['error' => 'Invalid JSON']);
        exit;
    }
    $name = isset($input['name']) ? trim($input['name']) : '';
    if (empty($name)) {
        http_response_code(422);
        echo json_encode(['error' => 'Name is required']);
        exit;
    }
    // Сохранение в БД (пример с PDO)
    $pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
    $stmt = $pdo->prepare('INSERT INTO users (name) VALUES (:name)');
    $stmt->execute(['name' => $name]);
    $id = $pdo->lastInsertId();
    http_response_code(201);
    echo json_encode(['id' => $id, 'name' => $name]);
}

Отправка запроса через curl:

curl -X POST http://localhost:8080/api/users -H "Content-Type: application/json" -d '{"name":"Alice"}'
{"id":1,"name":"Alice"}

Пример 3: Веб-сервис с передачей файлов через multipart/form-data

Используем микрофреймворк Slim для загрузки изображения.

Пример
$app->post('/api/upload', function (Request $request, Response $response) {
    $uploadedFiles = $request->getUploadedFiles();
    if (empty($uploadedFiles['avatar'])) {
        $response->getBody()->write(json_encode(['error' => 'No file uploaded']));
        return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
    }
    $avatar = $uploadedFiles['avatar'];
    if ($avatar->getError() !== UPLOAD_ERR_OK) {
        $response->getBody()->write(json_encode(['error' => 'Upload failed']));
        return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
    }
    $newFilename = uniqid() . '-' . $avatar->getClientFilename();
    $avatar->moveTo('uploads/' . $newFilename);
    $response->getBody()->write(json_encode(['filename' => $newFilename]));
    return $response->withHeader('Content-Type', 'application/json');
});

Проверка через curl:

curl -X POST -F "avatar=@/path/to/photo.jpg" http://localhost:8080/api/upload
{"filename":"657f3a2b1c0d4-photo.jpg"}

Пример 4: Веб-сервис с графическим интерфейсом (RAML/OpenAPI)

Генерация документации с помощью swagger-php.

Пример
composer require zircote/swagger-php

Добавьте аннотации к контроллеру:

Пример
/**
 * @OA\Get(
 *     path="/api/status",
 *     @OA\Response(response="200", description="Returns server status")
 * )
 */
public function status() { ... }

Генерация спецификации:

Пример
vendor/bin/openapi --output public/swagger.json src/

PHP веб-сервисы - comments

En
Php веб сервисы (php)