PHP cURL and SSL Connection Timeout

Apr02
Missing Image
By Ken Foubert

I've been working on a web site that uses cURL for request/response transactions and I was encountering a number of problems with empty responses from the server. This caused some frustrations, since these empty responses caused entire sections of a web page to be empty, especially on searches. Well, I couldn't have that, since people using the website would be confused on why a search for an item only worked occasionally. Trust in the web application would drop dramatically.

My first instinct was to blame the server for returning empty responses, but realized that I shouldn't jump to conclusions about other people's servers. So, I launched myself into debugging the request/response transaction.

Let's take a look at some PHP code for performing a cURL transaction. The most important thing to remember is that I can't stop the processing if an error occurs. So, if there is an error, the function returns an empty string.

// keep looping until we get a response
$count = 0;

// try to get a good response by looping 10 times
while( $response == "" )
{
    $count++;

    $response = curl_request( "https://php.net", "search=curl" );

    // if we looped ten times and still no response, lets quit to avoid never ending loop
    if( $count == 10 )
        break;

}    //end while loop

function curl_request($server_url, $values)
{
    // this array stores all the information for a cURL transaction
    $arrCurlInfo = array();

    $arrCurlOptions = array();

    $arrCurlOptions[CURLOPT_HEADER] = 1;

    $arrCurlOptions[] = "";

    // set to 1 to include header info from response
        $arrCurlOptions[CURLOPT_HEADER] = 1;
        
        //Return the output from the cURL session rather than displaying in the browser.
        //If already set, don't overwrite
        $arrCurlOptions[CURLOPT_RETURNTRANSFER] = 1;
       
        // if page redirects, curl will follow
        $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1, false); //
       
        //If already set, don't overwrite
        $arrCurlOptions[ CURLOPT_USERAGENT] = $_SERVER['HTTP_USER_AGENT'];
       
        / attempt the request/response
    try
        {
            $fp = curl_init();
           
            curl_setopt_array($fp, $arrCurlOptions);
   
        $response = curl_exec($fp);
           
        $arrCurlInfo = curl_getinfo($fp);
           
        }    //end try
       

    // catch any errors that occur and return an empty response
        catch( Exception $e)
        {
            $strResponse = "";

        $strErrorCode = $e->getCode();
       
        $strErrorMessage = $e->getMessage();

        log_curl_error($arrCurlInfo, $strErrorCode, $strErrorMessage);

        }    //end catch
               
    curl_close($fp);
           
    $fp = null;
   
    return $response;

    }    //end function

The log_curl_error() is a function that simply stores the cUrl information and the error code and message to a database table. Now, let's pretend that I run this script a large number of times. Once in a while, no response is returned. I take a look at the log table and notice that I get the same error message of "SSL connection timeout" and they are always in groups of ten.
Hmm, that must mean that even though we're re-initializing the cURL each time we loop through, it must be using the same connection each time. So, once the first connection is bad, each call to curl_request() uses the same connection. After some research, I found out that the cURL connection is cached.

I'm thinking that for some reason, the web site and the server have trouble connecting using "HTTPS," but since the connection is cached, we keep getting an empty response, no matter how many times we loop. During the afore mentioned research, I also discovered a cURL option,CURLOPT_FRESH_CONNECT, for clearing the cache. Additional cURL options.

Using this new insight, I added one more cURL option to the curl_request() function.

$arrCurlOptions[CURLOPT_FRESH_CONNECT] = 1;

By adding this option, the connection is cleared each time we run the loop. For example, the first time through the loop, the SSL connection between the web site and server is bad, and we get a "SSL connection timeout" error. The second time through, the connection is refreshed, this time the SSL connection between the web site and server is good. The function is now able to return a response from the server.


Dev

Back To Feed