Definindo o tempo limite do curl no PHP

230

Estou executando uma solicitação de curl em um banco de dados eXist através do php. O conjunto de dados é muito grande e, como resultado, o banco de dados leva consistentemente um longo período de tempo para retornar uma resposta XML. Para corrigir isso, configuramos uma solicitação de curvatura, com o que deveria ser um tempo limite longo.

$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);

No entanto, a solicitação de ondulação termina consistentemente antes da conclusão da solicitação (<1000 quando solicitado por um navegador). Alguém sabe se esta é a maneira correta de definir tempos limite em curl?

Moki
fonte

Respostas:

346

Consulte a documentação: http://www.php.net/manual/en/function.curl-setopt.php

CURLOPT_CONNECTTIMEOUT- O número de segundos a esperar enquanto tenta se conectar. Use 0 para esperar indefinidamente.
CURLOPT_TIMEOUT- O número máximo de segundos para permitir a execução de funções cURL.

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

Também não se esqueça de aumentar o tempo de execução do script php self:

set_time_limit(0);// to infinity for example
msangel
fonte
13
Você não precisa set_time_limit(0);se o script está sendo executado no console.
CONvid19
6
@PedroLobito, o que você mencionou é a configuração padrão do php on cli, mas é possível que isso possa ter sido modificado.
19417 cherouvim
4
@cherouvim está obviamente correto aqui (basta executar php -d max_execution_time=1 -r 'while(true){$r=1*1;}'ou algo para observar em ação que o cli não possui uma bandeira mágica 'sempre ilimitada'.
Wrikken
@ Pedro Lobito, você não precisa set_time_limit(0)se não o estiver usando dentro de um loop.
Viktor Joras 14/09
58

Hmm, parece-me que CURLOPT_TIMEOUTdefine a quantidade de tempo que qualquer função cURL pode levar para executar. Eu acho que você realmente deveria estar olhando CURLOPT_CONNECTTIMEOUT, pois isso indica ao cURL a quantidade máxima de tempo para aguardar a conclusão da conexão.

Chad Birch
fonte
Enquanto os documentos em PHP dizem que CURLOPT_TIMEOUTé sobre quanto tempo a função leva, os documentos subjacentes da biblioteca de curl parecem dizer que é sobre quanto tempo a solicitação leva, o que é uma distinção interessante - não tenho certeza de que maneira ler isso!
Fideloper 21/12/15
Eu acho que aqui é a melhor interpretação: stackoverflow.com/questions/27776129/...
fideloper
33

Há uma peculiaridade nisso que pode ser relevante para algumas pessoas ... A partir dos comentários dos documentos do PHP.

Se você deseja que o cURL atinja o tempo limite em menos de um segundo, é possível usá-lo CURLOPT_TIMEOUT_MS, embora exista um bug / "recurso" em "sistemas tipo Unix" que faça com que o libcurl atinja o tempo limite imediatamente se o valor for <1000 ms com o erro "cURL Erro (28): tempo limite atingido ". A explicação para esse comportamento é:

"Se a libcurl for criada para usar o resolvedor de nomes de sistema padrão, essa parte da transferência ainda usará a resolução de segundo inteiro para tempos limite com um tempo limite mínimo permitido de um segundo."

O que isso significa para os desenvolvedores do PHP é "Você não pode usar esta função sem testá-la primeiro, porque não pode saber se a libcurl está usando o resolvedor de nomes de sistema padrão (mas você pode ter certeza de que está)"

O problema é que, no (Li | U) nix, quando a libcurl usa o resolvedor de nomes padrão, um SIGALRM é gerado durante a resolução de nomes que a libcurl considera o alarme de tempo limite.

A solução é desativar os sinais usando CURLOPT_NOSIGNAL. Aqui está um exemplo de script que se solicita causando um atraso de 10 segundos para que você possa testar o tempo limite:

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.";
}

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

Simon East
fonte
Olá, este código funciona, mas o arquivo de origem tem 7MB e esse download me apenas 52KB, o que poderia estar errado? URL é algo como webserver.tld / folder / download /…
Muflix
@Simon leste você pode por favor me ajude stackoverflow.com/questions/30861112/...
Nathan Srivi
Note-se que você está esperando um erro de tempo limite com este script
kmoney12
30

Seu código define o tempo limite para 1000 segundos . Por milissegundos, use CURLOPT_TIMEOUT_MS.

Matt Humphreys
fonte
13

Você precisará garantir o tempo limite entre você e o arquivo. Nesse caso, PHP e Curl.

Para dizer ao Curl para nunca atingir o tempo limite quando uma transferência ainda está ativa, você deve definir CURLOPT_TIMEOUTpara 0, em vez de 1000.

curl_setopt($ch, CURLOPT_TIMEOUT, 0);

No PHP, novamente, você deve remover os limites de tempo ou o próprio PHP (após 30 segundos por padrão) matará o script conforme a solicitação de Curl. Isso por si só deve corrigir seu problema .
Além disso, se você precisar de integridade dos dados, poderá adicionar uma camada de segurança usando 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);

Uma desconexão do cliente interromperá a execução do script e possivelmente danificará os dados,
por exemplo. consulta de banco de dados não transitória, criação de um arquivo de configuração, etc., enquanto no seu caso ele baixaria um arquivo parcial ... e você pode ou não se importar com isso.

Respondendo a essa pergunta antiga porque esse segmento está no topo das pesquisas de mecanismo CURL_TIMEOUT.

MarcoP
fonte
8

Você não pode executar a solicitação em um navegador, o tempo limite será aguardado até o servidor que está executando a solicitação CURL responder. O navegador provavelmente está atingindo o tempo limite em 1 a 2 minutos, o tempo limite padrão da rede.

Você precisa executá-lo na linha de comando / terminal.

Brent Baisley
fonte
2
+1 - o tempo limite provavelmente é externo à ondulação. Na verdade, você pode contornar o tempo limite do navegador, certificando-se de produzir algo periodicamente; Os navegadores geralmente redefinem o tempo limite sempre que recebem mais dados. Mas isso é um truque; executar via CLI é (quase?) sempre preferível.
Frank Farmer #
3

Se você estiver usando PHP como um aplicativo fastCGI, verifique as configurações de tempo limite do fastCGI. Veja: PHP curl colocar erro 500

wbinky
fonte