Mercurial > hg > ywww
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 |
