comparison twitter/EpiOAuth.php @ 6:077b0a0a3e6d

remaining originals according to dependency walk
author Robert Boland <robert@markup.co.uk>
date Thu, 16 Feb 2017 22:29:02 +0000
parents
children
comparison
equal deleted inserted replaced
5:55445b456ad0 6:077b0a0a3e6d
1 <?php
2 class EpiOAuth
3 {
4 public $version = '1.0';
5
6 protected $requestTokenUrl;
7 protected $accessTokenUrl;
8 protected $authenticateUrl;
9 protected $authorizeUrl;
10 protected $consumerKey;
11 protected $consumerSecret;
12 protected $token;
13 protected $tokenSecret;
14 protected $signatureMethod;
15 protected $debug = false;
16 protected $useSSL = false;
17 protected $headers = array();
18 protected $userAgent = 'EpiOAuth (http://github.com/jmathai/twitter-async/tree/)';
19 protected $connectionTimeout = 5;
20 protected $requestTimeout = 30;
21
22 public function addHeader($header)
23 {
24 if(is_array($header) && !empty($header))
25 $this->headers = array_merge($this->headers, $header);
26 elseif(!empty($header))
27 $this->headers[] = $header;
28 }
29
30 public function getAccessToken($params = null)
31 {
32 $resp = $this->httpRequest('POST', $this->getUrl($this->accessTokenUrl), $params);
33 return new EpiOAuthResponse($resp);
34 }
35
36 public function getAuthenticateUrl($token = null, $params = null)
37 {
38 $token = $token ? $token : $this->getRequestToken($params);
39 if (is_object($token)) $token = $token->oauth_token;
40 $addlParams = empty($params) ? '' : '&'.http_build_query($params, '', '&');
41 return $this->getUrl($this->authenticateUrl) . '?oauth_token=' . $token . $addlParams;
42 }
43
44 public function getAuthorizeUrl($token = null, $params = null)
45 {
46 $token = $token ? $token : $this->getRequestToken($params);
47 if (is_object($token)) $token = $token->oauth_token;
48 return $this->getUrl($this->authorizeUrl) . '?oauth_token=' . $token;
49 }
50
51 // DEPRECATED in favor of getAuthorizeUrl()
52 public function getAuthorizationUrl($token = null)
53 {
54 return $this->getAuthorizeUrl($token);
55 }
56
57 public function getRequestToken($params = null)
58 {
59 $resp = $this->httpRequest('POST', $this->getUrl($this->requestTokenUrl), $params);
60 return new EpiOAuthResponse($resp);
61 }
62
63 public function getUrl($url)
64 {
65 if($this->useSSL === true)
66 return preg_replace('/^http:/', 'https:', $url);
67
68 return $url;
69 }
70
71 public function httpRequest($method = null, $url = null, $params = null, $isMultipart = false)
72 {
73 if(empty($method) || empty($url))
74 return false;
75
76 if(empty($params['oauth_signature']))
77 $params = $this->prepareParameters($method, $url, $params);
78
79 switch($method)
80 {
81 case 'GET':
82 return $this->httpGet($url, $params);
83 break;
84 case 'POST':
85 return $this->httpPost($url, $params, $isMultipart);
86 break;
87 case 'DELETE':
88 return $this->httpDelete($url, $params);
89 break;
90
91 }
92 }
93
94 public function setDebug($bool=false)
95 {
96 $this->debug = (bool)$bool;
97 }
98
99 public function setTimeout($requestTimeout = null, $connectionTimeout = null)
100 {
101 if($requestTimeout !== null)
102 $this->requestTimeout = floatval($requestTimeout);
103 if($connectionTimeout !== null)
104 $this->connectionTimeout = floatval($connectionTimeout);
105 }
106
107 public function setToken($token = null, $secret = null)
108 {
109 $this->token = $token;
110 $this->tokenSecret = $secret;
111 }
112
113 public function useSSL($use = false)
114 {
115 $this->useSSL = (bool)$use;
116 }
117
118 protected function addDefaultHeaders($url, $oauthHeaders)
119 {
120 $_h = array('Expect:');
121 $urlParts = parse_url($url);
122 $oauth = 'Authorization: OAuth realm="' . $urlParts['scheme'] . '://' . $urlParts['host'] . $urlParts['path'] . '",';
123 foreach($oauthHeaders as $name => $value)
124 {
125 $oauth .= "{$name}=\"{$value}\",";
126 }
127 $_h[] = substr($oauth, 0, -1);
128 $_h[] = "User-Agent: {$this->userAgent}";
129 $this->addHeader($_h);
130 }
131
132 protected function buildHttpQueryRaw($params)
133 {
134 $retval = '';
135 foreach((array)$params as $key => $value)
136 $retval .= "{$key}={$value}&";
137 $retval = substr($retval, 0, -1);
138 return $retval;
139 }
140
141 protected function curlInit($url)
142 {
143 $ch = curl_init($url);
144 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
145 curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
146 curl_setopt($ch, CURLOPT_TIMEOUT, $this->requestTimeout);
147 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectionTimeout);
148 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
149 if(isset($_SERVER ['SERVER_ADDR']) && !empty($_SERVER['SERVER_ADDR']) && $_SERVER['SERVER_ADDR'] != '127.0.0.1')
150 curl_setopt($ch, CURLOPT_INTERFACE, $_SERVER ['SERVER_ADDR']);
151
152 if($this->useSSL === true)
153 {
154 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
155 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
156 }
157 return $ch;
158 }
159
160 protected function emptyHeaders()
161 {
162 $this->headers = array();
163 }
164
165 protected function encode_rfc3986($string)
166 {
167 return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($string))));
168 }
169
170 protected function generateNonce()
171 {
172 if(isset($this->nonce)) // for unit testing
173 return $this->nonce;
174
175 return md5(uniqid(rand(), true));
176 }
177
178 // parameters should already have been passed through prepareParameters
179 // no need to double encode
180 protected function generateSignature($method = null, $url = null, $params = null)
181 {
182 if(empty($method) || empty($url))
183 return false;
184
185 // concatenating and encode
186 $concatenatedParams = $this->encode_rfc3986($this->buildHttpQueryRaw($params));
187
188 // normalize url
189 $normalizedUrl = $this->encode_rfc3986($this->normalizeUrl($url));
190 $method = $this->encode_rfc3986($method); // don't need this but why not?
191
192 $signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}";
193 return $this->signString($signatureBaseString);
194 }
195
196 protected function httpDelete($url, $params) {
197 $this->addDefaultHeaders($url, $params['oauth']);
198 $ch = $this->curlInit($url);
199 curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
200 curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params['request']));
201 $resp = $this->curl->addCurl($ch);
202 $this->emptyHeaders();
203 return $resp;
204 }
205
206 protected function httpGet($url, $params = null)
207 {
208 if(count($params['request']) > 0)
209 {
210 $url .= '?';
211 foreach($params['request'] as $k => $v)
212 {
213 $url .= "{$k}={$v}&";
214 }
215 $url = substr($url, 0, -1);
216 }
217 $this->addDefaultHeaders($url, $params['oauth']);
218 $ch = $this->curlInit($url);
219 $resp = $this->curl->addCurl($ch);
220 $this->emptyHeaders();
221
222 return $resp;
223 }
224
225 protected function httpPost($url, $params = null, $isMultipart)
226 {
227 $this->addDefaultHeaders($url, $params['oauth']);
228 $ch = $this->curlInit($url);
229 curl_setopt($ch, CURLOPT_POST, 1);
230 // php's curl extension automatically sets the content type
231 // based on whether the params are in string or array form
232 if($isMultipart)
233 curl_setopt($ch, CURLOPT_POSTFIELDS, $params['request']);
234 else
235 curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params['request']));
236 $resp = $this->curl->addCurl($ch);
237 $this->emptyHeaders();
238
239 return $resp;
240 }
241
242 protected function normalizeUrl($url = null)
243 {
244 $urlParts = parse_url($url);
245 $scheme = strtolower($urlParts['scheme']);
246 $host = strtolower($urlParts['host']);
247 $port = isset($urlParts['port']) ? intval($urlParts['port']) : 0;
248
249 $retval = strtolower($scheme) . '://' . strtolower($host);
250
251 if(!empty($port) && (($scheme === 'http' && $port != 80) || ($scheme === 'https' && $port != 443)))
252 $retval .= ":{$port}";
253
254 $retval .= $urlParts['path'];
255 if(!empty($urlParts['query']))
256 {
257 $retval .= "?{$urlParts['query']}";
258 }
259
260 return $retval;
261 }
262
263 protected function isMultipart($params = null)
264 {
265 if($params)
266 {
267 foreach($params as $k => $v)
268 {
269 if(strncmp('@',$k,1) === 0)
270 return true;
271 }
272 }
273 return false;
274 }
275
276 protected function prepareParameters($method = null, $url = null, $params = null)
277 {
278 if(empty($method) || empty($url))
279 return false;
280
281 $oauth['oauth_consumer_key'] = $this->consumerKey;
282 $oauth['oauth_token'] = $this->token;
283 $oauth['oauth_nonce'] = $this->generateNonce();
284 $oauth['oauth_timestamp'] = !isset($this->timestamp) ? time() : $this->timestamp; // for unit test
285 $oauth['oauth_signature_method'] = $this->signatureMethod;
286 if(isset($params['oauth_verifier']))
287 {
288 $oauth['oauth_verifier'] = $params['oauth_verifier'];
289 unset($params['oauth_verifier']);
290 }
291 $oauth['oauth_version'] = $this->version;
292 // encode all oauth values
293 foreach($oauth as $k => $v)
294 $oauth[$k] = $this->encode_rfc3986($v);
295 // encode all non '@' params
296 // keep sigParams for signature generation (exclude '@' params)
297 // rename '@key' to 'key'
298 $sigParams = array();
299 $hasFile = false;
300 if(is_array($params))
301 {
302 foreach($params as $k => $v)
303 {
304 if(strncmp('@',$k,1) !== 0)
305 {
306 $sigParams[$k] = $this->encode_rfc3986($v);
307 $params[$k] = $this->encode_rfc3986($v);
308 }
309 else
310 {
311 $params[substr($k, 1)] = $v;
312 unset($params[$k]);
313 $hasFile = true;
314 }
315 }
316
317 if($hasFile === true)
318 $sigParams = array();
319 }
320
321 $sigParams = array_merge($oauth, (array)$sigParams);
322
323 // sorting
324 ksort($sigParams);
325
326 // signing
327 $oauth['oauth_signature'] = $this->encode_rfc3986($this->generateSignature($method, $url, $sigParams));
328 return array('request' => $params, 'oauth' => $oauth);
329 }
330
331 protected function signString($string = null)
332 {
333 $retval = false;
334 switch($this->signatureMethod)
335 {
336 case 'HMAC-SHA1':
337 $key = $this->encode_rfc3986($this->consumerSecret) . '&' . $this->encode_rfc3986($this->tokenSecret);
338 $retval = base64_encode(hash_hmac('sha1', $string, $key, true));
339 break;
340 }
341
342 return $retval;
343 }
344
345 public function __construct($consumerKey, $consumerSecret, $signatureMethod='HMAC-SHA1')
346 {
347 $this->consumerKey = $consumerKey;
348 $this->consumerSecret = $consumerSecret;
349 $this->signatureMethod = $signatureMethod;
350 $this->curl = EpiCurl::getInstance();
351 }
352 }
353
354 class EpiOAuthResponse
355 {
356 private $__resp;
357 protected $debug = false;
358
359 public function __construct($resp)
360 {
361 $this->__resp = $resp;
362 }
363
364 public function __get($name)
365 {
366 if($this->__resp->code != 200)
367 EpiOAuthException::raise($this->__resp, $this->debug);
368
369 parse_str($this->__resp->data, $result);
370 foreach($result as $k => $v)
371 {
372 $this->$k = $v;
373 }
374
375 return isset($result[$name]) ? $result[$name] : null;
376 }
377
378 public function __toString()
379 {
380 return $this->__resp->data;
381 }
382 }
383
384 class EpiOAuthException extends Exception
385 {
386 public static function raise($response, $debug)
387 {
388 $message = $response->responseText;
389
390 switch($response->code)
391 {
392 case 400:
393 throw new EpiOAuthBadRequestException($message, $response->code);
394 case 401:
395 throw new EpiOAuthUnauthorizedException($message, $response->code);
396 default:
397 throw new EpiOAuthException($message, $response->code);
398 }
399 }
400 }
401 class EpiOAuthBadRequestException extends EpiOAuthException{}
402 class EpiOAuthUnauthorizedException extends EpiOAuthException{}
403