4 public $version = '1.0';
6 protected $requestTokenUrl;
7 protected $accessTokenUrl;
8 protected $authenticateUrl;
9 protected $authorizeUrl;
10 protected $consumerKey;
11 protected $consumerSecret;
13 protected $tokenSecret;
14 protected $signatureMethod;
15 protected $useSSL = false;
16 protected $headers = array();
17 protected $userAgent = 'EpiOAuth (http://github.com/jmathai/twitter-async/tree/)';
18 protected $timeout = 30;
20 public function addHeader($header)
22 if(is_array($header) && !empty($header))
23 $this->headers
= array_merge($this->headers
, $header);
24 elseif(!empty($header))
25 $this->headers
[] = $header;
28 public function getAccessToken($params = null)
30 $resp = $this->httpRequest('GET', $this->getUrl($this->accessTokenUrl
), $params);
31 return new EpiOAuthResponse($resp);
34 public function getAuthenticateUrl($token = null, $params = null)
36 $token = $token ?
$token : $this->getRequestToken();
37 $addlParams = empty($params) ?
'' : '&'.http_build_query($params);
38 return $this->getUrl($this->authenticateUrl
) . '?oauth_token=' . $token->oauth_token
. $addlParams;
41 public function getAuthorizeUrl($token = null)
43 return $this->getAuthorizationUrl($token);
46 // DEPRECATED in favor of getAuthorizeUrl()
47 public function getAuthorizationUrl($token = null)
49 $token = $token ?
$token : $this->getRequestToken();
50 return $this->getUrl($this->authorizeUrl
) . '?oauth_token=' . $token->oauth_token
;
53 public function getRequestToken($params = null)
55 $resp = $this->httpRequest('GET', $this->getUrl($this->requestTokenUrl
), $params);
56 return new EpiOAuthResponse($resp);
59 public function getUrl($url)
61 if($this->useSSL
=== true)
62 return preg_replace('/^http:/', 'https:', $url);
67 public function httpRequest($method = null, $url = null, $params = null, $isMultipart = false)
69 if(empty($method) ||
empty($url))
72 if(empty($params['oauth_signature']))
73 $params = $this->prepareParameters($method, $url, $params);
78 return $this->httpGet($url, $params);
81 return $this->httpPost($url, $params, $isMultipart);
86 public function setTimeout($timeout)
88 $this->timeout
= floatval($timeout);
91 public function setToken($token = null, $secret = null)
93 $this->token
= $token;
94 $this->tokenSecret
= $secret;
97 public function useSSL($use = false)
99 $this->useSSL
= (bool)$use;
102 protected function addDefaultHeaders($url, $oauthHeaders)
104 $_h = array('Expect:');
105 $urlParts = parse_url($url);
106 $oauth = 'Authorization: OAuth realm="' . $urlParts['scheme'] . '://' . $urlParts['host'] . $urlParts['path'] . '",';
107 foreach($oauthHeaders as $name => $value)
109 $oauth .= "{$name}=\"{$value}\",";
111 $_h[] = substr($oauth, 0, -1);
112 $_h[] = "User-Agent: {$this->userAgent}";
113 $this->addHeader($_h);
116 protected function buildHttpQueryRaw($params)
119 foreach((array)$params as $key => $value)
120 $retval .= "{$key}={$value}&";
121 $retval = substr($retval, 0, -1);
125 protected function curlInit($url)
127 $ch = curl_init($url);
128 curl_setopt($ch, CURLOPT_RETURNTRANSFER
, true);
129 curl_setopt($ch, CURLOPT_HTTPHEADER
, $this->headers
);
130 curl_setopt($ch, CURLOPT_TIMEOUT
, $this->timeout
);
131 if($this->useSSL
=== true)
133 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER
, false);
134 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST
, 0);
139 protected function encode_rfc3986($string)
141 return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($string))));
144 protected function generateNonce()
146 if(isset($this->nonce
)) // for unit testing
149 return md5(uniqid(rand(), true));
152 // parameters should already have been passed through prepareParameters
153 // no need to double encode
154 protected function generateSignature($method = null, $url = null, $params = null)
156 if(empty($method) ||
empty($url))
159 // concatenating and encode
160 $concatenatedParams = $this->encode_rfc3986($this->buildHttpQueryRaw($params));
163 $normalizedUrl = $this->encode_rfc3986($this->normalizeUrl($url));
164 $method = $this->encode_rfc3986($method); // don't need this but why not?
166 $signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}";
167 return $this->signString($signatureBaseString);
170 protected function httpGet($url, $params = null)
172 if(count($params['request']) > 0)
175 foreach($params['request'] as $k => $v)
177 $url .= "{$k}={$v}&";
179 $url = substr($url, 0, -1);
181 $this->addDefaultHeaders($url, $params['oauth']);
182 $ch = $this->curlInit($url);
183 $resp = $this->curl
->addCurl($ch);
188 protected function httpPost($url, $params = null, $isMultipart)
190 $this->addDefaultHeaders($url, $params['oauth']);
191 $ch = $this->curlInit($url);
192 curl_setopt($ch, CURLOPT_POST
, 1);
193 // php's curl extension automatically sets the content type
194 // based on whether the params are in string or array form
196 curl_setopt($ch, CURLOPT_POSTFIELDS
, $params['request']);
198 curl_setopt($ch, CURLOPT_POSTFIELDS
, $this->buildHttpQueryRaw($params['request']));
199 $resp = $this->curl
->addCurl($ch);
203 protected function normalizeUrl($url = null)
205 $urlParts = parse_url($url);
206 $scheme = strtolower($urlParts['scheme']);
207 $host = strtolower($urlParts['host']);
208 $port = isset($urlParts['port']) ?
intval($urlParts['port']) : 0;
210 $retval = strtolower($scheme) . '://' . strtolower($host);
212 if(!empty($port) && (($scheme === 'http' && $port != 80) ||
($scheme === 'https' && $port != 443)))
213 $retval .= ":{$port}";
215 $retval .= $urlParts['path'];
216 if(!empty($urlParts['query']))
218 $retval .= "?{$urlParts['query']}";
224 protected function prepareParameters($method = null, $url = null, $params = null)
226 if(empty($method) ||
empty($url))
229 $oauth['oauth_consumer_key'] = $this->consumerKey
;
230 $oauth['oauth_token'] = $this->token
;
231 $oauth['oauth_nonce'] = $this->generateNonce();
232 $oauth['oauth_timestamp'] = !isset($this->timestamp
) ?
time() : $this->timestamp
; // for unit test
233 $oauth['oauth_signature_method'] = $this->signatureMethod
;
234 $oauth['oauth_version'] = $this->version
;
235 // encode all oauth values
236 foreach($oauth as $k => $v)
237 $oauth[$k] = $this->encode_rfc3986($v);
238 // encode all non '@' params
239 // keep sigParams for signature generation (exclude '@' params)
240 // rename '@key' to 'key'
241 $sigParams = array();
243 if(is_array($params))
245 foreach($params as $k => $v)
247 if(strncmp('@',$k,1) !== 0)
249 $sigParams[$k] = $this->encode_rfc3986($v);
250 $params[$k] = $this->encode_rfc3986($v);
254 $params[substr($k, 1)] = $v;
260 if($hasFile === true)
261 $sigParams = array();
264 $sigParams = array_merge($oauth, (array)$sigParams);
270 $oauth['oauth_signature'] = $this->encode_rfc3986($this->generateSignature($method, $url, $sigParams));
271 return array('request' => $params, 'oauth' => $oauth);
274 protected function signString($string = null)
277 switch($this->signatureMethod
)
280 $key = $this->encode_rfc3986($this->consumerSecret
) . '&' . $this->encode_rfc3986($this->tokenSecret
);
281 $retval = base64_encode(hash_hmac('sha1', $string, $key, true));
288 public function __construct($consumerKey, $consumerSecret, $signatureMethod='HMAC-SHA1')
290 $this->consumerKey
= $consumerKey;
291 $this->consumerSecret
= $consumerSecret;
292 $this->signatureMethod
= $signatureMethod;
293 $this->curl
= EpiCurl
::getInstance();
297 class EpiOAuthResponse
301 public function __construct($resp)
303 $this->__resp
= $resp;
306 public function __get($name)
308 if($this->__resp
->code
!= 200)
309 EpiOAuthException
::raise($this->__resp
->data
, $this->__resp
->code
);
311 parse_str($this->__resp
->data
, $result);
312 foreach($result as $k => $v)
317 return $result[$name];
321 class EpiOAuthException
extends Exception
323 public static function raise($message, $code)
328 throw new EpiOAuthBadRequestException($message, $code);
330 throw new EpiOAuthUnauthorizedException($message, $code);
332 throw new EpiOAuthException($message, $code);
338 class EpiOAuthBadRequestException
extends EpiOAuthException
{}
339 class EpiOAuthUnauthorizedException
extends EpiOAuthException
{}