Функция curl_init в PHP: инициализация сеанса cURL для работы с HTTP
Инициализация cURL в PHP: функции curl_init и базовые возможности
Библиотека cURL предоставляет мощный инструмент для работы с HTTP протоколом. Центральная функция curl_init() создаёт новый сеанс (handle) для дальнейшей настройки и выполнения запроса. Без вызова этой функции невозможно воспользоваться остальными возможностями cURL. В статье рассматриваются различные способы использования curl_init, начиная от простейшего GET запроса и заканчивая обработкой ошибок и параллельными запросами.
Базовый способ: выполнение GET запроса
Основная задача curl_init - получение handle, который затем конфигурируется через curl_setopt и выполняется через curl_exec. Пример минимального GET запроса к публичному API:
<?php
$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if ($response === false) {
// ошибка
} else {
echo $response;
}
curl_close($ch);
?>
После выполнения handle необходимо закрыть функцией curl_close для освобождения ресурсов. Опция CURLOPT_RETURNTRANSFER заставляет вернуть результат в переменную, а не выводить напрямую.
Возможные проблемы и их решения
- Ошибка соединения (Could not resolve host) - проверьте правильность URL и доступность сети. Используйте curl_error($ch) для получения текста ошибки.
- Пустой ответ - может быть вызван блокировкой сервера или отсутствием CURLOPT_RETURNTRANSFER (тогда результат сразу выводится в поток). Убедитесь, что включена опция.
Как выполнить POST запрос?
Для отправки данных методом POST требуется установить опцию CURLOPT_POST в true и передать тело запроса через CURLOPT_POSTFIELDS. Пример:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.example.com/login');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['user' => 'admin', 'pass' => 'secret']));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Если передаётся массив, cURL автоматически устанавливает заголовок Content-Type: application/x-www-form-urlencoded. Для JSON данных нужно явно указать заголовки.
Типичная ошибка: пустой ответ при POST
Сервер может ожидать определённый формат данных. Проверьте, что CURLOPT_POSTFIELDS содержит строку или массив, а не объект. Используйте curl_getinfo($ch, CURLINFO_HTTP_CODE) для выяснения кода ответа.
Как обрабатывать ошибки cURL?
После вызова curl_exec стоит проверять возвращаемое значение на false. Для детальной диагностики используйте функции curl_error и curl_errno.
$ch = curl_init('http://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($ch);
if ($result === false) {
$error = curl_error($ch);
$errno = curl_errno($ch);
// логирование или вывод
} else {
// успешный ответ
}
curl_close($ch);
Ошибки, связанные с SSL
Если сервер использует самоподписанный сертификат, cURL может вернуть ошибку 60. Решение: временно отключить проверку сертификата (CURLOPT_SSL_VERIFYPEER = false), но в production лучше указать путь к CA-папке через CURLOPT_CAINFO.
Как установить таймаут на выполнение запроса?
Таймауты защищают скрипт от зависания при медленных ответах сервера. Используются опции CURLOPT_CONNECTTIMEOUT (время на соединение) и CURLOPT_TIMEOUT (общее время выполнения).
$ch = curl_init('http://slow.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 5 секунд на соединение
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 10 секунд на весь запрос
$response = curl_exec($ch);
curl_close($ch);
Превышение времени выполнения
Если скрипт завершается по таймауту, ответ может быть неполным. Увеличьте значения в php.ini (max_execution_time) или используйте более длинные таймауты.
Как получить только заголовки ответа?
Опция CURLOPT_HEADER включает заголовки в тело ответа. Чтобы получить исключительно заголовки (без тела), установите CURLOPT_NOBODY в true.
$ch = curl_init('http://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true); // заголовки вместе с телом
curl_setopt($ch, CURLOPT_NOBODY, true); // только заголовки
$headers = curl_exec($ch);
curl_close($ch);
echo $headers;
Такой приём полезен для проверки существования URL (получение кода 200) без загрузки содержимого.
Как передать заголовки запроса (User-Agent, Referer)?
Для установки кастомных заголовков используется опция CURLOPT_HTTPHEADER, которая принимает массив строк вида "Имя: значение".
$headers = [
'User-Agent: CustomUserAgent/1.0',
'Accept: application/json',
'Referer: https://mysite.com'
];
$ch = curl_init('https://api.example.com');
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Ошибка 400 при неправильном заголовке
Если сервер ожидает определённый формат (например, JSON), проверьте, что заголовок Content-Type установлен корректно. Для JSON: 'Content-Type: application/json'.
Как работать с автоперенаправлениями (редиректами)?
По умолчанию cURL не следует редиректам. Для автоматического перехода по Location нужно включить опцию CURLOPT_FOLLOWLOCATION и ограничить количество переходов через CURLOPT_MAXREDIRS.
$ch = curl_init('http://bit.ly/short');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
$response = curl_exec($ch);
$finalUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
echo $finalUrl;
Бесконечный редирект или слишком много переходов
Ограничение CURLOPT_MAXREDIRS помогает избежать зацикливания. Если сайт использует редиректы с куками, необходимо также обрабатывать cookie (см. следующий вариант).
Как сохранить и отправить cookie при повторных запросах?
Для работы с сессиями используются опции CURLOPT_COOKIEJAR (файл для записи cookie) и CURLOPT_COOKIEFILE (файл для чтения cookie).
$ch = curl_init('https://example.com/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
// выполнение первого запроса (логин)
$result = curl_exec($ch);
// теперь куки сохранены, можно делать второй запрос тем же handle
curl_setopt($ch, CURLOPT_URL, 'https://example.com/dashboard');
$result2 = curl_exec($ch);
curl_close($ch);
Можно также задать строку кук напрямую через CURLOPT_COOKIE.
Как отправить файл через cURL?
Для загрузки файлов используется класс CURLFile (доступен с PHP 5.5). Файл передаётся в CURLOPT_POSTFIELDS как элемент массива с ключом - именем поля.
$file = new CURLFile('/path/to/file.pdf', 'application/pdf', 'document.pdf');
$data = ['upload' => $file];
$ch = curl_init('https://example.com/upload');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
Ошибка при загрузке: файл не найден или превышен лимит post_max_size
Убедитесь, что файл существует, и проверьте настройки PHP (upload_max_filesize, post_max_size).
Как выполнить несколько запросов параллельно?
cURL поддерживает мульти-обработчики (curl_multi_init), позволяющие запускать запросы асинхронно. Это ускоряет работу, если нужно обойти несколько URL.
$urls = ['http://example.com', 'http://example.org', 'http://example.net'];
$mh = curl_multi_init();
$handles = [];
foreach ($urls as $i => $url) {
$handles[$i] = curl_init($url);
curl_setopt($handles[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $handles[$i]);
}
$running = null;
do {
curl_multi_exec($mh, $running);
curl_multi_select($mh);
} while ($running > 0);
$results = [];
foreach ($handles as $i => $ch) {
$results[$i] = curl_multi_getcontent($ch);
curl_multi_remove_handle($mh, $ch);
curl_close($ch);
}
curl_multi_close($mh);
// $results содержит ответы
Расширенная конфигурация с curl_setopt_array
Для удобства можно передать массив опций одной функцией curl_setopt_array. Это уменьшает количество строк кода и улучшает читаемость.
$options = [
CURLOPT_URL => 'https://api.example.com',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['key' => 'value']),
];
$ch = curl_init();
curl_setopt_array($ch, $options);
$response = curl_exec($ch);
curl_close($ch);
Такой подход удобен при многократном использовании одного набора опций.
Продвинутые примеры использования cURL в PHP
Пример 1: Запрос с базовой аутентификацией (HTTP Basic)
Для доступа к ресурсам, защищённым базовой аутентификацией, используется опция CURLOPT_USERPWD. Пример:
$ch = curl_init('https://api.example.com/private');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "HTTP код: " . $httpCode . "\n";
echo $response;
HTTP код: 200
{"status":"success","data":...}
Если сервер использует дайджест-аутентификацию, применяется CURLOPT_HTTPAUTH с CURLAUTH_DIGEST.
Пример 2: Отправка JSON через POST
Многие современные API ожидают JSON. Необходимо правильно задать Content-Type и сериализовать данные.
$data = ['title' => 'Example', 'body' => 'Content', 'userId' => 1];
$json = json_encode($data);
$ch = curl_init('https://jsonplaceholder.typicode.com/posts');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Content-Length: ' . strlen($json)
]
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "Code: $httpCode\n";
echo $response;
Code: 201
{
"title": "Example",
"body": "Content",
"userId": 1,
"id": 101
}
Пример 3: Работа с SSL через сертификат CA
Для безопасных HTTPS запросов рекомендуется использовать проверку SSL. Если у вас есть файл CA-сертификата (например, cacert.pem из curl), его путь указывается в CURLOPT_CAINFO.
$ch = curl_init('https://secure.example.com');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_CAINFO => '/path/to/cacert.pem',
CURLOPT_SSL_VERIFYHOST => 2
]);
$response = curl_exec($ch);
if ($response === false) {
echo "Ошибка SSL: " . curl_error($ch);
}
curl_close($ch);
Если проверка отключена (CURLOPT_SSL_VERIFYPEER = false), снижается безопасность соединения.
Пример 4: Загрузка файла с прогрессом
С помощью CURLOPT_PROGRESSFUNCTION можно отслеживать прогресс загрузки (download) или отправки (upload). Функция обратного вызова получает аргументы с размерами.
function progressCallback($resource, $download_size, $downloaded, $upload_size, $uploaded) {
if ($download_size > 0) {
$percent = round($downloaded / $download_size * 100);
echo "Загружено: $percent%\n";
}
}
$ch = curl_init('https://example.com/largefile.zip');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_PROGRESSFUNCTION => 'progressCallback',
CURLOPT_NOPROGRESS => false // отключаем встроенный прогресс
]);
$data = curl_exec($ch);
curl_close($ch);
Результат - строка из вызовов коллбэка в консоли. Важно: CURLOPT_NOPROGRESS должен быть false.
Пример 5: Использование cURL с proxy (HTTP/HTTPS)
Для работы через прокси-сервер устанавливаются опции CURLOPT_PROXY, CURLOPT_PROXYPORT и, если требуется аутентификация, CURLOPT_PROXYUSERPWD.
$ch = curl_init('http://httpbin.org/ip');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_PROXY => '192.168.1.100',
CURLOPT_PROXYPORT => 3128,
CURLOPT_PROXYUSERPWD => 'user:pass'
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
{
"origin": "192.168.1.100"
}
Тип прокси можно задать через CURLOPT_PROXYTYPE (например, CURLPROXY_SOCKS5).
Пример 6: Получение информации о запросе (curl_getinfo)
После выполнения запроса можно извлечь метаданные: HTTP код, размер, время выполнения, эффективный URL и др.
$ch = curl_init('https://www.example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
echo "HTTP code: " . $info['http_code'] . "\n";
echo "Content type: " . $info['content_type'] . "\n";
echo "Total time: " . $info['total_time'] . " сек\n";
echo "Effective URL: " . $info['url'] . "\n";
HTTP code: 200 Content type: text/html; charset=UTF-8 Total time: 0.234 сек Effective URL: https://www.example.com/
Пример 7: Запрос с пользовательским методом (DELETE, PUT, PATCH)
Опция CURLOPT_CUSTOMREQUEST позволяет задать любой HTTP метод. Например, DELETE запрос с телом (некоторые API требуют тело и при удалении).
$data = ['reason' => 'test'];
$json = json_encode($data);
$ch = curl_init('https://api.example.com/resource/123');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => ['Content-Type: application/json']
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo "HTTP $httpCode: $response";
Пример 8: Использование cURL через file_get_contents с контекстом (альтернативный подход)
Хотя это не cURL, иногда упоминается как альтернатива. Создание потока с помощью stream_context_create и выполнение GET запроса:
$opts = [
'http' => [
'method' => 'GET',
'header' => "User-Agent: MyAgent/1.0\r\n"
]
];
$context = stream_context_create($opts);
$result = file_get_contents('http://example.com', false, $context);
if ($result === false) {
echo "Ошибка получения данных";
} else {
echo $result;
}
Недостатки: нет поддержки параллельных запросов, менее гибкая обработка ошибок, ограниченные возможности настройки SSL.
Пример 9: Закрытие и повторное использование handle
Handle можно переиспользовать для нескольких последовательных запросов, меняя только URL или другие опции. Это экономит ресурсы.
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Первый запрос
curl_setopt($ch, CURLOPT_URL, 'http://api1.example.com');
$result1 = curl_exec($ch);
// Второй запрос (сброс некоторых опций не обязателен)
curl_setopt($ch, CURLOPT_URL, 'http://api2.example.com');
$result2 = curl_exec($ch);
curl_close($ch);
Важно: при смене URL cURL может сбрасывать некоторые внутренние состояния (например, cookie), но общие опции (таймауты, заголовки) сохраняются.
Пример 10: Обработка chunked transfer encoding
cURL автоматически декодирует chunked ответы, если включена опция CURLOPT_ENCODING с пустой строкой или 'gzip,deflate'. Пример сжатого ответа:
$ch = curl_init('http://httpbin.org/gzip');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => 'gzip,deflate'
]);
$response = curl_exec($ch);
curl_close($ch);
var_dump(json_decode($response, true));
array(3) {
["gzipped"] => bool(true)
["headers"] => array(...)
["method"] => string(3) "GET"
}
Без указания CURLOPT_ENCODING cURL не будет обрабатывать сжатие и вернёт бинарные данные.