Работа с JSON через cURL: практическое пособие для PHP разработчиков
Отправка JSON через HTTP с помощью cURL в PHP
Основной подход: использование curl_setopt с CURLOPT_POSTFIELDS и заголовком Content-Type
Для отправки JSON-данных через HTTP-запрос с помощью cURL в PHP необходимо сформировать JSON-строку, инициализировать сеанс cURL, установить необходимые опции и выполнить запрос. Ниже приведен наиболее эффективный и универсальный способ.
$data = ['name' => 'Иван', 'email' => 'ivan@example.com'];
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
$ch = curl_init('https://api.example.com/users');
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);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$result = json_decode($response, true);
// обработка ответа
}
Php curl application json (отправка json с помощью curl в php)
Пояснения: json_encode преобразует массив в JSON-строку. Флаг JSON_UNESCAPED_UNICODE сохраняет кириллицу без экранирования. Установка CURLOPT_POST в true указывает на POST-запрос. CURLOPT_POSTFIELDS принимает строку (не массив!) – именно так корректно отправляется JSON. Заголовок Content-Type обязателен, чтобы сервер понимал формат. Content-Length может быть опущен, но его явное указание улучшает совместимость. CURLOPT_RETURNTRANSFER возвращает ответ в переменную.
Типичные ошибки и их решение
- Ошибка: сервер возвращает
415 Unsupported Media Type– не указан заголовокContent-Type: application/json. - Ошибка:
curl_exec()возвращает false – необходимо проверитьcurl_error($ch). Частая причина: неверный URL, проблемы SSL (тогда временно можно добавитьcurl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false)в разработке, но не в production). - Ошибка: сервер не принимает данные – возможно, передаётся массив в
CURLOPT_POSTFIELDS(тогда PHP отправляет как form-data). Нужно обязательно передавать строку JSON. - Ошибка: некорректное кодирование – если не использовать
JSON_UNESCAPED_UNICODE, русские символы будут иметь вид\u0438\u0432\u0430\u043d.
Как отправить JSON через GET-запрос?
Иногда требуется передать JSON-данные в query-параметрах, например для поисковых запросов. Сериализованный JSON добавляется к URL после знака вопроса.
$params = ['filter' => ['status' => 'active', 'age' => 25]];
$query = http_build_query(['data' => json_encode($params)]);
$url = 'https://api.example.com/search?' . $query;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Случаи использования: когда API ожидает данные в строке запроса (например, для кэширования). Недостаток – ограничение длины URL.
Проблема: если JSON содержит спецсимволы, они должны быть закодированы функцией urlencode. Использование http_build_query решает эту задачу автоматически.
Как отправить JSON с помощью библиотеки Guzzle (альтернатива cURL)?
Guzzle – популярный HTTP-клиент для PHP. Он предоставляет удобный интерфейс, автоматически устанавливает заголовки и обрабатывает JSON.
use GuzzleHttp\Client;
$client = new Client(['base_uri' => 'https://api.example.com']);
$response = $client->post('/users', [
'json' => ['name' => 'Иван', 'email' => 'ivan@example.com']
]);
$body = $response->getBody()->getContents();
$httpCode = $response->getStatusCode();
Пояснение: опция json автоматически кодирует массив в JSON, устанавливает Content-Type и обрабатывает ошибки. Подходит для проектов, где уже используется Composer.
Проблема: Guzzle может требовать установки через Composer и имеет больше зависимостей. Для простых скриптов cURL предпочтительнее.
Как отправить многомерный или вложенный JSON?
Для сложных структур данные формируются в виде многомерного массива, после чего json_encode обрабатывает их корректно.
$data = [
'user' => [
'name' => 'Петр',
'contacts' => [
['type' => 'email', 'value' => 'petr@mail.com'],
['type' => 'phone', 'value' => '+71234567890']
]
],
'meta' => ['source' => 'web']
];
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
// отправка через cURL как в основном примере
Важно: флаг JSON_PRETTY_PRINT делает JSON читаемым, но увеличивает размер. Для production лучше не использовать.
Ошибка: если данные содержат объекты (stdClass) или ресурсы, json_encode может вернуть false. Следует проверять результат: if ($json === false) { echo json_last_error_msg(); }.
Как отправить JSON с аутентификацией (Bearer token)?
Для защищённых API необходимо добавить заголовок Authorization.
$token = 'your_bearer_token';
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $token
];
$ch = curl_init('https://api.example.com/users');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// ...
Случаи использования: работа с REST API, требующими токен (JWT, OAuth).
Проблема: токен может быть просрочен – необходима логика обновления. Также не следует хранить токен в коде – использовать переменные окружения.
Как обработать ответ сервера в случае ошибки?
Важно проверять HTTP-код ответа и декодировать JSON-ответ, который может содержать сообщение об ошибке.
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
$errorMsg = curl_error($ch);
// логирование или обработка
} elseif ($httpCode >= 400) {
$errorBody = json_decode($response, true);
$errorMessage = $errorBody['error']['message'] ?? 'Неизвестная ошибка';
// обработка ошибки
} else {
$result = json_decode($response, true);
}
Рекомендация: всегда использовать curl_error для обнаружения сетевых проблем и проверять HTTP-статус для бизнес-ошибок.
Общие проблемы и их решение
- SSL certificate problem: при разработке можно отключить проверку SSL:
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);. На production обязательно настроить правильные сертификаты (CA bundle). - Тайм-аут запроса: установить
CURLOPT_TIMEOUT(секунды) иCURLOPT_CONNECTTIMEOUT. - Ограничение памяти при большом JSON: использовать поточную обработку или увеличить memory_limit.
- Кодировка UTF-8: убедиться, что исходные данные в UTF-8. Флаг
JSON_UNESCAPED_UNICODEпомогает.
Расширенные примеры отправки JSON через cURL
Пример 1. Отправка JSON с авторизацией через Basic Auth
$data = ['login' => 'admin', 'password' => '12345'];
$json = json_encode($data);
$ch = curl_init('https://api.example.com/auth');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_USERPWD, 'admin:12345'); // Basic Auth
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo "HTTP код: " . curl_getinfo($ch, CURLINFO_HTTP_CODE) . "\n";
echo "Ответ: " . $response;
HTTP код: 200
Ответ: {"token":"eyJ..."}
Пример 2. Отправка JSON через прокси-сервер
$proxy = 'http://proxy.example.com:8080';
$proxyAuth = 'user:pass';
$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_PROXY, $proxy);
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxyAuth);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Пример 3. Отправка JSON с помощью PUT (обновление ресурса)
$data = ['status' => 'updated'];
$json = json_encode($data);
$ch = curl_init('https://api.example.com/users/123');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Пример 4. Отправка JSON с дополнительными заголовками (например, X-Request-Id)
$headers = [
'Content-Type: application/json',
'X-Request-Id: ' . uniqid(),
'Accept: application/json'
];
$ch = curl_init('https://api.example.com/orders');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Пример 5. Отправка JSON с управлением временем ожидания и редиректами
$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 5 секунд на соединение
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 10 секунд на весь запрос
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // следовать редиректам
curl_setopt($ch, CURLOPT_MAXREDIRS, 2); // ограничить количество редиректов
$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
echo "URL после редиректов: " . $info['url'];
Пример 6. Отправка большого JSON-файла из файла (поточная передача)
$filePath = '/tmp/large_data.json';
$handle = fopen($filePath, 'r');
$ch = curl_init('https://api.example.com/upload');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_INFILE, $handle);
curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
fclose($handle);
Пример 7. Отправка JSON с помощью cURL и обработка ответа в виде потока (stream)
$ch = curl_init('https://api.example.com/stream');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); // не возвращать, выводить напрямую
curl_setopt($ch, CURLOPT_FILE, fopen('php://output', 'w'));
$response = curl_exec($ch);
curl_close($ch);
// Данные выводятся на экран по мере получения
Пример 8. Параллельная отправка нескольких JSON-запросов (curl_multi)
$urls = [
'https://api.example.com/item/1',
'https://api.example.com/item/2',
'https://api.example.com/item/3'
];
$jsonData = ['action' => 'update', 'value' => 42];
$json = json_encode($jsonData);
$mh = 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);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch);
$handles[$i] = $ch;
}
$running = null;
do {
curl_multi_exec($mh, $running);
} 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,"status":"ok"}
Ответ: {"id":2,"status":"ok"}
Ответ: {"id":3,"status":"ok"}
Пример 9. Отправка JSON с автоматической обработкой ошибок и повторными попытками
function sendJsonWithRetry($url, $data, $maxRetries = 3) {
$json = json_encode($data);
$attempt = 0;
do {
$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']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch);
curl_close($ch);
if ($error === '' && $httpCode < 500) {
return ['code' => $httpCode, 'body' => $response];
}
$attempt++;
if ($attempt < $maxRetries) {
usleep(1000000 * $attempt); // задержка 1,2,3 секунды
}
} while ($attempt < $maxRetries);
return ['code' => 0, 'error' => 'Все попытки исчерпаны'];
}
$result = sendJsonWithRetry('https://api.example.com/try', ['test' => true]);
print_r($result);
Пример 10. Отправка JSON с указанием пользовательского User-Agent
$ch = curl_init('https://api.example.com/users');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'User-Agent: MyApp/1.0'
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);