Mercurial > hg > ywww
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/twitter/EpiOAuth.php Thu Feb 16 22:29:02 2017 +0000 @@ -0,0 +1,403 @@ +<?php +class EpiOAuth +{ + public $version = '1.0'; + + protected $requestTokenUrl; + protected $accessTokenUrl; + protected $authenticateUrl; + protected $authorizeUrl; + protected $consumerKey; + protected $consumerSecret; + protected $token; + protected $tokenSecret; + protected $signatureMethod; + protected $debug = false; + protected $useSSL = false; + protected $headers = array(); + protected $userAgent = 'EpiOAuth (http://github.com/jmathai/twitter-async/tree/)'; + protected $connectionTimeout = 5; + protected $requestTimeout = 30; + + public function addHeader($header) + { + if(is_array($header) && !empty($header)) + $this->headers = array_merge($this->headers, $header); + elseif(!empty($header)) + $this->headers[] = $header; + } + + public function getAccessToken($params = null) + { + $resp = $this->httpRequest('POST', $this->getUrl($this->accessTokenUrl), $params); + return new EpiOAuthResponse($resp); + } + + public function getAuthenticateUrl($token = null, $params = null) + { + $token = $token ? $token : $this->getRequestToken($params); + if (is_object($token)) $token = $token->oauth_token; + $addlParams = empty($params) ? '' : '&'.http_build_query($params, '', '&'); + return $this->getUrl($this->authenticateUrl) . '?oauth_token=' . $token . $addlParams; + } + + public function getAuthorizeUrl($token = null, $params = null) + { + $token = $token ? $token : $this->getRequestToken($params); + if (is_object($token)) $token = $token->oauth_token; + return $this->getUrl($this->authorizeUrl) . '?oauth_token=' . $token; + } + + // DEPRECATED in favor of getAuthorizeUrl() + public function getAuthorizationUrl($token = null) + { + return $this->getAuthorizeUrl($token); + } + + public function getRequestToken($params = null) + { + $resp = $this->httpRequest('POST', $this->getUrl($this->requestTokenUrl), $params); + return new EpiOAuthResponse($resp); + } + + public function getUrl($url) + { + if($this->useSSL === true) + return preg_replace('/^http:/', 'https:', $url); + + return $url; + } + + public function httpRequest($method = null, $url = null, $params = null, $isMultipart = false) + { + if(empty($method) || empty($url)) + return false; + + if(empty($params['oauth_signature'])) + $params = $this->prepareParameters($method, $url, $params); + + switch($method) + { + case 'GET': + return $this->httpGet($url, $params); + break; + case 'POST': + return $this->httpPost($url, $params, $isMultipart); + break; + case 'DELETE': + return $this->httpDelete($url, $params); + break; + + } + } + + public function setDebug($bool=false) + { + $this->debug = (bool)$bool; + } + + public function setTimeout($requestTimeout = null, $connectionTimeout = null) + { + if($requestTimeout !== null) + $this->requestTimeout = floatval($requestTimeout); + if($connectionTimeout !== null) + $this->connectionTimeout = floatval($connectionTimeout); + } + + public function setToken($token = null, $secret = null) + { + $this->token = $token; + $this->tokenSecret = $secret; + } + + public function useSSL($use = false) + { + $this->useSSL = (bool)$use; + } + + protected function addDefaultHeaders($url, $oauthHeaders) + { + $_h = array('Expect:'); + $urlParts = parse_url($url); + $oauth = 'Authorization: OAuth realm="' . $urlParts['scheme'] . '://' . $urlParts['host'] . $urlParts['path'] . '",'; + foreach($oauthHeaders as $name => $value) + { + $oauth .= "{$name}=\"{$value}\","; + } + $_h[] = substr($oauth, 0, -1); + $_h[] = "User-Agent: {$this->userAgent}"; + $this->addHeader($_h); + } + + protected function buildHttpQueryRaw($params) + { + $retval = ''; + foreach((array)$params as $key => $value) + $retval .= "{$key}={$value}&"; + $retval = substr($retval, 0, -1); + return $retval; + } + + protected function curlInit($url) + { + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->requestTimeout); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->connectionTimeout); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + if(isset($_SERVER ['SERVER_ADDR']) && !empty($_SERVER['SERVER_ADDR']) && $_SERVER['SERVER_ADDR'] != '127.0.0.1') + curl_setopt($ch, CURLOPT_INTERFACE, $_SERVER ['SERVER_ADDR']); + + if($this->useSSL === true) + { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + } + return $ch; + } + + protected function emptyHeaders() + { + $this->headers = array(); + } + + protected function encode_rfc3986($string) + { + return str_replace('+', ' ', str_replace('%7E', '~', rawurlencode(($string)))); + } + + protected function generateNonce() + { + if(isset($this->nonce)) // for unit testing + return $this->nonce; + + return md5(uniqid(rand(), true)); + } + + // parameters should already have been passed through prepareParameters + // no need to double encode + protected function generateSignature($method = null, $url = null, $params = null) + { + if(empty($method) || empty($url)) + return false; + + // concatenating and encode + $concatenatedParams = $this->encode_rfc3986($this->buildHttpQueryRaw($params)); + + // normalize url + $normalizedUrl = $this->encode_rfc3986($this->normalizeUrl($url)); + $method = $this->encode_rfc3986($method); // don't need this but why not? + + $signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}"; + return $this->signString($signatureBaseString); + } + + protected function httpDelete($url, $params) { + $this->addDefaultHeaders($url, $params['oauth']); + $ch = $this->curlInit($url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params['request'])); + $resp = $this->curl->addCurl($ch); + $this->emptyHeaders(); + return $resp; + } + + protected function httpGet($url, $params = null) + { + if(count($params['request']) > 0) + { + $url .= '?'; + foreach($params['request'] as $k => $v) + { + $url .= "{$k}={$v}&"; + } + $url = substr($url, 0, -1); + } + $this->addDefaultHeaders($url, $params['oauth']); + $ch = $this->curlInit($url); + $resp = $this->curl->addCurl($ch); + $this->emptyHeaders(); + + return $resp; + } + + protected function httpPost($url, $params = null, $isMultipart) + { + $this->addDefaultHeaders($url, $params['oauth']); + $ch = $this->curlInit($url); + curl_setopt($ch, CURLOPT_POST, 1); + // php's curl extension automatically sets the content type + // based on whether the params are in string or array form + if($isMultipart) + curl_setopt($ch, CURLOPT_POSTFIELDS, $params['request']); + else + curl_setopt($ch, CURLOPT_POSTFIELDS, $this->buildHttpQueryRaw($params['request'])); + $resp = $this->curl->addCurl($ch); + $this->emptyHeaders(); + + return $resp; + } + + protected function normalizeUrl($url = null) + { + $urlParts = parse_url($url); + $scheme = strtolower($urlParts['scheme']); + $host = strtolower($urlParts['host']); + $port = isset($urlParts['port']) ? intval($urlParts['port']) : 0; + + $retval = strtolower($scheme) . '://' . strtolower($host); + + if(!empty($port) && (($scheme === 'http' && $port != 80) || ($scheme === 'https' && $port != 443))) + $retval .= ":{$port}"; + + $retval .= $urlParts['path']; + if(!empty($urlParts['query'])) + { + $retval .= "?{$urlParts['query']}"; + } + + return $retval; + } + + protected function isMultipart($params = null) + { + if($params) + { + foreach($params as $k => $v) + { + if(strncmp('@',$k,1) === 0) + return true; + } + } + return false; + } + + protected function prepareParameters($method = null, $url = null, $params = null) + { + if(empty($method) || empty($url)) + return false; + + $oauth['oauth_consumer_key'] = $this->consumerKey; + $oauth['oauth_token'] = $this->token; + $oauth['oauth_nonce'] = $this->generateNonce(); + $oauth['oauth_timestamp'] = !isset($this->timestamp) ? time() : $this->timestamp; // for unit test + $oauth['oauth_signature_method'] = $this->signatureMethod; + if(isset($params['oauth_verifier'])) + { + $oauth['oauth_verifier'] = $params['oauth_verifier']; + unset($params['oauth_verifier']); + } + $oauth['oauth_version'] = $this->version; + // encode all oauth values + foreach($oauth as $k => $v) + $oauth[$k] = $this->encode_rfc3986($v); + // encode all non '@' params + // keep sigParams for signature generation (exclude '@' params) + // rename '@key' to 'key' + $sigParams = array(); + $hasFile = false; + if(is_array($params)) + { + foreach($params as $k => $v) + { + if(strncmp('@',$k,1) !== 0) + { + $sigParams[$k] = $this->encode_rfc3986($v); + $params[$k] = $this->encode_rfc3986($v); + } + else + { + $params[substr($k, 1)] = $v; + unset($params[$k]); + $hasFile = true; + } + } + + if($hasFile === true) + $sigParams = array(); + } + + $sigParams = array_merge($oauth, (array)$sigParams); + + // sorting + ksort($sigParams); + + // signing + $oauth['oauth_signature'] = $this->encode_rfc3986($this->generateSignature($method, $url, $sigParams)); + return array('request' => $params, 'oauth' => $oauth); + } + + protected function signString($string = null) + { + $retval = false; + switch($this->signatureMethod) + { + case 'HMAC-SHA1': + $key = $this->encode_rfc3986($this->consumerSecret) . '&' . $this->encode_rfc3986($this->tokenSecret); + $retval = base64_encode(hash_hmac('sha1', $string, $key, true)); + break; + } + + return $retval; + } + + public function __construct($consumerKey, $consumerSecret, $signatureMethod='HMAC-SHA1') + { + $this->consumerKey = $consumerKey; + $this->consumerSecret = $consumerSecret; + $this->signatureMethod = $signatureMethod; + $this->curl = EpiCurl::getInstance(); + } +} + +class EpiOAuthResponse +{ + private $__resp; + protected $debug = false; + + public function __construct($resp) + { + $this->__resp = $resp; + } + + public function __get($name) + { + if($this->__resp->code != 200) + EpiOAuthException::raise($this->__resp, $this->debug); + + parse_str($this->__resp->data, $result); + foreach($result as $k => $v) + { + $this->$k = $v; + } + + return isset($result[$name]) ? $result[$name] : null; + } + + public function __toString() + { + return $this->__resp->data; + } +} + +class EpiOAuthException extends Exception +{ + public static function raise($response, $debug) + { + $message = $response->responseText; + + switch($response->code) + { + case 400: + throw new EpiOAuthBadRequestException($message, $response->code); + case 401: + throw new EpiOAuthUnauthorizedException($message, $response->code); + default: + throw new EpiOAuthException($message, $response->code); + } + } +} +class EpiOAuthBadRequestException extends EpiOAuthException{} +class EpiOAuthUnauthorizedException extends EpiOAuthException{} +