Отправка POST данных через cURL в PHP: особенности реализации

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

Основной способ отправки POST запроса через cURL

Базовый алгоритм включает инициализацию сеанса, установку параметров и выполнение запроса. Ниже приведён минимальный рабочий пример.


<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://example.com/api');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['name' => 'John', 'email' => 'john@example.com']));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_errno($ch)) {
    $error = curl_error($ch);
}
curl_close($ch);
?>

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

  1. curl_init() создаёт новый сеанс.
  2. CURLOPT_URL задаёт адрес назначения.
  3. CURLOPT_POST включает метод POST.
  4. CURLOPT_POSTFIELDS принимает строку или массив (рекомендуется использовать http_build_query для правильного кодирования).
  5. CURLOPT_RETURNTRANSFER гарантирует, что результат будет возвращён в переменную, а не выведен напрямую.
  6. curl_exec() выполняет запрос.
  7. curl_errno() и curl_error() проверяют наличие ошибок.
  8. curl_close() закрывает сеанс.

Типичные ошибки и их решения

  • Ошибка SSL: Если сервер использует самоподписанный сертификат, может возникнуть ошибка проверки. Решение - отключить проверку CURLOPT_SSL_VERIFYPEER => false (не рекомендуется для продакшена).
  • Таймаут: Долгий ответ можно обработать, установив CURLOPT_TIMEOUT => 30 (секунды).
  • Некорректный Content-Type: Если сервер ожидает application/x-www-form-urlencoded, то передача строки через http_build_query - правильный подход. Для других типов данных нужно указывать заголовки явно.

Варианты отправки POST запросов

Как отправить POST запрос с JSON данными?

Для отправки JSON необходимо установить заголовок Content-Type: application/json и передать строку JSON в CURLOPT_POSTFIELDS.


<?php
$data = ['username' => 'admin', 'password' => 'secret'];
$ch = curl_init('https://example.com/auth');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>

Возможные проблемы

  • Если забыть установить заголовок Content-Type, сервер может не интерпретировать данные как JSON.
  • При работе с кириллицей необходимо убедиться, что данные корректно кодируются в UTF-8 перед json_encode.

Как загрузить файл через POST с помощью cURL?

Для отправки файлов используется класс CURLFile или устаревший синтаксис с префиксом @ (начиная с PHP 5.5 предпочтительнее CURLFile).


<?php
$file = new CURLFile('/path/to/image.jpg', 'image/jpeg', 'image.jpg');
$postData = ['file' => $file, 'description' => 'Photo'];
$ch = curl_init('https://example.com/upload');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // массив автоматически устанавливает multipart/form-data
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>

Частые ошибки

  • Если не указать mime-тип, может использоваться application/octet-stream.
  • Путь к файлу должен быть абсолютным или корректным относительным относительно рабочей директории скрипта.
  • Большие файлы могут превысить лимиты памяти или времени выполнения - настройте memory_limit и max_execution_time.

Как отправить POST запрос с авторизацией Basic?

Для базовой аутентификации достаточно задать параметры CURLOPT_USERPWD и CURLOPT_HTTPAUTH.


<?php
$ch = curl_init('https://example.com/protected');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'data=value');
curl_setopt($ch, CURLOPT_USERPWD, 'user:pass');
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>

Проблемы

  • Если сервер ожидает другой тип аутентификации (Digest, NTLM), нужно указать соответствующую константу.
  • Пароль в открытом виде в коде - не лучшая практика; используйте переменные окружения или файлы конфигурации.

Как обработать ответ с кодом ошибки HTTP?

После выполнения запроса полезно проверить HTTP-статус ответа через curl_getinfo($ch, CURLINFO_HTTP_CODE).


<?php
$ch = curl_init('https://example.com/api');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['key' => 'value']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode >= 400) {
    // Обработка ошибки
} else {
    // Успешный ответ
}
curl_close($ch);
?>

Ошибки

  • CURLOPT_RETURNTRANSFER не установлен - тогда curl_exec вернёт true/false, а тело ответа будет выведено напрямую.
  • При редиректах код 3xx не считается ошибкой, если не включён CURLOPT_FOLLOWLOCATION.

Как добавить пользовательские заголовки и cookie?

Дополнительные заголовки задаются через CURLOPT_HTTPHEADER, а cookie - через CURLOPT_COOKIE или CURLOPT_COOKIEFILE.


<?php
$headers = [
    'User-Agent: MyApp/1.0',
    'Accept: application/json'
];
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'data=test');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_COOKIE, 'session_id=abc123');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>

Типичные сложности

  • Заголовки должны быть строками в формате Name: Value без лишних пробелов.
  • Если используется несколько cookie, их можно объединить через точку с запятой.

Как настроить таймауты и ограничение скорости?

Таймаут на весь запрос задаётся CURLOPT_TIMEOUT, на соединение - CURLOPT_CONNECTTIMEOUT. Для ограничения скорости используется CURLOPT_MAX_RECV_SPEED_LARGE.


<?php
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'x=1');
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_MAX_RECV_SPEED_LARGE, 1024); // байт в секунду
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>

Ошибки при настройках

  • При слишком малом таймауте запрос может завершиться с ошибкой 28 (CURLE_OPERATION_TIMEDOUT).
  • Ограничение скорости может привести к увеличению времени выполнения, необходимо следить за max_execution_time в PHP.

Расширенные примеры использования cURL для POST запросов

Параллельная отправка нескольких POST запросов (curl_multi)

Когда требуется отправить несколько запросов одновременно, используется мульти-сеанс. Это ускоряет работу при обращении к разным серверам или эндпоинтам.

Пример

<?php
$urls = [
    'https://api1.example.com/post',
    'https://api2.example.com/post'
];
$multiHandle = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, "data=$i");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($multiHandle, $ch);
    $handles[] = $ch;
}
$active = null;
do {
    $status = curl_multi_exec($multiHandle, $active);
} while ($active > 0 && $status === CURLM_OK);
foreach ($handles as $ch) {
    $response = curl_multi_getcontent($ch);
    echo $response . PHP_EOL;
    curl_multi_remove_handle($multiHandle, $ch);
    curl_close($ch);
}
curl_multi_close($multiHandle);
?>
Результат: содержимое ответов от обоих серверов будет выведено последовательно.

Отправка POST запроса с автоматическими повторными попытками при неудаче

Для повышения надёжности можно реализовать логику повторных попыток с экспоненциальной задержкой.

Пример

<?php
function curlPostWithRetry($url, $data, $maxRetries = 3, $delay = 1) {
    $attempt = 0;
    while ($attempt < $maxRetries) {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        if ($httpCode === 200 && !$error) {
            return $response;
        }
        $attempt++;
        sleep($delay * $attempt);
    }
    return false;
}
$result = curlPostWithRetry('https://example.com/api', ['key' => 'value']);
?>
Функция возвращает ответ при успехе или false после исчерпания попыток.

Отправка POST запроса через SOCKS5 прокси

Для обхода ограничений или использования анонимности можно настроить cURL на работу через прокси-сервер.

Пример

<?php
$ch = curl_init('https://httpbin.org/post');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'test=proxy');
curl_setopt($ch, CURLOPT_PROXY, 'socks5://127.0.0.1:1080');
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
В ответе от httpbin.org будет видно, что запрос пришёл через указанный прокси.

Сохранение и повторное использование cookie между запросами

Для имитации сессии можно сохранить cookie в файл и загружать его при последующих запросах.

Пример

<?php
$cookieFile = '/tmp/cookies.txt';
$ch = curl_init('https://example.com/login');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'user=admin&pass=123');
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

// Второй запрос с теми же cookie
$ch2 = curl_init('https://example.com/profile');
curl_setopt($ch2, CURLOPT_COOKIEFILE, $cookieFile);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
$profile = curl_exec($ch2);
curl_close($ch2);
?>
Первый запрос сохраняет куки, второй использует их, имитируя аутентифицированное состояние.

Альтернативный метод POST без cURL: stream_context_create

В некоторых окружениях cURL может быть отключён. Тогда можно воспользоваться обёрткой file_get_contents с контекстом потока.

Пример

<?php
$data = http_build_query(['name' => 'John']);
$options = [
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => $data
    ]
];
$context = stream_context_create($options);
$response = file_get_contents('https://example.com/api', false, $context);
?>
Этот способ проще, но имеет меньше возможностей (таймауты, прокси, работа с файлами).

CURL POST запрос в PHP - comments

En
Php curl post (php)