Написание серверного кода на PHP: практическое руководство для разработчиков

Раздел: Программирование PHP -> Серверное программирование

Основы написания серверного кода на PHP

Наиболее эффективным решением для построения серверной логики на PHP является использование объектно-ориентированного подхода с разделением ответственности. Вместо работы с суперглобальными массивами напрямую, рекомендуется создать классы-обёртки для запроса (Request) и ответа (Response), а также центральный обработчик (Router). Такой подход обеспечивает тестируемость, расширяемость и соответствие современным стандартам (PSR-7, PSR-15).

Пример базовой структуры


// Request.php
class Request {
    private array $data;
    public function __construct() {
        $this->data = array_merge($_GET, $_POST, json_decode(file_get_contents('php://input'), true) ?? []);
    }
    public function getParam(string $key, $default = null) {
        return $this->data[$key] ?? $default;
    }
    public function getMethod(): string {
        return $_SERVER['REQUEST_METHOD'];
    }
}

// Response.php
class Response {
    private int $statusCode;
    private array $headers;
    private mixed $body;

    public function __construct(mixed $body = '', int $status = 200, array $headers = []) {
        $this->body = $body;
        $this->statusCode = $status;
        $this->headers = $headers;
    }

    public function send(): void {
        http_response_code($this->statusCode);
        foreach ($this->headers as $name => $value) {
            header("$name: $value");
        }
        if (is_array($this->body) || is_object($this->body)) {
            header('Content-Type: application/json');
            echo json_encode($this->body);
        } else {
            echo $this->body;
        }
    }
}

// index.php (точка входа)
require 'Request.php';
require 'Response.php';

$request = new Request();
$response = new Response();

if ($request->getMethod() === 'GET' && $request->getParam('action') === 'hello') {
    $response = new Response(['message' => 'Hello, ' . $request->getParam('name', 'World')]);
}
$response->send();

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

Пояснение шагов

  1. Создаются классы Request и Response для инкапсуляции данных входящего запроса и построения ответа.
  2. Точка входа index.php обрабатывает все запросы (front controller).
  3. Анализируется метод и параметры, формируется ответ.
  4. Метод send() отправляет заголовки и тело.

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

  • Проблема: Если не обрабатывать ошибки, приложение может выдать неинформативное сообщение. Решение: Реализовать глобальный обработчик исключений через set_exception_handler.
  • Проблема: Заголовки могут быть отправлены дважды. Решение: Перед вызовом send() убедиться, что не было вывода в stdout (например, через ob_start).

Как быстро обработать GET/POST запрос без фреймворка?

Процедурный подход с использованием суперглобальных массивов $_GET, $_POST и $_SERVER подходит для очень простых скриптов, где не требуется сложная маршрутизация.


// simple_form.php
$name = $_POST['name'] ?? 'гость';
echo "Привет, $name!";

Пояснение

  • Данные из формы доступны через $_POST.
  • Оператор ?? задаёт значение по умолчанию.
  • Вывод сразу отправляется клиенту.

Типичные ошибки

  • Отсутствие проверки на наличие ключей приводит к ошибке Undefined array key.
  • Неверный тип данных (например, строка вместо числа) без валидации.
  • Решение: использовать filter_input() или собственную валидацию.

Как запустить встроенный сервер PHP для разработки?

Встроенный сервер (CLI-сервер) позволяет тестировать приложение без установки Apache или Nginx.


# Запуск в корне проекта
php -S localhost:8000 -t public/

Параметр -t указывает корневую директорию. Все запросы направляются в index.php, если не найден статический файл.

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

  • Сервер перезапускается после каждого изменения кода (не горячая замена).
  • Не поддерживает многопоточность.
Как реализовать маршрутизацию с использованием микрофреймворка Slim?

Микрофреймворки, такие как Slim, предоставляют удобную маршрутизацию, middleware и внедрение зависимостей.


// index.php с Slim 4
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('/hello/{name}', function (Request $request, Response $response, array $args) {
    $name = $args['name'];
    $response->getBody()->write("Hello, $name");
    return $response;
});

$app->run();

Пояснение

  • Маршруты определяются с помощью методов get(), post() и т.д.
  • Параметры из URI передаются в замыкание через $args.
  • Ответ формируется через объект $response.

Типичные ошибки

  • Отсутствие автозагрузки Composer: классы не будут найдены.
  • Неверная версия PHP (требуется PHP 8.0+ для Slim 4).

Каждый из этих вариантов подходит для разных сценариев: процедурный код – для быстрых прототипов, встроенный сервер – для локальной отладки, микрофреймворк – для серьёзных приложений с чёткой архитектурой. Выбор зависит от масштабов проекта и требований к сопровождаемости.

Расширенные примеры серверного кода на PHP

1. Обработка JSON-запросов и формирование RESTful ответа

Пример

// api.php - универсальный обработчик REST
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

// Извлечение тела запроса в JSON
$body = json_decode(file_get_contents('php://input'), true);

// Простой роутинг
if ($uri === '/users' && $method === 'GET') {
    header('Content-Type: application/json');
    // Имитация выборки из БД
    $users = [
        ['id' => 1, 'name' => 'Анна'],
        ['id' => 2, 'name' => 'Борис']
    ];
    echo json_encode($users);
} elseif ($uri === '/users' && $method === 'POST') {
    if ($body === null) {
        http_response_code(400);
        echo json_encode(['error' => 'Неверный JSON']);
        exit;
    }
    // Сохранение пользователя (имитация)
    http_response_code(201);
    echo json_encode(['id' => 3, 'name' => $body['name'] ?? 'Неизвестный']);
} else {
    http_response_code(404);
    echo json_encode(['error' => 'Маршрут не найден']);
}
Пример вызова:
curl -X POST -H "Content-Type: application/json" -d '{"name":"Виктор"}' http://localhost:8000/api.php/users
Ответ: {"id":3,"name":"Виктор"}

2. Работа с базой данных через PDO (подготовленные запросы)

Пример

// db.php - подключение к MySQL и безопасный запрос
$dsn = 'mysql:host=localhost;dbname=myapp;charset=utf8mb4';
$user = 'root';
$pass = '';

try {
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
    ]);
} catch (PDOException $e) {
    http_response_code(500);
    echo json_encode(['error' => 'Ошибка БД: ' . $e->getMessage()]);
    exit;
}

// Пример вставки с подготовленным выражением
$stmt = $pdo->prepare('INSERT INTO users (name, email) VALUES (:name, :email)');
$stmt->execute([
    ':name' => $_POST['name'] ?? '',
    ':email' => filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL)
]);

if ($stmt->rowCount() > 0) {
    echo json_encode(['success' => true, 'last_id' => $pdo->lastInsertId()]);
} else {
    http_response_code(500);
    echo json_encode(['error' => 'Не удалось вставить запись']);
}
Пример запроса:
curl -d "name=Мария&email=maria@example.com" http://localhost:8000/db.php
Результат: {"success":true,"last_id":10}

3. Обработка загрузки файлов

Пример

// upload.php
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('Метод не разрешён');
}

$uploadDir = __DIR__ . '/uploads/';
if (!is_dir($uploadDir)) {
    mkdir($uploadDir, 0755, true);
}

$file = $_FILES['file'] ?? null;
if (!$file || $file['error'] !== UPLOAD_ERR_OK) {
    http_response_code(400);
    exit('Ошибка загрузки файла');
}

$allowedTypes = ['image/jpeg', 'image/png'];
if (!in_array($file['type'], $allowedTypes)) {
    http_response_code(400);
    exit('Недопустимый тип файла');
}

$filename = uniqid() . '_' . basename($file['name']);
if (move_uploaded_file($file['tmp_name'], $uploadDir . $filename)) {
    echo json_encode(['file' => $filename, 'size' => $file['size']]);
} else {
    http_response_code(500);
    exit('Не удалось сохранить файл');
}
Вызов:
curl -F "file=@photo.png" http://localhost:8000/upload.php
Ответ: {"file":"64f3a2b1c9d7e_photo.png","size":12345}

4. Использование сессий для аутентификации

Пример

// login.php
session_start();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $username = $_POST['username'] ?? '';
    $password = $_POST['password'] ?? '';

    // Имитация проверки (в реальности - хеши паролей и БД)
    if ($username === 'admin' && $password === 'secret') {
        $_SESSION['user'] = $username;
        session_regenerate_id(true);
        header('Location: dashboard.php');
        exit;
    } else {
        $error = 'Неверное имя пользователя или пароль';
    }
}

// dashboard.php (проверка аутентификации)
session_start();
if (!isset($_SESSION['user'])) {
    header('Location: login.php');
    exit;
}
echo 'Добро пожаловать, ' . htmlspecialchars($_SESSION['user']);

Примечание

Хранение паролей в открытом виде недопустимо. Для хеширования используется password_hash() и password_verify().

5. Простой middleware для логирования запросов (на чистом PHP)

Пример

// middleware.php - обёртка обработчика
function withLogging(callable $handler): callable {
    return function () use ($handler) {
        $start = microtime(true);
        $result = $handler();
        $elapsed = microtime(true) - $start;
        error_log("[" . date('Y-m-d H:i:s') . "] " .
            $_SERVER['REQUEST_METHOD'] . " " .
            $_SERVER['REQUEST_URI'] . " - " .
            round($elapsed * 1000, 2) . "ms");
        return $result;
    };
}

// Использование
$handler = function () {
    echo 'Hello';
};

withLogging($handler)();
В логах:
[2025-04-10 12:00:00] GET /index.php - 2.34 ms

Эти примеры демонстрируют реальные сценарии, с которыми сталкивается разработчик серверной части на PHP: работа с запросами, БД, файлами, сессиями и middleware. Каждый блок можно адаптировать под конкретный проект.

Написание кода сервера на PHP - comments

En
код сервера на php (php)