Выполнение POST запроса к внешнему API на PHP

Раздел: Веб-разработка на PHP -> API интеграция

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

Самый надёжный и гибкий подход - использование расширения cURL.

Оно поддерживает все необходимые опции: установку метода, заголовков, передачу данных, обработку сертификатов и таймауты. Ниже приведён базовый пример отправки JSON-данных и чтения ответа.

<?php
$url = 'https://api.example.com/v1/items';
$data = ['name' => 'Новый товар', 'price' => 99.99];
$json = json_encode($data);

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Accept: application/json'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Для продакшена отключать проверку SSL не рекомендуется
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if(curl_error($ch)) {
    $error = curl_error($ch);
    // обработка ошибки
}
curl_close($ch);

// Обработка ответа
if($httpCode === 201) {
    $result = json_decode($response, true);
}
?>

Пояснения:

  • CURLOPT_POST - переводит запрос в метод POST.
  • CURLOPT_POSTFIELDS - тело запроса. Для JSON передаётся строка, для формы - массив.
  • CURLOPT_HTTPHEADER - заголовки для указания типа данных.
  • CURLOPT_RETURNTRANSFER - возвращает ответ как строку вместо вывода.

Проблема: неверный заголовок Content-Type может привести к ошибке 415. Решение - всегда указывать его соответственно передаваемому формату.

Как выполнить POST запрос без использования cURL?

Встроенная функция file_get_contents с контекстом потоков подходит для простых запросов, когда не требуется детальная настройка. Пример:

<?php
$url = 'https://api.example.com/v1/items';
$data = ['name' => 'Товар'];
$options = [
    'http' => [
        'method' => 'POST',
        'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query($data)
    ]
];
$context = stream_context_create($options);
$response = file_get_contents($url, false, $context);
// $http_response_header содержит заголовки ответа
?>

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

Типичная ошибка - неправильное указание заголовков (пропуск \r\n в конце каждой строки). Решение - формировать заголовки строго по спецификации HTTP.

Как отправить POST запрос с помощью Composer пакета Guzzle?

Guzzle - современная библиотека для работы с HTTP. Устанавливается через Composer: composer require guzzlehttp/guzzle. Пример отправки JSON:

<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.example.com']);
try {
    $response = $client->post('/v1/items', [
        'json' => ['name' => 'Товар'],
        'headers' => ['Authorization' => 'Bearer token123']
    ]);
    $body = $response->getBody()->getContents();
    $status = $response->getStatusCode();
} catch (\GuzzleHttp\Exception\ClientException $e) {
    // 4xx ошибки
}
?>

Guzzle автоматически обрабатывает JSON, поддерживает повторные попытки, асинхронные запросы. Рекомендуется для сложных проектов.

Ошибка при неверной конфигурации SSL - можно отключить проверку на этапе разработки: ['verify' => false]. В продакшене это недопустимо.

Как принять и обработать POST данные на PHP сервере?

Когда необходимо создать собственное API, принимающее POST запросы, используется суперглобальный массив $_POST для формы или php://input для JSON. Пример обработчика:

<?php
// Устанавливаем заголовки ответа
header('Content-Type: application/json');

// Получаем тело запроса
$input = file_get_contents('php://input');
$data = json_decode($input, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    http_response_code(400);
    echo json_encode(['error' => 'Невалидный JSON']);
    exit;
}

// Валидация и работа с данными
if (empty($data['name'])) {
    http_response_code(422);
    echo json_encode(['error' => 'Поле name обязательно']);
    exit;
}

// Сохранение в БД...
http_response_code(201);
echo json_encode(['id' => 1, 'message' => 'Создано']);
?>

Важно проверять метод запроса: $_SERVER['REQUEST_METHOD'] === 'POST'. Типичная ошибка - забыть декодировать JSON или неправильно установить заголовок ответа.

Если данные приходят как multipart/form-data (с файлами), используйте $_POST и $_FILES. Для JSON всегда php://input.

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

Пример 1: POST запрос с авторизацией Bearer токеном и обработкой ошибок через cURL

Пример
<?php
function apiPost($url, $data, $token) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/json',
        'Authorization: Bearer ' . $token,
        'Accept: application/json'
    ]);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($ch, CURLOPT_TIMEOUT, 10);
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);
    
    if ($error) {
        return ['error' => "cURL error: $error"];
    }
    return ['code' => $httpCode, 'body' => json_decode($response, true)];
}

$result = apiPost('https://api.example.com/data', ['key' => 'value'], 'myToken123');
print_r($result);
?>
Array
(
    [code] => 200
    [body] => Array
        (
            [success] => true
            [id] => 42
        )
)

Пояснение: функция возвращает структурированный ответ с кодом и телом. Таймауты соединения и выполнения защищают от зависания.

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

Пример
<?php
$url = 'https://api.example.com/upload';
$filePath = '/path/to/file.pdf';
$cfile = new CURLFile($filePath, 'application/pdf', 'document.pdf');

$postData = [
    'file' => $cfile,
    'description' => 'Отчёт за март'
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); // массив, не json!
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
?>

При использовании CURLFile не нужно вручную устанавливать Content-Type - cURL задаст multipart/form-data автоматически.

Пример 3: Асинхронный POST запрос с помощью curl_multi (выполнение нескольких запросов параллельно)

Пример
<?php
$urls = [
    'https://api1.com/endpoint',
    'https://api2.com/endpoint'
];
$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, json_encode(['index' => $i]));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($multiHandle, $ch);
    $handles[$i] = $ch;
}

$active = null;
do {
    $mrc = curl_multi_exec($multiHandle, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($multiHandle) !== -1) {
        do {
            $mrc = curl_multi_exec($multiHandle, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}

foreach ($handles as $i => $ch) {
    $response = curl_multi_getcontent($ch);
    $info = curl_getinfo($ch);
    echo "Запрос $i: HTTP {$info['http_code']} - $response\n";
    curl_multi_remove_handle($multiHandle, $ch);
    curl_close($ch);
}
curl_multi_close($multiHandle);
?>

Результат (пример):

Запрос 0: HTTP 200 - {"status":"ok"}
Запрос 1: HTTP 200 - {"status":"ok"}

Такой подход сокращает общее время ожидания при работе с несколькими API.

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

En
Php post api (php)