Created
September 13, 2012 23:32
-
-
Save ManInTheBox/3718590 to your computer and use it in GitHub Desktop.
Curl wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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