Sometimes the connection to a remote host may stall and a resource
cannot be retrieved. This makes Tweeper hang for a very long time which
can be annoying for users.
Setting a shorter timeout and a retry mechanism usually works around the
problem allowing the resource to be retrieved eventually.
Implement such a mechanism by adding curlExec() method and while at it
move non-curl related messages outside of getUrlContents() and
getUrlInfo() to give the user a better understanding of what actually
failed when even the retry mechanism was not able to retrieve the
resource.
class Tweeper {
private static $userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0";
class Tweeper {
private static $userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:60.0) Gecko/20100101 Firefox/60.0";
+ private static $maxConnectionTimeout = 5;
+ private static $maxConnectionRetries = 5;
/**
* Create a new Tweeper object controlling optional settings.
/**
* Create a new Tweeper object controlling optional settings.
+ * Perform a cURL session multiple times when it fails with a timeout.
+ *
+ * @param resource $ch
+ * a cURL session handle.
+ */
+ private static function curlExec($ch) {
+ $ret = FALSE;
+ $attempt = 0;
+ do {
+ $ret = curl_exec($ch);
+ if (FALSE === $ret) {
+ trigger_error(curl_error($ch), E_USER_WARNING);
+ }
+ } while (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT && ++$attempt < Tweeper::$maxConnectionRetries);
+
+ return $ret;
+ }
+
+ /**
* Get the contents from a URL.
*/
private static function getUrlContents($url) {
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_HEADER => FALSE,
* Get the contents from a URL.
*/
private static function getUrlContents($url) {
$ch = curl_init($url);
curl_setopt_array($ch, array(
CURLOPT_HEADER => FALSE,
+ CURLOPT_CONNECTTIMEOUT => Tweeper::$maxConnectionTimeout,
// Follow http redirects to get the real URL.
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
// Follow http redirects to get the real URL.
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_HTTPHEADER => array('Accept-language: en'),
CURLOPT_USERAGENT => Tweeper::$userAgent,
));
CURLOPT_HTTPHEADER => array('Accept-language: en'),
CURLOPT_USERAGENT => Tweeper::$userAgent,
));
- $contents = curl_exec($ch);
- if (FALSE === $contents) {
- trigger_error(curl_error($ch), E_USER_WARNING);
- }
+ $contents = Tweeper::curlExec($ch);
curl_close($ch);
return $contents;
curl_close($ch);
return $contents;
curl_setopt_array($ch, array(
CURLOPT_HEADER => TRUE,
CURLOPT_NOBODY => TRUE,
curl_setopt_array($ch, array(
CURLOPT_HEADER => TRUE,
CURLOPT_NOBODY => TRUE,
+ CURLOPT_CONNECTTIMEOUT => Tweeper::$maxConnectionTimeout,
// Follow http redirects to get the real URL.
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
// Follow http redirects to get the real URL.
CURLOPT_FOLLOWLOCATION => TRUE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_USERAGENT => Tweeper::$userAgent,
));
CURLOPT_USERAGENT => Tweeper::$userAgent,
));
+ $ret = Tweeper::curlExec($ch);
- trigger_error(curl_error($ch), E_USER_WARNING);
curl_close($ch);
return FALSE;
}
curl_close($ch);
return FALSE;
}
$stylesheet_contents = Tweeper::getUrlContents($stylesheet);
if (FALSE === $stylesheet_contents) {
$stylesheet_contents = Tweeper::getUrlContents($stylesheet);
if (FALSE === $stylesheet_contents) {
+ trigger_error("Cannot open $stylesheet", E_USER_WARNING);
$html = Tweeper::getUrlContents($src_url);
if (FALSE === $html) {
$html = Tweeper::getUrlContents($src_url);
if (FALSE === $html) {
+ trigger_error("Failed to retrieve $src_url", E_USER_WARNING);