Как быстро вызвать curl в PHP из 1.php без ожидания ответа
В 1.php можно отправить запрос к 2.php через cURL, сразу закрыв соединение и не дожидаясь ответа, используя опции CURLOPT_RETURNTRANSFER=false, Connection: close.
Как вызвать curl в PHP и не ждать ответа от удалённого скрипта?
У меня есть скрипт 1.php, который делает запрос к 2.php через curl.
Скрипт 2.php может выполняться долго (например, sleep(10)).
Я хочу, чтобы скрипт 1.php сразу выводил “1-ok” и завершался, не дожидаясь завершения 2.php.
Как настроить curl или использовать асинхронный запрос, чтобы это было возможно?
Скрипт 1.php может «отправить» запрос к 2.php, сразу закрывая соединение и не дожидаясь его завершения.
Нужно заставить cURL «отправить» HTTP‑запрос, затем закрыть сокет до получения ответа. Это достигается комбинацией опций, которые отключают ожидание ответа и заставляют сервер держать соединение открытым.
Содержание
- Краткое решение
- Подключаем cURL и задаём параметры
- Пошаговый пример кода
- Альтернативы: fsockopen и Guzzle
- Пояснения к опциям
- Заключение
- Источники
Краткое решение
$ch = curl_init('http://example.com/2.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); // не хранить ответ
curl_setopt($ch, CURLOPT_HEADER, false); // без заголовков
curl_setopt($ch, CURLOPT_NOSIGNAL, 1); // не использовать сигналы
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1); // очень короткое ожидание
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Connection: close']);
curl_exec($ch); // отправляем, но не ждём ответа
curl_close($ch);
echo "1-ok";
— Connection: close говорит серверу, что клиент сразу разорвёт соединение, но сервер продолжит работу скрипта 2.php.
Подключаем cURL и задаём параметры
| Параметр | Что делает | Почему важно |
|---|---|---|
CURLOPT_RETURNTRANSFER = false |
Не сохранять ответ в переменную | Уменьшает нагрузку |
CURLOPT_HEADER = false |
Не получать заголовки | Уменьшает объём данных |
CURLOPT_NOSIGNAL = true |
Отключить сигналы (не блокирует) | Не вызывает таймауты |
CURLOPT_TIMEOUT_MS = 1 |
Минимальный таймаут в миллисекундах | Позволяет быстро завершить curl_exec |
CURLOPT_CONNECTTIMEOUT_MS = 1 |
Минимальный таймаут подключения | Быстрое завершение при проблемах |
CURLOPT_HTTPHEADER = ['Connection: close'] |
Сообщаем серверу об отключении | Сервер продолжит работу в фоне |
Информация об опциях: PHP Manual – curl_setopt.
Пошаговый пример кода
<?php
// 1.php
$url = 'http://example.com/2.php'; // адрес 2.php
$ch = curl_init($url);
// Отключаем ожидание ответа
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
// Минимальный таймаут, чтобы curl «забросил» запрос и закрыл соединение
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 1);
// Указываем, что соединение будет закрыто клиентом
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Connection: close']);
// Отправляем запрос
curl_exec($ch);
curl_close($ch);
// Немедленный вывод
echo '1-ok';
?>
Когда 1.php будет выполнен, сервер 2.php уже получил запрос и продолжит работу (например sleep(10)), но клиент уже получил ответ и завершил скрипт.
Альтернативы: fsockopen и Guzzle
1. fsockopen
$fp = fsockopen('example.com', 80, $errno, $errstr, 1);
if ($fp) {
fwrite($fp, "GET /2.php HTTP/1.1\r\n");
fwrite($fp, "Host: example.com\r\n");
fwrite($fp, "Connection: close\r\n\r\n");
fclose($fp); // закрываем сразу, не читаем ответ
}
echo '1-ok';
fsockopenоткрывает низкоуровневый сокет, отправляет raw HTTP‑запрос и сразу закрывает соединение. Это самый «чистый» способ fire‑and‑forget.
2. Guzzle (асинхронный запрос)
$client = new \GuzzleHttp\Client();
$promise = $client->requestAsync('GET', 'http://example.com/2.php');
$promise->then(
fn($res) => null, // ничего не делаем при ответе
fn($e) => null // игнорируем ошибки
);
// Не ждём, просто продолжаем выполнение
echo '1-ok';
Guzzle поддерживает асинхронные запросы, но по‑прежнему держит соединение открытым до завершения. Для настоящего fire‑and‑forget лучше использовать
fsockopenили описанный выше cURL‑вариант.
Пояснения к опциям
Connection: close
HTTP‑заголовок, который сообщает серверу, что клиент не будет держать соединение открытым. Это ключ к тому, что сервер будет продолжать работу после того, как клиент разорвет соединение.CURLOPT_TIMEOUT_MS/CURLOPT_CONNECTTIMEOUT_MS
Устанавливают минимальный таймаут в миллисекундах. Если задать1,curl_execпочти мгновенно вернёт управление, даже если сервер ещё обрабатывает запрос.CURLOPT_NOSIGNAL
Отключает использование сигналов, которые могут блокироватьcurl_execпри таймауте в некоторых версиях PHP.
Заключение
- С помощью cURL: задайте
Connection: close, минимальные таймауты и отключите возврат данных. Послеcurl_execсразу закройте дескриптор и выводите1-ok. - Если нужно более простое решение: используйте
fsockopenи посылайте raw HTTP‑запрос. - Асинхронные библиотеки (например, Guzzle) не гарантируют fire‑and‑forget; они ждут завершения соединения, поэтому для настоящего «отправить и забыть» предпочтительнее cURL‑вариант выше.
Эти методы позволяют 1.php завершиться мгновенно, а 2.php продолжать работу в фоновом режиме, даже если это
sleep(10)или более длительная операция.