Установка таймаута Curl в PHP

230

Я запускаю запрос curl для базы данных eXist через php. Набор данных очень большой, и, как следствие, базе данных постоянно требуется много времени для возврата XML-ответа. Чтобы исправить это, мы настроили запрос curl, который должен быть долгим.

$ch = curl_init();
$headers["Content-Length"] = strlen($postString);
$headers["User-Agent"] = "Curl/1.0";

curl_setopt($ch, CURLOPT_URL, $requestUrl);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERPWD, 'admin:');
curl_setopt($ch,CURLOPT_TIMEOUT,1000);
$response = curl_exec($ch);
curl_close($ch);

Тем не менее, запрос curl последовательно завершается до его завершения (<1000 при запросе через браузер). Кто-нибудь знает, это правильный способ установить таймауты в curl?

Moki
источник

Ответы:

346

См документацию: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- Количество секунд ожидания при попытке подключения. Используйте 0, чтобы ждать бесконечно.
CURLOPT_TIMEOUT- Максимальное количество секунд, чтобы позволить функциям cURL выполнить.

curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0); 
curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout in seconds

Также не забудьте увеличить время выполнения скрипта php self:

set_time_limit(0);// to infinity for example
msangel
источник
13
Вам не нужно, set_time_limit(0);если скрипт работает на консоли.
CONvid19
6
@PedroLobito, что вы упоминаете, является конфигурацией по умолчанию для php на cli, но возможно, что это могло быть изменено.
Черувим
4
@cherouvim, очевидно, здесь правильный (просто запустите php -d max_execution_time=1 -r 'while(true){$r=1*1;}'или что-то, чтобы наблюдать в действии, что у cli нет волшебного флага «всегда неограничен».
Wrikken
@Pedro Lobito вам не нужно, set_time_limit(0)если вы не используете его внутри цикла.
Виктор Жорас
58

Хм, похоже, он CURLOPT_TIMEOUTопределяет количество времени, которое любая функция cURL может занять для выполнения. Я думаю, что вы должны смотреть CURLOPT_CONNECTTIMEOUTвместо этого, так как это говорит cURL максимальное количество времени ожидания для завершения соединения.

Чад берез
источник
В то время как документы в PHP говорят CURLOPT_TIMEOUTо том, сколько времени занимает функция, базовые документы библиотеки curl, похоже, говорят о том, сколько времени занимает запрос, что является интересным отличием - не уверен, каким способом это читать!
Фиделопер
Я думаю, что здесь лучшая интерпретация: stackoverflow.com/questions/27776129/…
fideloper
33

Есть странная вещь, которая может иметь отношение к некоторым людям ... Из комментариев к документам PHP.

Если вы хотите, чтобы cURL превышал время ожидания менее чем за одну секунду, вы можете использовать его CURLOPT_TIMEOUT_MS, хотя в «Unix-подобных системах» есть ошибка / «функция», которая приводит к немедленному истечению времени ожидания libcurl, если значение <1000 мс с ошибкой «cURL» Ошибка (28): истекло время ожидания ». Объяснение этого поведения:

«Если libcurl создан для использования стандартного распознавателя имен системы, эта часть передачи будет по-прежнему использовать разрешение в полсекунды для тайм-аутов с минимально допустимым тайм-аутом, равным одной секунде».

Для разработчиков PHP это означает, что «Вы не можете использовать эту функцию без предварительного тестирования, потому что вы не можете сказать, использует ли libcurl стандартный преобразователь имен системы (но вы можете быть уверены, что это так)»

Проблема заключается в том, что в (Li | U) nix, когда libcurl использует стандартный преобразователь имен, во время разрешения имени возникает SIGALRM, который libcurl считает сигналом времени ожидания.

Решение состоит в том, чтобы отключить сигналы, используя CURLOPT_NOSIGNAL. Вот пример сценария, который запрашивает себя, вызывая 10-секундную задержку, чтобы вы могли проверить таймауты:

if (!isset($_GET['foo'])) {
    // Client
    $ch = curl_init('http://localhost/test/test_timeout.php?foo=bar');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
    $data = curl_exec($ch);
    $curl_errno = curl_errno($ch);
    $curl_error = curl_error($ch);
    curl_close($ch);

    if ($curl_errno > 0) {
        echo "cURL Error ($curl_errno): $curl_error\n";
    } else {
        echo "Data received: $data\n";
    }
} else {
    // Server
    sleep(10);
    echo "Done.";
}

От http://www.php.net/manual/en/function.curl-setopt.php#104597

Саймон Ист
источник
Здравствуйте, этот код работает, но исходный файл 7 МБ, и это загрузить меня только 52 КБ, что может быть не так? URL - это что-то вроде webserver.tld / folder / download /…
Muflix,
@Simon East, не могли бы вы мне помочь stackoverflow.com/questions/30861112/…
Натан Шриви,
Следует отметить, что вы ожидаете ошибку тайм-аута с этим сценарием
kmoney12
30

Ваш код устанавливает время ожидания до 1000 секунд . Для миллисекунд, используйте CURLOPT_TIMEOUT_MS.

Мэтт Хамфрис
источник
13

Вам нужно будет убедиться в тайм-аутах между вами и файлом. В этом случае PHP и Curl.

Сказать Curl , чтобы никогда не тайм - аут , когда передача все еще активна, вам нужно установить CURLOPT_TIMEOUTна 0, вместо 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

В PHP, опять же, вы должны удалить временные ограничения или PHP сам по себе (через 30 секунд по умолчанию) уничтожит скрипт по запросу Curl. Это само по себе должно решить вашу проблему .
Кроме того, если вам требуется целостность данных, вы можете добавить уровень безопасности, используя ignore_user_abort:

# The maximum execution time, in seconds. If set to zero, no time limit is imposed.
set_time_limit(0);

# Make sure to keep alive the script when a client disconnect.
ignore_user_abort(true);

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

Отвечая на этот старый вопрос, потому что эта тема находится вверху поисковиков CURL_TIMEOUT.

MarcoP
источник
8

Вы не можете запустить запрос из браузера, он будет ждать по истечении времени ожидания ответа сервера CURL. Вероятно, время ожидания браузера составляет 1-2 минуты, по умолчанию время ожидания сети.

Вам нужно запустить его из командной строки / терминала.

Брент Бэйсли
источник
2
+1 - время ожидания, вероятно, является внешним по отношению к скручиванию. На самом деле вы можете обойти тайм-аут браузера, периодически проверяя что-либо; браузеры обычно сбрасывают время ожидания каждый раз, когда получают больше данных. Но это взломать; работа через CLI (почти?) всегда предпочтительнее.
Франк Фармер
3

Если вы используете PHP в качестве приложения fastCGI, то обязательно проверьте настройки тайм-аута fastCGI. Смотрите: PHP curl put 500 error

wbinky
источник