PHP POST JSON: способы и инструкции

Раздел: Веб-интеграция -> HTTP запросы

Основные подходы к отправке POST запроса с JSON телом

Для отправки POST запроса с телом в формате JSON на PHP существует несколько методов. Наиболее распространённым и гибким является использование cURL. Это решение рассматривается как базовое.

Решение с помощью cURL

cURL (Client URL Library) позволяет отправлять запросы с полным контролем заголовков, тела, таймаутов и сертификатов.

Как отправить JSON через POST с помощью cURL?

$data = ['name' => 'Иван', 'age' => 30];
$json = json_encode($data);
$ch = curl_init('https://example.com/api');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Content-Length: ' . strlen($json)
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_error($ch)) {
    $error = curl_error($ch);
} else {
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
}
curl_close($ch);

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

  • Неверный Content-Type: сервер может не распознать JSON.
  • Проблемы с SSL сертификатами: рекомендуется использовать CURLOPT_SSL_VERIFYPEER и CURLOPT_CAINFO.
  • Кодировка: json_encode автоматически кодирует в UTF-8, следует убедиться, что данные в нужной кодировке.
  • Если сервер ожидает application/json; charset=utf-8, это указывается в заголовке.
  • Размер отправляемых данных: при больших объёмах требуется настройка memory_limit и времени выполнения.

Вариант с file_get_contents и stream context

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

Если cURL недоступен, можно использовать file_get_contents с контекстом потока.

$data = ['key' => 'value'];
$json = json_encode($data);
$options = [
    'http' => [
        'method' => 'POST',
        'header' => 'Content-Type: application/json' . chr(13).chr(10) .
                    'Content-Length: ' . strlen($json) . chr(13).chr(10),
        'content' => $json
    ]
];
$context = stream_context_create($options);
$response = file_get_contents('https://example.com/api', false, $context);
if ($response === false) {
    $error = error_get_last();
}

Ограничения:

  • file_get_contents блокирует выполнение скрипта до получения ответа.
  • Сложнее обрабатывать ошибки HTTP (например, 404) - требуется парсить заголовки ответа через переменную $http_response_header.
  • Не поддерживается настройка таймаутов напрямую; для этого используется параметр timeout в контексте.

Вариант с использованием библиотеки Guzzle

Как отправлять JSON POST запросы современным способом с помощью Composer пакета?

Guzzle - популярный HTTP клиент для PHP. Требует установки через Composer.

require 'vendor/autoload.php';
use GuzzleHttp\Client;
$client = new Client();
try {
    $response = $client->post('https://example.com/api', [
        'json' => ['name' => 'Анна', 'email' => 'anna@example.com'],
        'headers' => ['X-Custom' => 'value']
    ]);
    $body = $response->getBody()->getContents();
    $status = $response->getStatusCode();
} catch (\Exception $e) {
    $error = $e->getMessage();
}

Возможные сложности:

  • Требуется установка (composer require guzzlehttp/guzzle).
  • Версии PHP 7.2+ для Guzzle 7.
  • Необходимо обрабатывать исключения (ConnectException, ClientException и др.).
  • Автоматическое управление заголовками может не подходить для некоторых API.
Пример
// Пример 1: Отправка JSON с авторизацией Bearer token
$token = '...';
$data = ['action' => 'update', 'id' => 123];
$ch = curl_init('https://api.example.com/user');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($data),
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer ' . $token
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 30
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo 'HTTP код: ' . $httpCode . '\n';
echo 'Ответ: ' . $response;
HTTP код: 200
Ответ: {"status":"ok"}
Пример
// Пример 2: Отправка JSON с проверкой SSL (для самоподписанных сертификатов)
$ch = curl_init('https://internal.api.local/');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode(['test' => true]),
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => false, // Только для разработки!
    CURLOPT_SSL_VERIFYHOST => false,
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'cURL error: ' . curl_error($ch);
} else {
    echo $response;
}
curl_close($ch);
{"message":"Test endpoint"}
Пример
// Пример 3: Асинхронная отправка нескольких POST запросов с curl_multi
$urls = ['https://api1.example.com', 'https://api2.example.com'];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode(['index' => $i]),
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER => true,
    ]);
    curl_multi_add_handle($mh, $ch);
    $handles[] = $ch;
}
$running = null;
do {
    curl_multi_exec($mh, $running);
    curl_multi_select($mh);
} while ($running > 0);
foreach ($handles as $ch) {
    $response = curl_multi_getcontent($ch);
    echo 'Ответ: ' . $response . '\n';
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}
curl_multi_close($mh);
Ответ: {"id":1}
Ответ: {"id":2}
Пример
// Пример 4: Использование file_get_contents с настройкой таймаута
$data = ['operation' => 'get_status'];
$json = json_encode($data);
$options = [
    'http' => [
        'method' => 'POST',
        'header' => 'Content-Type: application/json' . chr(13).chr(10) .
                    'Content-Length: ' . strlen($json) . chr(13).chr(10),
        'content' => $json,
        'timeout' => 10
    ]
];
$context = stream_context_create($options);
$response = @file_get_contents('https://example.com/status', false, $context);
if ($response === false) {
    $error = error_get_last();
    echo 'Ошибка: ' . $error['message'];
} else {
    if (isset($http_response_header[0])) {
        $statusLine = $http_response_header[0];
        echo 'Статус: ' . $statusLine . '\n';
    }
    echo 'Ответ: ' . $response;
}
Статус: HTTP/1.1 200 OK
Ответ: {"status":"active"}
Пример
// Пример 5: Отправка JSON с Guzzle и обработкой исключений
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$client = new Client(['base_uri' => 'https://api.example.com', 'timeout' => 5.0]);
try {
    $response = $client->post('/v1/items', [
        'json' => ['item' => ['name' => 'New Item', 'price' => 99.99]],
        'headers' => ['Accept' => 'application/json']
    ]);
    $body = $response->getBody();
    $decoded = json_decode($body, true);
    print_r($decoded);
} catch (RequestException $e) {
    echo 'HTTP Error: ' . $e->getCode() . ' ' . $e->getMessage();
    if ($e->hasResponse()) {
        echo '\nResponse body: ' . $e->getResponse()->getBody();
    }
} catch (\Exception $e) {
    echo 'General error: ' . $e->getMessage();
}
Array
(
    [id] => 42
    [name] => New Item
    [price] => 99.99
)

PHP: отправка POST-запроса с JSON - comments

En
Php post json (php)