Отправка HTTPS запросов на PHP: способы и примеры

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

Основные методы отправки HTTPS запросов в PHP

Решение с помощью cURL (наиболее эффективное)

Библиотека cURL

cURL предоставляет гибкий и надёжный способ выполнения HTTPS запросов в PHP. Она поддерживает GET, POST, любые методы, заголовки, таймауты, сертификаты SSL и многое другое. Рекомендуется как основной инструмент для работы с удалёнными ресурсами.


<?php
// Инициализация сеанса cURL
$ch = curl_init('https://api.example.com/data');

// Настройка параметров
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // возвращать результат, а не выводить
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // проверка SSL сертификата
curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem'); // свой файл сертификатов (опционально)
curl_setopt($ch, CURLOPT_TIMEOUT, 30); // таймаут в секундах

// Выполнение запроса
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// Обработка ошибок
if (curl_errno($ch)) {
    $error = curl_error($ch);
    // запись в лог, исключение и т.д.
}

curl_close($ch);
?>
  

Приведённый код отправляет GET запрос на HTTPS endpoint. После выполнения переменная $response содержит тело ответа, а $httpCode – код состояния HTTP. Ошибки, такие как недоступность хоста или проблемы с SSL, обрабатываются через curl_errno().

Типичные ошибки и их решения

  • SSL certificate problem – возникает при неверной цепочке сертификатов. Решение: скачать актуальный cacert.pem с curl.haxx.se и указать путь через CURLOPT_CAINFO. Либо временно отключить проверку через CURLOPT_SSL_VERIFYPEER = false (не рекомендуется для продакшена).
  • Timeout – увеличить значение CURLOPT_TIMEOUT или CURLOPT_CONNECTTIMEOUT.
  • Could not resolve host – проверить правильность URL и состояние DNS.

Как выполнить HTTPS запрос без cURL, используя встроенные функции PHP?

Для простых запросов подходит связка file_get_contents и stream_context_create. Этот метод не требует установки дополнительных расширений, но имеет ограничения.


<?php
$url = 'https://api.example.com/items';
$data = json_encode(['name' => 'test']);

$opts = [
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/json\r\n" .
                     "Accept: application/json\r\n",
        'content' => $data,
        'timeout' => 10,
        'ignore_errors' => true // получать тело ответа даже при ошибках HTTP
    ],
    'ssl' => [
        'verify_peer'      => true,
        'cafile'           => '/path/to/cacert.pem',
        'verify_peer_name' => true
    ]
];

$context = stream_context_create($opts);
$response = @file_get_contents($url, false, $context);
if ($response === false) {
    $error = error_get_last();
    // обработка ошибки
}
?>
  

Настройки SSL передаются в ключе 'ssl'. Таймаут задаётся через 'timeout'. С помощью 'ignore_errors' можно получать тело ответа даже при коде 4xx/5xx. Основной недостаток – сложность управления заголовками запроса и невозможность работы с большими объёмами данных в потоковом режиме.

Распространённые проблемы

  • allow_url_fopen запрещён – в php.ini должна быть директива allow_url_fopen = On. Если отключена, единственный выход – cURL.
  • SSL ошибки – те же, что и для cURL: необходимо указать cacert.pem или временно отключить проверку ('verify_peer' => false).
  • Невозможно отправить DELETE, PUT и другие методы – метод указывается в ключе 'method', всё корректно работает.

Как использовать современный HTTP клиент Guzzle для сложных запросов?

Guzzle – это мощная библиотека, устанавливаемая через Composer. Она предоставляет объектно-ориентированный интерфейс, поддержку асинхронных запросов, мидлвары и встроенную работу с PSR-7. Идеально подходит для сложных API-интеграций.


<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://api.example.com/',
    'timeout'  => 30.0,
    'verify'   => '/path/to/cacert.pem'
]);

try {
    $response = $client->request('POST', 'items', [
        'headers' => [
            'Accept'     => 'application/json',
            'X-API-Key' => 'your-key'
        ],
        'json' => ['name' => 'test']
    ]);
    
    $body = $response->getBody()->getContents();
    $statusCode = $response->getStatusCode();
} catch (\GuzzleHttp\Exception\ConnectException $e) {
    // ошибка соединения
} catch (\GuzzleHttp\Exception\ClientException $e) {
    // ошибка HTTP (4xx)
}
?>
  

Guzzle автоматически преобразует переданные json и устанавливает Content-Type. Обработка ошибок вынесена в исключения. Для простых скриптов установка Composer может быть избыточной, но при активном использовании HTTP-запросов библиотека окупается.

Возможные сложности

  • Composer не установлен – необходима его установка глобально или в проекте.
  • Версия PHP – Guzzle требует PHP 7.2.5+ для последних версий. Старые проекты могут использовать Guzzle 6.
  • Конфликт с другими библиотеками – управляется через composer.json.

Как вручную сформировать HTTPS запрос через сокеты?

Техника для глубокого понимания протокола. Используется редко, но может пригодиться в случаях, когда отсутствуют cURL и allow_url_fopen. Требует ручного формирования запроса и работы с OpenSSL.


<?php
$host = 'api.example.com';
$port = 443;
$path = '/data';

$socket = fsockopen("ssl://$host", $port, $errno, $errstr, 30);
if (!$socket) {
    die("Ошибка: $errstr ($errno)");
}

$request = "GET $path HTTP/1.1\r\n" .
           "Host: $host\r\n" .
           "Connection: close\r\n\r\n";

fwrite($socket, $request);
$response = '';
while (!feof($socket)) {
    $response .= fgets($socket, 4096);
}
fclose($socket);

// Разделяем заголовки и тело
list($headers, $body) = explode("\r\n\r\n", $response, 2);
echo $body;
?>
  

В этом примере используется поток ssl://, который автоматически устанавливает TLS. Такой подход даёт полный контроль, но требует ручной обработки заголовков и передачи данных, а также не поддерживает прокси, куки и другие удобства. Практическое применение ограничено отладкой или встраиванием в системы без cURL.

Типичные ошибки

  • Unknown protocol – если PHP собран без поддержки OpenSSL, ssl:// не работает. Проверить через extension_loaded('openssl').
  • Chunked transfer encoding – сокет не обрабатывает автоматически, поэтому для больших ответов потребуется парсинг Transfer-Encoding: chunked.
  • Блокирующие вызовы – при медленных соединениях скрипт может зависнуть. Рекомендуется задавать таймауты через stream_set_timeout.

Расширенные примеры и нестандартные случаи

Пример 1: cURL с отправкой JSON и получением ответа

Пример

<?php
$ch = curl_init('https://httpbin.org/post');
$payload = json_encode(['key' => 'value', 'number' => 42]);

curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'Accept: application/json'
    ],
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_CAINFO         => '/etc/ssl/certs/ca-certificates.crt',
    CURLOPT_TIMEOUT        => 10
]);

$response = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);

echo "HTTP Code: " . $info['http_code'] . "\n";
echo "Response Body:\n";
echo $response;
?>

Результат выполнения (сокращённый):

HTTP Code: 200
Response Body:
{
  "args": {},
  "data": "{\"key\":\"value\",\"number\":42}",
  "files": {},
  "form": {},
  "headers": {
    "Content-Type": "application/json",
    ...
  },
  "json": {
    "key": "value",
    "number": 42
  },
  "url": "https://httpbin.org/post"
}

Пример 2: file_get_contents для отправки PUT запроса

Пример

<?php
$url = 'https://httpbin.org/put';
$data = json_encode(['updated' => true]);

$opts = [
    'http' => [
        'method'  => 'PUT',
        'header'  => "Content-Type: application/json\r\n" .
                     "Accept: application/json\r\n",
        'content' => $data,
        'timeout' => 5
    ],
    'ssl' => [
        'verify_peer' => true,
        'cafile'      => '/etc/ssl/certs/ca-certificates.crt'
    ]
];

$context = stream_context_create($opts);
$result = file_get_contents($url, false, $context);

if ($result !== false) {
    echo $result;
} else {
    echo "Ошибка: " . print_r(error_get_last(), true);
}
?>

Результат (фрагмент):

{
  "args": {},
  "data": "{\"updated\":true}",
  "form": {},
  "json": {
    "updated": true
  },
  "method": "PUT",
  "url": "https://httpbin.org/put"
}

Пример 3: Guzzle с параллельными асинхронными запросами

Пример

<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['timeout' => 5, 'verify' => '/etc/ssl/certs/ca-certificates.crt']);

$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') {
        echo "$key: успех, код " . $result['value']->getStatusCode() . "\n";
    } else {
        echo "$key: ошибка - " . $result['reason'] . "\n";
    }
}
?>

Результат (примерный вывод):

users: успех, код 200
posts: успех, код 200

Пример 4: cURL с загрузкой файла (multipart/form-data)

Пример

<?php
$file = new CURLFile('/path/to/image.jpg', 'image/jpeg', 'image.jpg');

$ch = curl_init('https://httpbin.org/post');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => ['file' => $file],
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_CAINFO         => '/etc/ssl/certs/ca-certificates.crt'
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "HTTP $httpCode\n";
echo $response;
?>

Результат (часть JSON, где отображаются файлы):

HTTP 200
{
  "files": {
    "file": "data:image/jpeg;base64,..."
  },
  "form": {},
  ...
}

Отправка HTTPS запроса через PHP - comments

En
Https отправить php (php)