Сетевое программирование в PHP: Как вручную сформировать POST-запрос через fwrite и fsockopen с передачей хоста, пути и заголовков HTTP 1.1?

Сетевое программирование в PHP позволяет отправлять HTTP-запросы напрямую через сокеты, минуя высокоуровневые обёртки вроде cURL или file_get_contents. Это даёт полный контроль над формируемым запросом и полезно для понимания протокола HTTP изнутри.

## Основы: fsockopen и fwrite

Функция `fsockopen()` открывает TCP-соединение с удалённым сервером и возвращает файловый дескриптор, с которым можно работать как с обычным файлом — читать через `fread()`/`fgets()` и писать через `fwrite()`.

Сигнатура:
php
$socket = fsockopen($host, $port, $errno, $errstr, $timeout);

## Структура HTTP 1.1 POST-запроса

ПОСТ-запрос по протоколу HTTP 1.1 состоит из:
1. **Стартовой строки**: метод, путь, версия протокола.
2. **Заголовков**: Host, Content-Type, Content-Length, Connection и др.
3. **Пустой строки** (разделитель заголовков и тела).
4. **Тела запроса** (payload).

## Пример кода

php
‘john’,
‘password’ => ‘secret123’,
]);

// Открываем сокет
$socket = fsockopen($host, $port, $errno, $errstr, $timeout);

if (!$socket) {
die(«Ошибка подключения: $errstr ($errno)n»);
}

// Формируем HTTP 1.1 POST-запрос
$request = «POST {$path} HTTP/1.1rn»;
$request .= «Host: {$host}rn»;
$request .= «Content-Type: application/x-www-form-urlencodedrn»;
$request .= «Content-Length: » . strlen($postData) . «rn»;
$request .= «Connection: closern»;
$request .= «rn»; // Обязательная пустая строка!
$request .= $postData;

// Отправляем запрос
fwrite($socket, $request);

// Читаем ответ
$response = »;
while (!feof($socket)) {
$response .= fgets($socket, 1024);
}

fclose($socket);

echo $response;
?>

## Ключевые моменты

— **`rn`** — обязательный разделитель строк в HTTP (CRLF), не просто `n`.
— **`Content-Length`** должен точно совпадать с длиной тела в байтах (`strlen()`).
— **`Connection: close`** — сервер закроет соединение после ответа, что упрощает чтение.
— Для HTTPS используйте `ssl://` как префикс хоста и порт 443: `fsockopen(‘ssl://example.com’, 443, …)`.
— Заголовок `Host` обязателен в HTTP 1.1 — без него сервер вернёт ошибку 400.

## Отправка JSON

Если нужно отправить JSON, измените Content-Type:
php
$postData = json_encode([‘key’ => ‘value’]);
$request .= «Content-Type: application/jsonrn»;

## Добавление авторизации

Для Basic Auth добавьте заголовок:
php
$request .= «Authorization: Basic » . base64_encode(‘user:pass’) . «rn»;

Такой подход даёт максимальную гибкость и помогает глубоко понять работу HTTP-протокола.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.