Сетевое программирование в 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-протокола.
