Применение cURL в PHP для взаимодействия с HTTP сервисами

Раздел: PHP -> HTTP и cURL

Основы работы с cURL в PHP

Библиотека cURL (Client URL) предоставляет широкие возможности для отправки HTTP запросов и получения ответов. В PHP функции cURL позволяют имитировать браузер, управлять заголовками, куками, обрабатывать редиректы и выполнять асинхронные запросы.

Как реализовать универсальную функцию для HTTP запросов с обработкой ошибок?

Наиболее эффективным решением является создание отдельной функции, которая принимает параметры запроса (метод, URL, данные, заголовки, настройки таймаута и SSL) и возвращает ответ в удобном формате.


function curl_request($url, $method = 'GET', $data = null, $headers = [], $options = []) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_TIMEOUT, $options['timeout'] ?? 30);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $options['follow_redirects'] ?? true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $options['verify_ssl'] ?? true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $options['verify_ssl'] ?? true ? 2 : 0);

    if ($headers) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }

    if ($method === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        if ($data !== null) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
    } elseif ($method === 'PUT') {
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
        if ($data !== null) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
    } elseif ($method !== 'GET') {
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
        if ($data !== null) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }
    }

    $response = curl_exec($ch);
    $error = curl_error($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($error) {
        return ['error' => $error, 'http_code' => $http_code, 'response' => $response];
    }

    return ['http_code' => $http_code, 'response' => $response];
}

Index php curl (curl в php)

Пояснение шагов:

  • Инициализация сеанса cURL через curl_init.
  • Установка базовых опций: возврат результата в переменную, таймаут, следование редиректам, проверка SSL.
  • Передача заголовков, если они заданы.
  • Выбор метода запроса: GET, POST, PUT, DELETE и другие.
  • Выполнение запроса и обработка ошибок.
  • Закрытие сеанса и возврат массива с кодом ответа, телом и возможной ошибкой.

Типичные проблемы и их решения:

  • Ошибка SSL 60: сертификат не доверенный. Решение: установить CURLOPT_SSL_VERIFYPEER = false или указать путь к CA bundle через CURLOPT_CAINFO.
  • Таймаут (ошибка 28): сервер долго отвечает. Увеличить CURLOPT_TIMEOUT или CURLOPT_CONNECTTIMEOUT.
  • Пустой ответ: возможно редирект без разрешения. Проверить CURLOPT_FOLLOWLOCATION.
  • Ошибка 52: сервер закрыл соединение. Проверить правильность URL и доступность сервера.

Как отправить простой GET запрос с параметрами?

Цель: получить данные от удаленного API, передав параметры в URL.


$url = 'https://api.example.com/users';
$params = ['page' => 1, 'limit' => 10];
$url .= '?' . http_build_query($params);

$result = curl_request($url, 'GET');
if ($result['http_code'] === 200) {
    $data = json_decode($result['response'], true);
    // обработка данных
} else {
    echo 'Ошибка: ' . $result['http_code'];
}

Как передать данные через POST запрос в формате JSON?

Цель: отправить структурированные данные в теле запроса (например, для REST API).


$data = ['name' => 'Иван', 'email' => 'ivan@example.com'];
$json = json_encode($data);

$url = 'https://api.example.com/users';
$headers = ['Content-Type: application/json'];

$result = curl_request($url, 'POST', $json, $headers);

Проблема: если не указать заголовок Content-Type: application/json, сервер может не распознать JSON. Также важно правильно кодировать UTF-8.

Как выполнить POST запрос с URL-кодированными данными (form-data)?

Цель: имитация отправки HTML формы.


$form_data = ['username' => 'user', 'password' => 'pass'];
$url = 'https://example.com/login';

$result = curl_request($url, 'POST', http_build_query($form_data));

Обратите внимание, что http_build_query автоматически кодирует данные.

Как загрузить файл на сервер через multipart/form-data?

Цель: отправка файла вместе с другими полями (например, аватар).


$file_path = '/path/to/file.jpg';
$ch = curl_init('https://example.com/upload');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = [
    'file' => new CURLFile($file_path, 'image/jpeg', 'avatar.jpg'),
    'description' => 'Мой аватар'
];
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);

Важно:

Если используется CURLFile, PHP автоматически установит Content-Type: multipart/form-data. Не нужно добавлять заголовок вручную.

Ошибка: "Only arrays and Traversables can be unpacked" может возникнуть при передаче файла через CURLOPT_POSTFIELDS в старых версиях PHP. Решение: использовать curl_file_create вместо new CURLFile.

Как установить пользовательские заголовки (User-Agent, Authorization)?

Цель: имитация браузера или авторизация через токен.


$url = 'https://api.example.com/protected';
$token = 'Bearer abc123';
$headers = [
    'Authorization: ' . $token,
    'User-Agent: MyApp/1.0',
    'Accept: application/json'
];
$result = curl_request($url, 'GET', null, $headers);

Как управлять cookie в cURL (сохранение и отправка)?

Цель: поддержка сессии между запросами.


$cookie_file = '/tmp/cookies.txt';
$ch = curl_init('https://example.com/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['user' => 'admin', 'pass' => '123']);
$response = curl_exec($ch);
curl_close($ch);
// последующие запросы будут использовать те же cookies

Проблема: файл cookie может быть недоступен для записи. Убедиться в правах доступа или использовать временную директорию.

Как выполнить запрос через прокси-сервер?

Цель: обход ограничений или анонимизация.


$ch = curl_init('https://httpbin.org/ip');
curl_setopt($ch, CURLOPT_PROXY, 'http://proxy.example.com:3128');
curl_setopt($ch, CURLOPT_PROXYUSERPWD, 'user:pass');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);

Типы прокси:

SOAP, HTTP, SOCKS5. Для SOCKS5 используйте CURLOPT_PROXYTYPE = CURLPROXY_SOCKS5.

Как обработать редиректы и получить финальный URL?

Цель: узнать, куда привел редирект (например, после сокращения ссылки).


$ch = curl_init('http://bit.ly/example');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
$response = curl_exec($ch);
$final_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
echo 'Финальный URL: ' . $final_url;

Как выполнить несколько запросов параллельно (cURL Multi)?

Цель: ускорение загрузки данных с нескольких серверов одновременно.


$urls = ['https://api1.com', 'https://api2.com', 'https://api3.com'];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($mh, $ch);
    $handles[$i] = $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);
    // обработка ответа
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}
curl_multi_close($mh);

Проблема: неконтролируемое количество одновременных соединений. Можно ограничить через CURLOPT_CONNECTTIMEOUT или использовать curl_multi_select для ожидания.

Как отлаживать запросы cURL (вывод заголовков и деталей)?

Цель: увидеть что отправляется и приходит для диагностики.


$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
$response = curl_exec($ch);
rewind($verbose);
$verbose_output = stream_get_contents($verbose);
fclose($verbose);
echo 'Отладочная информация:';
echo '<pre>' . htmlspecialchars($verbose_output) . '</pre>';
curl_close($ch);

Также можно использовать CURLOPT_HEADER = true для включения заголовков ответа в тело.

Совместное использование cookie между запросами через curl_share

Для экономии ресурсов при множественных запросах к одному домену можно использовать общий cookie-стор.

Пример

$share = curl_share_init();
curl_share_setopt($share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);

$ch1 = curl_init('https://example.com/login');
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch1, CURLOPT_POST, true);
curl_setopt($ch1, CURLOPT_POSTFIELDS, 'user=admin&pass=123');
curl_setopt($ch1, CURLOPT_SHARE, $share);
$result1 = curl_exec($ch1);

$ch2 = curl_init('https://example.com/profile');
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_SHARE, $share);
$result2 = curl_exec($ch2);

curl_close($ch1);
curl_close($ch2);
curl_share_close($share);

Результат:

Второй запрос получит содержимое профиля уже авторизованного пользователя, так как cookies были общими.
(Пример вывода: HTML страница профиля)

Скачивание большого файла напрямую в файловую систему

Избегаем загрузки всего файла в память, используя CURLOPT_FILE.

Пример

$url = 'https://example.com/file.zip';
$output_file = fopen('download.zip', 'wb');
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_FILE, $output_file);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch);
if (curl_error($ch)) {
    echo 'Ошибка: ' . curl_error($ch);
} else {
    echo 'Файл скачан успешно';
}
curl_close($ch);
fclose($output_file);

Результат:

Файл будет сохранен на диск без использования дополнительной памяти.
Файл скачан успешно

Отправка данных частями с помощью callback функции

Полезно для передачи больших объёмов данных без предварительной загрузки.

Пример

$data = 'abcdefghijklmnopqrstuvwxyz';
$offset = 0;
$ch = curl_init('https://httpbin.org/post');
curl_setopt($ch, CURLOPT_PUT, true);
curl_setopt($ch, CURLOPT_READFUNCTION, function($ch, $fd, $length) use ($data, &$offset) {
    $remaining = substr($data, $offset, $length);
    $offset += strlen($remaining);
    return $remaining;
});
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
echo $response;

Результат:

Сервер получит строку целиком как PUT данные.
{
  "data": "abcdefghijklmnopqrstuvwxyz",
  ...
}

Обработка заголовков ответа без их включения в тело

Позволяет прочитать заголовки до получения полного ответа.

Пример

$headers = [];
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($ch, $header) use (&$headers) {
    $headers[] = $header;
    return strlen($header);
});
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);
curl_close($ch);
print_r($headers);

Результат:

Массив заголовков ответа будет выведен.
Array
(
    [0] => HTTP/2 200 
    [1] => Content-Type: text/html
    [2] => Date: ...
)

Работа с cookies через массив (без записи на диск)

Удобно, когда нужно быстро задать или прочитать cookies.

Пример

$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIELIST, 'Set-Cookie: session_id=abc123; path=/');
curl_exec($ch);
$cookies = curl_getinfo($ch, CURLINFO_COOKIELIST);
print_r($cookies);
curl_close($ch);

Результат:

Массив cookie, которые были установлены сервером и отправлены.
Array
(
    [0] => example.com\tFALSE\t/\tFALSE\t0\tsession_id\tabc123
)

cURL в PHP - comments

En
Index php curl (php)