Выполнение HTTP-запросов в PHP: сравнение cURL и file_get_contents

Раздел: Разработка на PHP -> HTTP запросы

Выполнение HTTP-запросов в PHP: cURL и file_get_contents

Наиболее эффективное решение: использование cURL

cURL (Client URL Library) предоставляет максимальную гибкость при работе с HTTP-запросами. Он поддерживает различные методы, заголовки, таймауты, обработку ошибок и работу с SSL. Рекомендуется для всех серьезных проектов.

Простой GET-запрос с cURL


$ch = curl_init('https://api.example.com/data');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (curl_errno($ch)) {
    // обработать ошибку
    $error = curl_error($ch);
} else {
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    // работаем с ответом
}
curl_close($ch);
  

curl_init создает дескриптор сеанса. CURLOPT_RETURNTRANSFER заставляет curl вернуть ответ в виде строки вместо прямого вывода. curl_exec выполняет запрос. curl_errno и curl_error позволяют отловить ошибки сети или протокола. curl_getinfo получает HTTP-код ответа.

Типичные проблемы cURL:

  • Ошибка SSL (CURLE_SSL_CONNECT_ERROR) - часто из-за устаревших сертификатов. Решение: установить CURLOPT_SSL_VERIFYPEER = false (не рекомендуется в продакшене) или обновить CA-бандл.
  • Таймаут соединения - установить CURLOPT_CONNECTTIMEOUT и CURLOPT_TIMEOUT.
  • Проблемы с редиректами - включить CURLOPT_FOLLOWLOCATION.

Как выполнить GET-запрос с помощью file_get_contents?

file_get_contents с параметром контекста stream позволяет делать простые GET-запросы без внешних библиотек. Для более сложных сценариев (POST, заголовки) требуется stream_context_create.


$options = [
    'http' => [
        'method' => 'GET',
        'header' => "User-Agent: MyApp\r\n"
    ]
];
$context = stream_context_create($options);
$response = file_get_contents('https://api.example.com/data', false, $context);
if ($response === false) {
    // обработка ошибки
    $error = error_get_last();
}
  

stream_context_create создает контекст с настройками. Если сервер возвращает ошибку 4xx или 5xx, file_get_contents может вернуть false, а сообщение об ошибке будет в error_get_last. Для получения HTTP-кода можно использовать $http_response_header.

Проблемы file_get_contents:

  • Не поддерживает куки, авторизацию, файлы напрямую.
  • Неэффективен для больших ответов - загружает все в память.
  • Требует включенной директивы allow_url_fopen.

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


$ch = curl_init('https://api.example.com/submit');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(['name' => 'John', 'email' => 'john@example.com']));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
  

CURLOPT_POST переключает метод на POST. CURLOPT_POSTFIELDS принимает строку или массив. Если передать массив, curl сам закодирует данные как multipart/form-data (для файлов) или application/x-www-form-urlencoded.

Как использовать библиотеку Guzzle для HTTP-запросов?

Guzzle - это современный HTTP-клиент на PHP, построенный поверх cURL. Он предоставляет объектно-ориентированный интерфейс, поддержку PSR-7, асинхронные запросы и middleware.


use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.example.com']);
$response = $client->get('/data', ['headers' => ['Accept' => 'application/json']]);
$body = $response->getBody()->getContents();
$statusCode = $response->getStatusCode();
  

Важно: требуется установка через Composer. Guzzle упрощает обработку ошибок, позволяет отправлять асинхронные запросы и автоматически управляет дескрипторами cURL.

Возможные ошибки при использовании Guzzle:

  • Исключения при HTTP-ошибках - Guzzle выбрасывает исключение GuzzleHttp\Exception\ClientException для 4xx и ServerException для 5xx. Нужно обрабатывать через try-catch.
  • Проблемы с памятью при больших ответах - используйте стриминг: $response->getBody()->read(1024).

Расширенные примеры работы с HTTP-запросами в PHP

1. Асинхронные запросы с curl_multi

Для одновременной отправки нескольких запросов используйте curl_multi_init. Это ускоряет работу при обращении к нескольким API.

Пример

$urls = ['https://api1.example.com', 'https://api2.example.com'];
$multiHandle = curl_multi_init();
$handles = [];

foreach ($urls as $url) {
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_multi_add_handle($multiHandle, $ch);
    $handles[] = $ch;
}

$active = null;
do {
    $status = curl_multi_exec($multiHandle, $active);
} while ($status === CURLM_CALL_MULTI_PERFORM || $active);

foreach ($handles as $ch) {
    $response = curl_multi_getcontent($ch);
    echo "Ответ: $response\n";
    curl_multi_remove_handle($multiHandle, $ch);
    curl_close($ch);
}
curl_multi_close($multiHandle);
Ответ: { "data": "from api1" }
Ответ: { "data": "from api2" }

2. Отправка POST-запроса с файлом через cURL

Для загрузки файла используйте CURLFile или передайте массив с путем.

Пример

$file = new CURLFile('/path/to/image.jpg', 'image/jpeg', 'image.jpg');
$data = ['upload' => $file, 'description' => 'My image'];

$ch = curl_init('https://api.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);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

3. Работа с cookie через cURL

cURL позволяет сохранять и отправлять cookie с помощью файла cookie jar.

Пример

$cookieFile = '/tmp/cookies.txt';
$ch = curl_init('https://example.com/login');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);   // сохранять cookie
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile);  // отправлять из файла
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'user=admin&pass=secret');
$response = curl_exec($ch);
curl_close($ch);

// следующий запрос с теми же cookie
$ch2 = curl_init('https://example.com/dashboard');
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_COOKIEFILE, $cookieFile);
$dashboard = curl_exec($ch2);
curl_close($ch2);

4. Basic-авторизация через cURL

Пример

$ch = curl_init('https://api.example.com/secure');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
$response = curl_exec($ch);
curl_close($ch);

5. Использование прокси в cURL

Пример

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

6. Установка кастомных заголовков и User-Agent

Пример

$ch = curl_init('https://api.example.com');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer token123',
    'Accept: application/json',
    'X-Custom-Header: value'
]);
curl_setopt($ch, CURLOPT_USERAGENT, 'MyApp/1.0');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

7. Обработка ошибок SSL в cURL

Пример

$ch = curl_init('https://expired.badssl.com/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_exec($ch);
if (curl_errno($ch) === CURLE_SSL_CONNECT_ERROR) {
    // можно попробовать обновить CA-пакет или временно отключить проверку
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($ch);
}
curl_close($ch);

8. Отправка JSON в POST-запросе через cURL

Пример

$data = json_encode(['key' => 'value']);
$ch = curl_init('https://api.example.com/endpoint');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

9. Получение ответа частями (chunked) через file_get_contents с stram-контекстом

Пример

$context = stream_context_create([
    'http' => [
        'method' => 'GET',
        'header' => "Accept-Encoding: gzip\r\n"
    ]
]);
$handle = fopen('https://httpbin.org/stream-bytes/100', 'r', false, $context);
if ($handle) {
    while (!feof($handle)) {
        $chunk = fread($handle, 1024);
        // обработать кусок
    }
    fclose($handle);
}

10. Использование Guzzle с асинхронным запросом

Пример

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client();
$promises = [
    'users'  => $client->getAsync('https://api.example.com/users'),
    'posts'  => $client->getAsync('https://api.example.com/posts'),
];

$results = Promise\Utils::settle($promises)->wait();
foreach ($results as $key => $result) {
    if ($result['state'] === 'fulfilled') {
        $body = $result['value']->getBody()->getContents();
        echo "$key: $body\n";
    } else {
        echo "$key failed: " . $result['reason']->getMessage() . "\n";
    }
}
users: [{"id":1,"name":"Alice"}]
posts: [{"id":1,"title":"Hello"}]

Fetch-запрос в PHP (cURL или file_get_contents) - comments

En
Fetch php (php)