简体   繁体   中英

PHP Catch cURL CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT events and take action

I want to detect, catch and do something when CURLOPT_CONNECTTIMEOUT and CURLOPT_TIMEOUT are detected.

How do i do this ?

I have the following headers:

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

and the folowing function, where $res is a array that contains html file names

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
}

To get info about request, you can take a look on curl_getinfo or curl_multi_info_read

And use it something like it:

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

in an info array you can receive following data:

  • "url"
  • "content_type"
  • "http_code"
  • "header_size"
  • "request_size"
  • "filetime"
  • "ssl_verify_result"
  • "redirect_count"
  • "total_time"
  • "namelookup_time"
  • "connect_time"
  • "pretransfer_time"
  • "size_upload"
  • "size_download"
  • "speed_download"
  • "speed_upload"
  • "download_content_length"
  • "upload_content_length"
  • "starttransfer_time"
  • "redirect_time"
  • "certinfo"
  • "request_header" (This is only set if the CURLINFO_HEADER_OUT is set by a previous call to curl_setopt())

You have 2 options:

  1. In the array returned from curl_getinfo($ch) , compare the connect_time to the the vale you used for the CURLOPT_CONNECTTIMEOUT option. You can also compare total_time to the value you used for CURLOPT_TIMEOUT . If you dump out curl_getinfo($ch) you will see there are a bunch of other timers as well that you can deduce whatever you need.
  2. Use the string returned from curl_error($ch) . If any of your *_TIMEOUT options are hit, this will return a string like:

Operation timed out after 2001 milliseconds with 0 bytes received

You can have a function like the following that will try to connect 3 times and stop if not succeed. The time out will be increase with each attempt just in case the server is "FULL" and just need a little bit of time.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM