PHP捕获cURL CURLOPT_TIMEOUT和CURLOPT_CONNECTTIMEOUT事件并采取行动


PHP Catch cURL CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT events and take action

当检测到CURLOPT_CONNECTTIMEOUT和CURLOPT_TIMEOUT时,我想检测、捕获并执行一些操作。

我该怎么做?

我有以下标题:

public static $userAgents = array(
    'FireFox3' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9) Gecko/2008052906 Firefox/3.0',
    'GoogleBot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
    'IE7' => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
    'Netscape' => 'Mozilla/4.8 [en] (Windows NT 6.0; U)',
    'Opera' => 'Opera/9.25 (Windows NT 6.0; U; en)'
);
public static $options = array(
    CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
    CURLOPT_AUTOREFERER => true,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_FRESH_CONNECT => true,
    CURLOPT_COOKIEJAR => "cookies.txt",
    CURLOPT_COOKIEFILE => "cookies.txt",
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT => 300,
        //CURLOPT_COOKIESESSION => false,
);

和下面的函数,其中$res是一个包含html文件名的数组

public function multiCurl($res, $options = "") {
    if (count($res) <= 0)
        return False;
    $handles = array();
    if (!$options) // add default options
        $options = self::$options;
    // add curl options to each handle
    foreach ($res as $k => $row) {
        $ch{$k} = curl_init();
        $options[CURLOPT_URL] = $row['url'];
        curl_setopt_array($ch{$k}, $options);
        $handles[$k] = $ch{$k};
    }
    $mh = curl_multi_init();
    foreach ($handles as $k => $handle) {
        curl_multi_add_handle($mh, $handle);
    }
    $running_handles = null;
    //execute the handles
    do {
        $status_cme = curl_multi_exec($mh, $running_handles);
    } while ($cme == CURLM_CALL_MULTI_PERFORM);
    while ($running_handles && $status_cme == CURLM_OK) {
        if (curl_multi_select($mh) != -1) {
            do {
                $status_cme = curl_multi_exec($mh, $running_handles);
            } while ($status == CURLM_CALL_MULTI_PERFORM);
        }
    }
    foreach ($res as $k => $row) {
        $res[$k]['error'] = curl_error($handles[$k]);
        if (!empty($res[$k]['error']))
            $res[$k]['data'] = '';
        else {
            //$res[$k]['data'] = curl_multi_getcontent($handles[$k]);  // get results 
            file_put_contents(CRAWLER_FILES . $k . '.html', curl_multi_getcontent($handles[$k]));
        }
        // close current handler
        curl_multi_remove_handle($mh, $handles[$k]);
    }
    curl_multi_close($mh);
    return $res; // return response
}

要获得有关请求的信息,您可以查看curl_getinfocurl_multi_info_read

并使用类似的东西:

curl_exec($ch);
if(!curl_errno($ch))
{
 $info = curl_getinfo($ch);
 echo 'Took ' . $info['total_time'] . ' seconds to send a request to ' . $info['url'];
}

在信息数组中,您可以接收以下数据:

  • "url"
  • "content_type"
  • "http_code"
  • "header_size"
  • "requestrongize"
  • "文件时间"
  • "ssl_verify_result"
  • "重定向计数"
  • "total_time"
  • "namelookup_time"
  • "连接时间"
  • "预传输时间"
  • "size_upload"
  • "size_download"
  • "speed_download"
  • "speed_pload"
  • "download_content_length"
  • "upload_content_length"
  • "starttransfer_time"
  • "重定向时间"
  • "certinfo"
  • "request_header"(仅当CURLINFO_HEADER_OUT由以前的调用curl_setopt())

您有两个选项:

  1. 在从curl_getinfo($ch)返回的数组中,将connect_time与用于CURLOPT_CONNECTTIMEOUT选项的值进行比较。您还可以将total_time与用于CURLOPT_TIMEOUT的值进行比较。如果你扔掉curl_getinfo($ch),你会发现还有很多其他计时器,你可以推断出你需要的任何东西
  2. 使用从curl_error($ch)返回的字符串。如果您的任何*_TIMEOUT选项被命中,这将返回一个字符串,如:

操作在2001毫秒后超时,收到0个字节的

您可以使用如下函数,该函数将尝试连接3次,如果不成功则停止。每次尝试都会增加超时时间,以防服务器"已满",只需要一点时间。

public function functionName($attempt = 0) {
    if ($attemp >= 3) {
        return FALSE;
    }
    $TIMEOUT = 1;
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $TIMEOUT + $attempt);
    curl_exec($ch);
    if (!curl_errno($ch)) {
        $info = curl_getinfo($ch);
        if ($info['total_time'] > $TIMEOUT) {
            $this->functionName($attempt++);
        } else {
            return TRUE;
        }
    }
}