Avatar ·

Как установить произвольные заголовки (custom headers) в PHP cURL?

Всем привет! Я новичок в PHP и пытаюсь отправить POST-запрос к внешнему API через cURL. В документации API сказано, что нужно передать несколько кастомных заголовков: `X-API-Key: mysecretkey`, `Content-Type: application/json` и `Authorization: Bearer token123`. Я пробовал передавать их как строку в `curl_setopt($ch, CURLOPT_HTTPHEADER, ...)`, но у меня ничего не работает — сервер отвечает ошибкой 400 Bad Request или игнорирует мои заголовки. Вот мой текущий код: ```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"])); curl_setopt($ch, CURLOPT_HTTPHEADER, "X-API-Key: mysecretkey; Content-Type: application/json; Authorization: Bearer token123"); $response = curl_exec($ch); curl_close($ch); ``` Я передаю все заголовки одной строкой через точку с запятой. Может, нужно по-другому? И ещё: как проверить, что заголовки вообще отправляются? Заранее спасибо за помощь! <<>>

Правильный способ установки кастомных заголовков в 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.