file_get_contents_with_timeout

So here’s a piece of code which I think you guys will like. It’s a URL call with timeout function in PHP.


/* This works only for simple URIs
  Returns:

  array(headers, body): if everything's fine.
  TIMED OUT if it times out.
  UNABLE TO OPEN if we can't connect to host.
  */
private function file_get_contents_with_timeout($url, $read_timeout = 5, $connection_timeout = 5) {
  $url_parts = parse_url($url);

  $host = $url_parts['host'];
  $get = $url_parts['path'] . '?' . $url_parts['query'];

  $fp = fsockopen($host, 80, $errno, $errstr, $connection_timeout);
  if (!$fp) {
    return "UNABLE TO OPEN";
  } else {
    $out = "GET $get HTTP/1.1\r\n";
    $out .= "Host: $host\r\n";
    $out .= "Connection: Close\r\n\r\n";

    fwrite($fp, $out);
    stream_set_timeout($fp, $read_timeout);

    $result = stream_get_contents($fp);
    $divider = strpos($result, "\r\n\r\n");
    $headers = substr($result, 0, $divider);

    $body = substr($result, $divider, strlen($result));

    $info = stream_get_meta_data($fp);

    fclose($fp);

    if ($info['timed_out']) {
      return 'TIMED OUT';
    } else {
      return array('headers' => $headers, 'body' => $body);
    }
  }
}

Yup, a bit crude, but hey it works for me! (Oh, and it probably needs PHP5). Feel free to take the core logic out and wrap it up in exceptions and what have you.

Why did I have to write this contraption? Ah, the joys of the Indian SMS scene. Let me take you through a tour: Fastalerts is a bulk SMS solution for end users and resellers. The web frontend is written in PHP using Symfony (an older version, 0.6). The API is written in plain PHP and it connects to a SOAP-based (using nuSOAP) SMS sending solution.

This is a comment I have on top of the new backend code which sums up all the complexity:


/*
  A note on message sending.

  These actions have to happen as transactions:
  * Calling the GATEWAY.
  * Entering data into LOGS.
  * Reducing CREDITS.

  ONLY if:
  * User has "enough" credits.
  * Input is valid (numbers and mesage)
  * User has valid credentials

  AND we have to handle:
  * Gateway timeouts
  * Gateway errors
  * CDMA senderid correction.

  ALSO:
  If the user doesn't have enough credits to send the entirety of numbers,
  messages are sent until his credits are exhausted.

  AND:
  A separate status message is returned for each of these conditions.

  BUT WE ENSURE:
  That everything is logged appropriately:

  * All successfully sent messages are logged and credits reduced.
  * In every other case, credits are NOT reduced (we are customer friendly).
  * When gateway times out or errors out, the messages are logged.

*/

Interested people should note that there is a lot more you can add on to this: dynamic gateway switches (automatic failover), regular gateway tests, more backend support etc. but this is the bare minimum that’s needed for the backend to work. If you spend some time thinking about the problem, you’ll come to the realization that this bit:


 AND we have to handle:
  * Gateway timeouts
  * Gateway errors

means that we have to handle gateways that time out and never return a response. Most of the SMPP providers in India use something called NowSMS to manage their backend connectivity to the operator. In short: we connect to a vendor via his common gateway, he routes it (depending on destination) to multiple operators. NowSMS exposes a simple HTTP service (a URL call in other words) to add SMS to the vendor queue and it’s this service that’s preferred by a majority of the good vendors. However, HTTP traffic being what it is, a monolithic backend in PHP will stall if the request doesn’t return a response. Hence that file_get_contents_with_timeout.

Note: this is hardly an ideal solution (that would be a separate daemon). But without adding moving parts, this simple function should increase the reliability of our backend.

2 Replies to “file_get_contents_with_timeout”

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s