Skip to content

Instantly share code, notes, and snippets.

@ManInTheBox
Created September 13, 2012 23:32
Show Gist options
  • Save ManInTheBox/3718590 to your computer and use it in GitHub Desktop.
Save ManInTheBox/3718590 to your computer and use it in GitHub Desktop.
Curl wrapper
<?php
/**
* Curl is class you will probably want to use
* in order to fetch remote content.
*
* It is faster than `file_get_contents()` so using it is preferred.
*
* @author Zarko Stankovic <stankovic.zarko@gmail.com>
*/
class Curl extends CComponent
{
/**
* @var string target url to visit
*/
public $url;
/**
* @var array cURL options
*/
public $options = array();
/**
* @var array default cURL options
*/
public $defaultOptions = array(
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16',
);
/**
* @var boolean process cURL request after object creation. Defaults to true.
*/
public $autoOpen = true;
/**
* @var boolean close cURL session when request is finished. Defaults to true.
*/
public $autoClose = true;
/**
* @var string cURL response body
*/
public $response;
/**
* @var string current url that is processed
*/
public $currentUrl;
/**
* @var integer maximum execution timeout (seconds)
*/
public $maxExecutionTime = 20;
/**
* @var integer cURL start time
*/
private $startTime = 0;
/**
* @var resource cURL handle
*/
private $_handle;
/**
* @var integer keeps track of cURL redirections. Used internally.
*/
private static $_loops = 0;
/**
* @var integer max redirections allowed. Used internally.
*/
private static $_maxLoops = 20;
/**
* The Constructor
*
* @param string $url url to process
* @param array $options cURL options (will be merged with default options).
*/
public function __construct($url, $options = array())
{
$this->url = $url;
$this->defaultOptions[CURLOPT_URL] = $url;
$this->defaultOptions[CURLOPT_TIMEOUT] = $this->maxExecutionTime;
$this->options = $this->defaultOptions + $options;
$this->init();
}
/**
* Initializes cURL session.
* If {@link $autoOpen} is set to `true` connection is automatically made,
* otherwise you need to fire {@link open()) by yourself.
*/
public function init()
{
$this->_handle = curl_init();
if ($this->autoOpen)
{
$this->response = $this->open();
}
}
/**
* Open a cURL sesion.
*
* @return string cURL response body
* @throws CException if fail to set cURL options or to start cURL session
*/
public function open()
{
$optionsSet = curl_setopt_array($this->_handle, $this->options);
if (!$optionsSet)
{
throw new CException('Failed to set cURL options: ' . print_r($this->options, true));
}
$this->startTime = time();
$response = $this->curl_redir_exec($this->_handle);
if (curl_errno($this->_handle))
{
throw new CException(curl_error($this->_handle));
}
else
{
if ($this->autoClose)
{
$this->close();
}
return $response;
}
}
/**
* Close a cURL session
*/
public function close()
{
curl_close($this->_handle);
}
/**
* Allows you to use `Curl` instance as a string. {@link $response} will be used.
* @return string returns cURL response body
*/
public function __toString()
{
return $this->response;
}
/**
* Credits:
* http://php.net/manual/en/function.curl-setopt.php#71313
* with little modifications by `Zarko Stankovic <stankovic.zarko@gmail.com>`
*
* @return string content fetched from remote host
*/
private function curl_redir_exec()
{
$remoteHost = curl_getinfo($this->_handle);
$remoteHost = $remoteHost['url'];
$message = "cURL got no response from $remoteHost.";
if (self::$_loops++ >= self::$_maxLoops)
{
$message .= " Reason: Maximum redirections (".self::$_loops.").";
throw new CException($message);
}
$data = curl_exec($this->_handle);
if (!$data)
{
$timeouted = (time() - $this->startTime) >= $this->maxExecutionTime;
if ($timeouted)
{
$message .= " Reason: Timeouted ({$this->maxExecutionTime} seconds).";
throw new CException($message);
}
}
$responseArray = explode("\r\n\r\n", $data, 2);
if (empty($responseArray) || empty($data))
{
$message .= " Reason: Couldn't parse response.";
throw new CException($message);
}
$headers = $responseArray[0];
$data = $responseArray[1];
$http_code = curl_getinfo($this->_handle, CURLINFO_HTTP_CODE);
if ($http_code == 301 || $http_code == 302)
{
$matches = array();
preg_match('/Location:(.*)/', $headers, $matches);
$url = @parse_url(trim(array_pop($matches)));
if (!$url)
{
// couldn't process the url to redirect to
self::$_loops = 0;
return $data;
}
$last_url = parse_url(curl_getinfo($this->_handle, CURLINFO_EFFECTIVE_URL));
if (!isset($url['scheme']))
{
$url['scheme'] = $last_url['scheme'];
}
if (!isset($url['host']))
{
$url['host'] = $last_url['host'];
}
if (!isset($url['path']))
{
$url['path'] = $last_url['path'];
}
$new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . (isset($url['query']) ? '?' . $url['query'] : '');
curl_setopt($this->_handle, CURLOPT_URL, $new_url);
// redirect to new url
return $this->curl_redir_exec($this->_handle);
}
else
{
$info = curl_getinfo($this->_handle);
$this->currentUrl = $info['url'];
self::$_loops = 0;
return $data;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment