Как установить произвольные заголовки (custom headers) в PHP cURL?
Правильный способ установки кастомных заголовков в cURL
Ваша основная ошибка — в неправильном формате параметра CURLOPT_HTTPHEADER. Согласно документации PHP, этот параметр принимает массив строк, где каждая строка — это один заголовок в формате "Имя: Значение". Вы же передали одну строку с разделителями ";" — так cURL не сможет корректно разобрать заголовки.
Исправленный код будет выглядеть так:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://api.example.com/data");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["name" => "John"]));
// Правильный способ: массив заголовков
$headers = [
"X-API-Key: mysecretkey",
"Content-Type: application/json",
"Authorization: Bearer token123"
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Важно: возвращать результат в виде строки, а не выводить сразу
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
// Проверка на ошибки
if (curl_errno($ch)) {
echo 'Ошибка cURL: ' . curl_error($ch);
}
curl_close($ch);
// Обработка ответа
$data = json_decode($response, true);
print_r($data);
?>
Как проверить отправленные заголовки?
Есть два способа отладки:
- CURLOPT_VERBOSE — включает подробный вывод. Добавьте перед
curl_exec():
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
// После выполнения запроса:
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Подробный лог:\n" . $verboseLog;
- CURLINFO_HEADER_OUT — получить отправленные заголовки после выполнения:
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
// ... выполнение запроса ...
$sentHeaders = curl_getinfo($ch, CURLINFO_HEADER_OUT);
echo "Отправленные заголовки:\n" . $sentHeaders;
Дополнительные важные моменты
- Content-Type — если вы передаёте JSON, обязательно укажите его явно. Если передаёте форму (
application/x-www-form-urlencoded), cURL установит его автоматически. - Авторизация — для Bearer-токенов можно использовать
CURLOPT_HTTPHEADER, как показано выше, или альтернативный вариант:curl_setopt($ch, CURLOPT_USERPWD, "token123:X");(но это для Basic Auth). - Безопасность — никогда не храните ключи и токены в коде. Используйте переменные окружения или конфигурационные файлы.
Полный пример с обработкой ошибок
<?php
function sendApiRequest($url, $data, $apiKey, $token) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_HTTPHEADER => [
"X-API-Key: $apiKey",
"Content-Type: application/json",
"Authorization: Bearer $token",
"Accept: application/json"
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true // для production
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (curl_errno($ch)) {
throw new Exception('cURL error: ' . curl_error($ch));
}
curl_close($ch);
return [
'http_code' => $httpCode,
'body' => json_decode($response, true)
];
}
// Использование
try {
$result = sendApiRequest(
'https://api.example.com/data',
['name' => 'John'],
getenv('API_KEY'),
getenv('AUTH_TOKEN')
);
print_r($result);
} catch (Exception $e) {
echo 'Ошибка: ' . $e->getMessage();
}
?>
<<Альтернативный подход: использование библиотеки Guzzle
Если вы работаете с современными PHP-проектами (Laravel, Symfony) или просто хотите более удобный интерфейс, рекомендую перейти на Guzzle HTTP Client. Он избавляет от ручной настройки cURL и делает код чище.
Установка через Composer:
composer require guzzlehttp/guzzle
Пример с кастомными заголовками:
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$client = new Client([
'base_uri' => 'https://api.example.com',
'headers' => [
'X-API-Key' => 'mysecretkey',
'Authorization' => 'Bearer token123',
'Accept' => 'application/json',
]
]);
try {
$response = $client->post('/data', [
'json' => ['name' => 'John'], // Guzzle сам установит Content-Type: application/json
]);
$body = $response->getBody()->getContents();
$data = json_decode($body, true);
print_r($data);
} catch (RequestException $e) {
echo 'HTTP ошибка: ' . $e->getMessage();
if ($e->hasResponse()) {
echo 'Ответ сервера: ' . $e->getResponse()->getBody();
}
}
?>
Преимущества Guzzle: автоматическая обработка JSON, встроенные middleware для логирования, поддержка асинхронных запросов и PSR-18 совместимость. Для простых задач можно оставить cURL, но для серьёзной работы с API Guzzle — стандарт де-факто в современном PHP.