[PHP]curlCURLOPT_TIMEOUT_MS小於1秒解決方案

progpark發表於2016-12-09

CURLOPT_TIMEOUT 設定cURL允許執行的最長秒數
CURLOPT_TIMEOUT_MS 設定cURL允許執行的最長毫秒數
CURLOPT_CONNECTTIMEOUT 在發起連線前等待的時間,如果設定為0,則無限等待
CURLOPT_CONNECTTIMEOUT_MS 嘗試連線等待的時間,以毫秒為單位。如果設定為0,則無限等待

CURLOPT_TIMEOUT_MS 在cURL 7.16.2中被加入。從PHP 5.2.3起可使用。
所以使用的時候請先檢視libcurl版本 curl –version。

但是這個函式有個bug,如果時間小於1000毫秒也就是1秒的話,會立馬報錯,檢視下面說明

  If you want cURL to timeout in less than one second, you can use CURLOPT_TIMEOUT_MS, although there is a bug/"feature"  on "Unix-like systems" that causes libcurl to timeout immediately if the value is < 1000 ms with the error "cURL Error (28): Timeout was reached".  The explanation for this behavior is:
  "If libcurl is built to use the standard system name resolver, that portion of the transfer will still use full-second resolution for timeouts with a minimum timeout allowed of one second."
  What this means to PHP developers is "You can use this function without testing it first, because you can`t tell if libcurl is using the standard system name resolver (but you can be pretty sure it is)"
  The problem is that on (Li|U)nix, when libcurl uses the standard name resolver, a SIGALRM is raised during name resolution which libcurl thinks is the timeout alarm.
  The solution is to disable signals using CURLOPT_NOSIGNAL.  Here`s an example script that requests itself causing a 10-second delay so you can test timeouts:

增加 curl_setopt($ch, CURLOPT_NOSIGNAL, 1) 可以解決此問題:

if (!isset($_GET[`foo`])) {
    // Client
    $ch = curl_init(`http://localhost/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
";
    } else {
         echo "Data received: $data
";
    }
} else {
    // Server
    sleep(10);
    echo "Done.";
} 


相關文章