在PHP中设置Curl的超时


230

我正在通过php在eXist数据库上运行curl请求。数据集非常大,因此,数据库始终需要很长时间才能返回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中设置超时的正确方法吗?

Answers:


346

请参阅文档:http : //www.php.net/manual/zh/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脚本自身的执行时间:

set_time_limit(0);// to infinity for example

13
set_time_limit(0);如果脚本在控制台上运行,则不需要。
CONvid19 2016年

6
@PedroLobito您提到的是cli上php的默认配置,但可能已被修改。
cherouvim

4
@cherouvim在这里显然是正确的(只是跑步php -d max_execution_time=1 -r 'while(true){$r=1*1;}'或观察到一些事实,表明cli没有神奇的“永远无限”标志
。– Wrikken

set_time_limit(0)如果您不在循环中使用@Pedro Lobito,则不需要。
维克多·乔拉斯

58

嗯,对我来说,它CURLOPT_TIMEOUT定义了允许任何cURL函数执行所需的时间。我认为您实际上应该在看CURLOPT_CONNECTTIMEOUT,因为这告诉cURL等待连接完成的最长时间。


虽然PHP中文档说的CURLOPT_TIMEOUT是函数要花多长时间,但是底层curl库文档似乎说的是请求要花多长时间,这是一个有趣的区别-不确定读取哪种方式!
fideloper

我认为这是最好的解释:stackoverflow.com/questions/27776129/…–
fideloper

33

这可能与某些人有关。这个问题来自PHP文档注释。

如果您希望cURL在不到一秒的时间内超时,则可以使用CURLOPT_TIMEOUT_MS,尽管“类Unix系统”上存在一个bug /“功能”,如果值<1000 ms且错误为“ cURL”,则会导致libcurl立即超时错误(28):已达到超时”。此行为的解释是:

“如果libcurl是为使用标准系统名称解析器而构建的,则传输的那部分仍将使用整秒的分辨率进行超时,最小超时允许为一秒钟。”

这对PHP开发人员意味着什么:“您必须先对其进行测试,才能使用此功能,因为您无法确定libcurl是否正在使用标准系统名称解析器(但可以肯定的是)”

问题在于,在(Li | U)nix上,当libcurl使用标准名称解析器时,libcurl认为这是超时警报时,在名称解析期间会引发SIGALRM。

解决方案是使用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/zh/function.curl-setopt.php#104597


您好,此代码有效,但源文件为7MB,仅下载我52KB,这可能是什么错误?URL类似于webserver.tld / folder / download /…
Muflix


应该注意的是,您期望该脚本超时错误
kmoney12 '17


13

您将需要确保您和文件之间的超时。在这种情况下,PHP和Curl。

要让Curl在传输仍处于活动状态时永不超时,您需要将设置CURLOPT_TIMEOUT0,而不是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


8

您无法从浏览器运行请求,它将等待运行CURL请求的服务器响应而超时。浏览器可能会在1-2分钟(默认网络超时)中超时。

您需要从命令行/终端运行它。


2
+1-超时可能是外部卷曲的。通过确保定期输出某些内容,您实际上可以解决浏览器超时的问题。浏览器通常在每次接收更多数据时重置其超时。但这是骇客。通过CLI运行(几乎是?)总是可取的。
Frank Farmer

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.