Отправка контента через HTTP-запросы в PHP: практическое руководство

Раздел: -> HTTP запросы

Основные подходы к отправке данных через HTTP в PHP

Наиболее эффективное решение: использование библиотеки cURL

Функционал cURL (Client URL Library) предоставляет разработчику полный контроль над HTTP-запросами: управление заголовками, телом, методами, таймаутами, SSL-сертификатами. Это встроенное расширение PHP, не требующее установки дополнительных пакетов. Для отправки контента (POST-запросов) cURL является оптимальным выбором в большинстве сценариев, особенно при работе с API, которые требуют специфических заголовков или аутентификации.


$ch = curl_init('https://api.example.com/endpoint');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
$data = ['name' => 'John', 'age' => 30];
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
$response = curl_exec($ch);
if (curl_errno($ch)) {
    $error = curl_error($ch);
    // обработка ошибки
}
curl_close($ch);

В примере создаётся сессия cURL, указывается целевой URL, активируется метод POST, данные передаются в виде строки запроса (application/x-www-form-urlencoded). Функция curl_exec выполняет запрос, результат сохраняется в переменной. Ошибки обрабатываются через curl_errno и curl_error.

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

  • Неверный Content-Type: если сервер ожидает JSON, необходимо установить заголовок Content-Type: application/json и передать данные через json_encode внутри CURLOPT_POSTFIELDS.
  • Проблемы с SSL: на локальных серверах с самоподписанными сертификатами может потребоваться CURLOPT_SSL_VERIFYPEER = false (не рекомендуется в продакшене).
  • Таймауты: необходимо задавать CURLOPT_TIMEOUT и CURLOPT_CONNECTTIMEOUT.

Как отправить POST-запрос без использования внешних библиотек?

Встроенная функция file_get_contents с контекстом потока (stream_context_create) позволяет отправлять простые запросы. Подходит для лёгких задач, не требующих сложной настройки.


$options = [
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query(['key' => 'value'])
    ]
];
$context = stream_context_create($options);
$response = file_get_contents('https://httpbin.org/post', false, $context);

Проблемы: отсутствие контроля над временем ожидания, невозможность сохранить промежуточные заголовки ответа, сложность обработки ошибок (неудачный запрос возвращает false и генерирует warning).

Как использовать Guzzle для современной отправки запросов?

Guzzle – популярная библиотека PHP, предоставляющая объектно-ориентированный интерфейс, поддержку PSR-7, асинхронные запросы и middleware. Устанавливается через Composer.


use GuzzleHttp\Client;

$client = new Client();
$response = $client->post('https://api.example.com/data', [
    'form_params' => ['username' => 'admin', 'password' => '123']
]);
$body = $response->getBody()->getContents();

Ошибки: если не обработать исключения (GuzzleHttp\Exception\ClientException), скрипт может прерваться. Также требуется правильная настройки таймаутов и перенаправлений.

Как эмулировать браузерные формы и загружать файлы?

Для отправки multipart/form-data (например, загрузка файлов) cURL и Guzzle поддерживают автоматическую кодировку.


$file = new CURLFile('/path/to/image.jpg', 'image/jpeg', 'photo.jpg');
curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => $file, 'description' => 'Avatar']);

Как отправлять запросы с низкоуровневым доступом через fsockopen?

Функция fsockopen открывает сокет и позволяет вручную формировать HTTP-сообщение. Используется крайне редко, в специфических случаях, когда требуется полный контроль над сетевым уровнем.


$fp = fsockopen('ssl://api.example.com', 443, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)\n";
} else {
    $out = "POST /endpoint HTTP/1.1\r\n";
    $out .= "Host: api.example.com\r\n";
    $out .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $body = 'key=value';
    $out .= "Content-Length: " . strlen($body) . "\r\n";
    $out .= "Connection: Close\r\n\r\n";
    $out .= $body;
    fwrite($fp, $out);
    while (!feof($fp)) {
        echo fgets($fp, 128);
    }
    fclose($fp);
}

Сложность: необходимо вручную разбирать ответ, обрабатывать chunked encoding, перенаправления. Часто возникают ошибки при формировании заголовков (неправильные переводы строк).

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

Пример 1: Отправка JSON через cURL с правильными заголовками и обработка ответа

Пример

$url = 'https://jsonplaceholder.typicode.com/posts';
$data = ['title' => 'foo', 'body' => 'bar', 'userId' => 1];
$json = json_encode($data);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Content-Length: ' . strlen($json)
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode >= 200 && $httpCode < 300) {
    $decoded = json_decode($response, true);
    print_r($decoded);
} else {
    echo "Ошибка HTTP: $httpCode";
}
Array
(
    [title] => foo
    [body] => bar
    [userId] => 1
    [id] => 101
)

Пример 2: Загрузка файла с помощью cURL (multipart/form-data)

Пример

$url = 'https://httpbin.org/post';
$filePath = '/tmp/test.txt';
$file = curl_file_create($filePath, 'text/plain', 'file.txt');

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['upload' => $file, 'description' => 'Пример']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
{
  "files": {"upload": "... content of file ..."},
  "form": {"description": "Пример"}
}

Пример 3: Асинхронный запрос с Guzzle Promises

Пример

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['base_uri' => 'https://api.example.com']);
$promises = [
    'users' => $client->getAsync('/users'),
    'posts' => $client->getAsync('/posts')
];

$results = Promise\settle($promises)->wait();
foreach ($results as $key => $result) {
    if ($result['state'] === 'fulfilled') {
        echo $key . ': ' . $result['value']->getBody() . "\n";
    } else {
        echo $key . ' failed: ' . $result['reason'] . "\n";
    }
}

Пример 4: Отправка запроса с авторизацией по Bearer токену через Guzzle

Пример

$client = new Client([
    'headers' => [
        'Authorization' => 'Bearer eyJhbGciOiJIUzI1NiIs...'
    ]
]);
$response = $client->post('https://api.secure.com/data', [
    'json' => ['action' => 'read']
]);
echo $response->getStatusCode();

Пример 5: Использование stream_context для отправки JSON с проверкой ошибок

Пример

$data = json_encode(['test' => true]);
$options = [
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/json\r\nContent-Length: " . strlen($data) . "\r\n",
        'content' => $data,
        'ignore_errors' => true  // предотвращает warning при HTTP-ошибках
    ]
];
$context = stream_context_create($options);
$result = @file_get_contents('https://httpbin.org/status/400', false, $context);
if ($result === false) {
    $error = error_get_last();
    echo "Ошибка: " . $error['message'];
} else {
    echo $result;
}
Ошибка: file_get_contents(https://httpbin.org/status/400): Failed to open stream: HTTP request failed! HTTP/1.1 400 BAD REQUEST

Пример 6: cURL с прокси и таймаутами

Пример

$proxy = 'tcp://proxy.example.com:8080';
$ch = curl_init('https://api.ipify.org');
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$ip = curl_exec($ch);
curl_close($ch);
echo $ip;

Отправка контента по HTTP в PHP - comments

En
Http content php (php)