X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=pumpio%2Foauth%2Foauth_client.php;fp=pumpio%2Foauth%2Foauth_client.php;h=5047e0e9b41f10d3e09aefcc54dbc55d434feb34;hb=92ad7f294dcc62940aeea50c1a96335151b9d3bc;hp=0000000000000000000000000000000000000000;hpb=ed96ffa9208b8361766a1f16034ca2cf9e2393dc;p=friendica-addons.git diff --git a/pumpio/oauth/oauth_client.php b/pumpio/oauth/oauth_client.php new file mode 100644 index 00000000..5047e0e9 --- /dev/null +++ b/pumpio/oauth/oauth_client.php @@ -0,0 +1,2176 @@ + + + + net.manuellemos.oauth + + @(#) $Id: oauth_client.php,v 1.58 2013/04/11 09:33:16 mlemos Exp $ + Copyright © (C) Manuel Lemos 2012 + OAuth client + Manuel Lemos + mlemos-at-acm.org + + + en + This class serves two main purposes: + 1) Implement the OAuth protocol to retrieve a token from a server to + authorize the access to an API on behalf of the current + user. + 2) Perform calls to a Web services API using a token previously + obtained using this class or a token provided some other way by the + Web services provider. + Regardless of your purposes, you always need to start calling + the class Initialize function after + initializing setup variables. After you are done with the class, + always call the Finalize function at + the end. + This class supports either OAuth protocol versions 1.0, 1.0a and + 2.0. It abstracts the differences between these protocol versions, + so the class usage is the same independently of the OAuth + version of the server. + The class also provides built-in support to several popular OAuth + servers, so you do not have to manually configure all the details to + access those servers. Just set the + server variable to configure the class + to access one of the built-in supported servers. + If you need to access one type of server that is not yet directly + supported by the class, you need to configure it explicitly setting + the variables: oauth_version, + url_parameters, + authorization_header, + request_token_url, + dialog_url, + offline_dialog_url, + append_state_to_redirect_uri and + access_token_url. + Before proceeding to the actual OAuth authorization process, you + need to have registered your application with the OAuth server. The + registration provides you values to set the variables + client_id and + client_secret. + You also need to set the variables + redirect_uri and + scope before calling the + Process function to make the class + perform the necessary interactions with the OAuth + server. + The OAuth protocol involves multiple steps that include redirection + to the OAuth server. There it asks permission to the current user to + grant your application access to APIs on his/her behalf. When there + is a redirection, the class will set the + exit variable to + 1. Then your script should exit + immediately without outputting anything. + When the OAuth access token is successfully obtained, the following + variables are set by the class with the obtained values: + access_token, + access_token_secret, + access_token_expiry, + access_token_type. You may want to + store these values to use them later when calling the server + APIs. + If there was a problem during OAuth authorization process, check the + variable authorization_error to + determine the reason. + Once you get the access token, you can call the server APIs using + the CallAPI function. Check the + access_token_error variable to + determine if there was an error when trying to to call the + API. + If for some reason the user has revoked the access to your + application, you need to ask the user to authorize your application + again. First you may need to call the function + ResetAccessToken to reset the value of + the access token that may be cached in session variables. + + +{/metadocument} +*/ + +class oauth_client_class +{ +/* +{metadocument} + + error + STRING + + + Store the message that is returned when an error + occurs. + Check this variable to understand what happened when a call to + any of the class functions has failed. + This class uses cumulative error handling. This means that if one + class functions that may fail is called and this variable was + already set to an error message due to a failure in a previous call + to the same or other function, the function will also fail and does + not do anything. + This allows programs using this class to safely call several + functions that may fail and only check the failure condition after + the last function call. + Just set this variable to an empty string to clear the error + condition. + + +{/metadocument} +*/ + var $error = ''; + +/* +{metadocument} + + debug + BOOLEAN + 0 + + Control whether debug output is enabled + Set this variable to 1 if you + need to check what is going on during calls to the class. When + enabled, the debug output goes either to the variable + debug_output and the PHP error log. + + +{/metadocument} +*/ + var $debug = false; + +/* +{metadocument} + + debug_http + BOOLEAN + 0 + + Control whether the dialog with the remote Web server + should also be logged. + Set this variable to 1 if you + want to inspect the data exchange with the OAuth server. + + +{/metadocument} +*/ + var $debug_http = false; + +/* +{metadocument} + + exit + BOOLEAN + 0 + + Determine if the current script should be exited. + Check this variable after calling the + Process function and exit your script + immediately if the variable is set to + 1. + + +{/metadocument} +*/ + var $exit = false; + +/* +{metadocument} + + debug_output + STRING + + + Capture the debug output generated by the class + Inspect this variable if you need to see what happened during + the class function calls. + + +{/metadocument} +*/ + var $debug_output = ''; + +/* +{metadocument} + + debug_prefix + STRING + OAuth client: + + Mark the lines of the debug output to identify actions + performed by this class. + Change this variable if you prefer the debug output lines to + be prefixed with a different text. + + +{/metadocument} +*/ + var $debug_prefix = 'OAuth client: '; + +/* +{metadocument} + + server + STRING + + + Identify the type of OAuth server to access. + The class provides built-in support to several types of OAuth + servers. This means that the class can automatically initialize + several configuration variables just by setting this server + variable. + Currently it supports the following servers: + Bitbucket, + Box, + Dropbox, + Eventful, + Facebook, + Fitbit, + Flickr, + Foursquare, + github, + Google, + Instagram, + LinkedIn, + Microsoft, + Scoop.it, + StockTwits, + Tumblr, + Twitter, + XING and + Yahoo. Please contact the author if you + would like to ask to add built-in support for other types of OAuth + servers. + If you want to access other types of OAuth servers that are not + yet supported, set this variable to an empty string and configure + other variables with values specific to those servers. + + +{/metadocument} +*/ + var $server = ''; + +/* +{metadocument} + + request_token_url + STRING + + + URL of the OAuth server to request the initial token for + OAuth 1.0 and 1.0a servers. + Set this variable to the OAuth request token URL when you are + not accessing one of the built-in supported OAuth + servers. + For OAuth 1.0 and 1.0a servers, the request token URL can have + certain marks that will act as template placeholders which will be + replaced with given values before requesting the authorization + token. Currently it supports the following placeholder + marks: + {SCOPE} - scope of the requested permissions to the granted by the + OAuth server with the user permissions + + +{/metadocument} +*/ + var $request_token_url = ''; + +/* +{metadocument} + + dialog_url + STRING + + + URL of the OAuth server to redirect the browser so the user + can grant access to your application. + Set this variable to the OAuth request token URL when you are + not accessing one of the built-in supported OAuth servers. + For certain servers, the dialog URL can have certain marks that + will act as template placeholders which will be replaced with + values defined before redirecting the users browser. Currently it + supports the following placeholder marks: + {REDIRECT_URI} - URL to redirect when returning from the OAuth + server authorization page + {CLIENT_ID} - client application identifier registered at the + server + {SCOPE} - scope of the requested permissions to the granted by the + OAuth server with the user permissions + {STATE} - identifier of the OAuth session state + + +{/metadocument} +*/ + var $dialog_url = ''; + +/* +{metadocument} + + offline_dialog_url + STRING + + + URL of the OAuth server to redirect the browser so the user + can grant access to your application when offline access is + requested. + Set this variable to the OAuth request token URL when you are + not accessing one of the built-in supported OAuth servers and the + OAuth server supports offline access. + It should have the same format as the + dialog_url variable. + + +{/metadocument} +*/ + var $offline_dialog_url = ''; + +/* +{metadocument} + + append_state_to_redirect_uri + STRING + + + Pass the OAuth session state in a variable with a different + name to work around implementation bugs of certain OAuth + servers + Set this variable when you are not accessing one of the + built-in supported OAuth servers if the OAuth server has a bug + that makes it not pass back the OAuth state identifier in a + request variable named state. + + +{/metadocument} +*/ + var $append_state_to_redirect_uri = ''; + +/* +{metadocument} + + access_token_url + STRING + + + OAuth server URL that will return the access token + URL. + Set this variable to the OAuth access token URL when you are + not accessing one of the built-in supported OAuth servers. + + +{/metadocument} +*/ + var $access_token_url = ''; + + +/* +{metadocument} + + oauth_version + STRING + 2.0 + + Version of the protocol version supported by the OAuth + server. + Set this variable to the OAuth server protocol version when + you are not accessing one of the built-in supported OAuth + servers. + + +{/metadocument} +*/ + var $oauth_version = '2.0'; + +/* +{metadocument} + + url_parameters + BOOLEAN + 0 + + Determine if the API call parameters should be moved to the + call URL. + Set this variable to 1 if the + API you need to call requires that the call parameters always be + passed via the API URL. + + +{/metadocument} +*/ + var $url_parameters = false; + +/* +{metadocument} + + authorization_header + BOOLEAN + 1 + + Determine if the OAuth parameters should be passed via HTTP + Authorization request header. + Set this variable to 1 if the + OAuth server requires that the OAuth parameters be passed using + the HTTP Authorization instead of the request URI parameters. + + +{/metadocument} +*/ + var $authorization_header = true; + +/* +{metadocument} + + token_request_method + STRING + GET + + Define the HTTP method that should be used to request + tokens from the server. + Set this variable to POST if the + OAuth server does not support requesting tokens using the HTTP GET + method. + + +{/metadocument} +*/ + var $token_request_method = 'GET'; + +/* +{metadocument} + + signature_method + STRING + HMAC-SHA1 + + Define the method to generate the signature for API request + parameters values. + Currently it supports PLAINTEXT + and HMAC-SHA1. + + +{/metadocument} +*/ + var $signature_method = 'HMAC-SHA1'; + +/* +{metadocument} + + redirect_uri + STRING + + + URL of the current script page that is calling this + class + Set this variable to the current script page URL before + proceeding the the OAuth authorization process. + + +{/metadocument} +*/ + var $redirect_uri = ''; + +/* +{metadocument} + + client_id + STRING + + + Identifier of your application registered with the OAuth + server + Set this variable to the application identifier that is + provided by the OAuth server when you register the + application. + + +{/metadocument} +*/ + var $client_id = ''; + +/* +{metadocument} + + client_secret + STRING + + + Secret value assigned to your application when it is + registered with the OAuth server. + Set this variable to the application secret that is provided + by the OAuth server when you register the application. + + +{/metadocument} +*/ + var $client_secret = ''; + +/* +{metadocument} + + scope + STRING + + + Permissions that your application needs to call the OAuth + server APIs + Check the documentation of the APIs that your application + needs to call to set this variable with the identifiers of the + permissions that the user needs to grant to your application. + + +{/metadocument} +*/ + var $scope = ''; + +/* +{metadocument} + + offline + BOOLEAN + 0 + + Specify whether it will be necessary to call the API when + the user is not present and the server supports renewing expired + access tokens using refresh tokens. + Set this variable to 1 if the + server supports renewing expired tokens automatically when the + user is not present. + + +{/metadocument} +*/ + var $offline = false; + +/* +{metadocument} + + access_token + STRING + + + Access token obtained from the OAuth server + Check this variable to get the obtained access token upon + successful OAuth authorization. + + +{/metadocument} +*/ + var $access_token = ''; + +/* +{metadocument} + + access_token_secret + STRING + + + Access token secret obtained from the OAuth server + If the OAuth protocol version is 1.0 or 1.0a, check this + variable to get the obtained access token secret upon successful + OAuth authorization. + + +{/metadocument} +*/ + var $access_token_secret = ''; + +/* +{metadocument} + + access_token_expiry + STRING + + + Timestamp of the expiry of the access token obtained from + the OAuth server. + Check this variable to get the obtained access token expiry + time upon successful OAuth authorization. If this variable is + empty, that means no expiry time was set. + + +{/metadocument} +*/ + var $access_token_expiry = ''; + +/* +{metadocument} + + access_token_type + STRING + + + Type of access token obtained from the OAuth server. + Check this variable to get the obtained access token type + upon successful OAuth authorization. + + +{/metadocument} +*/ + var $access_token_type = ''; + +/* +{metadocument} + + refresh_token + STRING + + + Refresh token obtained from the OAuth server + Check this variable to get the obtained refresh token upon + successful OAuth authorization. + + +{/metadocument} +*/ + var $refresh_token = ''; + +/* +{metadocument} + + access_token_error + STRING + + + Error message returned when a call to the API fails. + Check this variable to determine if there was an error while + calling the Web services API when using the + CallAPI function. + + +{/metadocument} +*/ + var $access_token_error = ''; + +/* +{metadocument} + + authorization_error + STRING + + + Error message returned when it was not possible to obtain + an OAuth access token + Check this variable to determine if there was an error while + trying to obtain the OAuth access token. + + +{/metadocument} +*/ + var $authorization_error = ''; + +/* +{metadocument} + + response_status + INTEGER + 0 + + HTTP response status returned by the server when calling an + API + Check this variable after calling the + CallAPI function if the API calls and you + need to process the error depending the response status. + 200 means no error. + 0 means the server response was not + retrieved. + + +{/metadocument} +*/ + var $response_status = 0; + + var $oauth_user_agent = 'PHP-OAuth-API (http://www.phpclasses.org/oauth-api $Revision: 1.58 $)'; + var $session_started = false; + + Function SetError($error) + { + $this->error = $error; + if($this->debug) + $this->OutputDebug('Error: '.$error); + return(false); + } + + Function SetPHPError($error, &$php_error_message) + { + if(IsSet($php_error_message) + && strlen($php_error_message)) + $error.=": ".$php_error_message; + return($this->SetError($error)); + } + + Function OutputDebug($message) + { + if($this->debug) + { + $message = $this->debug_prefix.$message; + $this->debug_output .= $message."\n";; + error_log($message); + } + return(true); + } + + Function GetRequestTokenURL(&$request_token_url) + { + $request_token_url = $this->request_token_url; + return(true); + } + + Function GetDialogURL(&$url, $redirect_uri = '', $state = '') + { + $url = (($this->offline && strlen($this->offline_dialog_url)) ? $this->offline_dialog_url : $this->dialog_url); + if(strlen($url) === 0) + return $this->SetError('the dialog URL '.($this->offline ? 'for offline access ' : '').'is not defined for this server'); + $url = str_replace( + '{REDIRECT_URI}', UrlEncode($redirect_uri), str_replace( + '{STATE}', UrlEncode($state), str_replace( + '{CLIENT_ID}', UrlEncode($this->client_id), str_replace( + '{SCOPE}', UrlEncode($this->scope), + $url)))); + return(true); + } + + Function GetAccessTokenURL(&$access_token_url) + { + $access_token_url = $this->access_token_url; + return(true); + } + + Function GetStoredState(&$state) + { + if(!$this->session_started) + { + if(!function_exists('session_start')) + return $this->SetError('Session variables are not accessible in this PHP environment'); + } + if(IsSet($_SESSION['OAUTH_STATE'])) + $state = $_SESSION['OAUTH_STATE']; + else + $state = $_SESSION['OAUTH_STATE'] = time().'-'.substr(md5(rand().time()), 0, 6); + return(true); + } + + Function GetRequestState(&$state) + { + $check = (strlen($this->append_state_to_redirect_uri) ? $this->append_state_to_redirect_uri : 'state'); + $state = (IsSet($_GET[$check]) ? $_GET[$check] : null); + return(true); + } + + Function GetRequestCode(&$code) + { + $code = (IsSet($_GET['code']) ? $_GET['code'] : null); + return(true); + } + + Function GetRequestError(&$error) + { + $error = (IsSet($_GET['error']) ? $_GET['error'] : null); + return(true); + } + + Function GetRequestDenied(&$denied) + { + $denied = (IsSet($_GET['denied']) ? $_GET['denied'] : null); + return(true); + } + + Function GetRequestToken(&$token, &$verifier) + { + $token = (IsSet($_GET['oauth_token']) ? $_GET['oauth_token'] : null); + $verifier = (IsSet($_GET['oauth_verifier']) ? $_GET['oauth_verifier'] : null); + return(true); + } + + Function GetRedirectURI(&$redirect_uri) + { + if(strlen($this->redirect_uri)) + $redirect_uri = $this->redirect_uri; + else + $redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; + return true; + } + +/* +{metadocument} + + StoreAccessToken + BOOLEAN + + Store the values of the access token when it is succefully + retrieved from the OAuth server. + This function is meant to be only be called from inside the + class. By default it stores access tokens in a session variable + named OAUTH_ACCESS_TOKEN. + Actual implementations should create a sub-class and override this + function to make the access token values be stored in other types + of containers, like for instance databases. + This function should return + 1 if the access token was stored + successfully. + + + access_token + HASH + + Associative array with properties of the access token. + The array may have set the following + properties: + value: string value of the access + token + authorized: boolean value that + determines if the access token was obtained + successfully + expiry: (optional) timestamp in ISO + format relative to UTC time zone of the access token expiry + time + type: (optional) type of OAuth token + that may determine how it should be used when sending API call + requests. + refresh: (optional) token that some + servers may set to allowing refreshing access tokens when they + expire. + + + +{/metadocument} +*/ + Function StoreAccessToken($access_token) + { + if(!$this->session_started) + { + if(!function_exists('session_start')) + return $this->SetError('Session variables are not accessible in this PHP environment'); + } + $_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url] = $access_token; + return true; + } +/* +{metadocument} + + +{/metadocument} +*/ + +/* +{metadocument} + + GetAccessToken + BOOLEAN + + Retrieve the OAuth access token if it was already + previously stored by the + StoreAccessToken function. + This function is meant to be only be called from inside the + class. By default it retrieves access tokens stored in a session + variable named + OAUTH_ACCESS_TOKEN. + Actual implementations should create a sub-class and override this + function to retrieve the access token values from other types of + containers, like for instance databases. + This function should return + 1 if the access token was retrieved + successfully. + + + access_token + STRING + + + Return the properties of the access token in an + associative array. If the access token was not yet stored, it + returns an empty array. Otherwise, the properties it may return + are the same that may be passed to the + StoreAccessToken. + + + +{/metadocument} +*/ + Function GetAccessToken(&$access_token) + { + if(!$this->session_started) + { + if(!function_exists('session_start')) + return $this->SetError('Session variables are not accessible in this PHP environment'); + if(!session_start()) + return($this->SetPHPError('it was not possible to start the PHP session', $php_error_message)); + $this->session_started = true; + } + if(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url])) + $access_token = $_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]; + else + $access_token = array(); + return true; + } +/* +{metadocument} + + +{/metadocument} +*/ + +/* +{metadocument} + + ResetAccessToken + BOOLEAN + + Reset the access token to a state back when the user has + not yet authorized the access to the OAuth server API. + Call this function if for some reason the token to access + the API was revoked and you need to ask the user to authorize + the access again. + By default the class stores and retrieves access tokens in a + session variable named + OAUTH_ACCESS_TOKEN. + This function must be called when the user is accessing your site + pages, so it can reset the information stored in session variables + that cache the state of a previously retrieved access + token. + Actual implementations should create a sub-class and override this + function to reset the access token state when it is stored in + other types of containers, like for instance databases. + This function should return + 1 if the access token was resetted + successfully. + + +{/metadocument} +*/ + Function ResetAccessToken() + { + if($this->debug) + $this->OutputDebug('Resetting the access token status for OAuth server located at '.$this->access_token_url); + if(!$this->session_started) + { + if(!function_exists('session_start')) + return $this->SetError('Session variables are not accessible in this PHP environment'); + if(!session_start()) + return($this->SetPHPError('it was not possible to start the PHP session', $php_error_message)); + } + $this->session_started = true; + if(IsSet($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url])) + Unset($_SESSION['OAUTH_ACCESS_TOKEN'][$this->access_token_url]); + return true; + } +/* +{metadocument} + + +{/metadocument} +*/ + + Function Encode($value) + { + return(is_array($value) ? $this->EncodeArray($value) : str_replace('%7E', '~', str_replace('+',' ', RawURLEncode($value)))); + } + + Function EncodeArray($array) + { + foreach($array as $key => $value) + $array[$key] = $this->Encode($value); + return $array; + } + + Function HMAC($function, $data, $key) + { + switch($function) + { + case 'sha1': + $pack = 'H40'; + break; + default: + if($this->debug) + $this->OutputDebug($function.' is not a supported an HMAC hash type'); + return(''); + } + if(strlen($key) > 64) + $key = pack($pack, $function($key)); + if(strlen($key) < 64) + $key = str_pad($key, 64, "\0"); + return(pack($pack, $function((str_repeat("\x5c", 64) ^ $key).pack($pack, $function((str_repeat("\x36", 64) ^ $key).$data))))); + } + + Function SendAPIRequest($url, $method, $parameters, $oauth, $options, &$response) + { + $this->response_status = 0; + $http = new http_class; + $http->debug = ($this->debug && $this->debug_http); + $http->log_debug = true; + $http->sasl_authenticate = 0; + $http->user_agent = $this->oauth_user_agent; + $http->redirection_limit = (IsSet($options['FollowRedirection']) ? intval($options['FollowRedirection']) : 0); + $http->follow_redirect = ($http->redirection_limit != 0); + if($this->debug) + $this->OutputDebug('Accessing the '.$options['Resource'].' at '.$url); + $post_files = array(); + $method = strtoupper($method); + $authorization = ''; + $type = (IsSet($options['RequestContentType']) ? strtolower(trim(strtok($options['RequestContentType'], ';'))) : 'application/x-www-form-urlencoded'); + if(IsSet($oauth)) + { + $values = array( + 'oauth_consumer_key'=>$this->client_id, + 'oauth_nonce'=>md5(uniqid(rand(), true)), + 'oauth_signature_method'=>$this->signature_method, + 'oauth_timestamp'=>time(), + 'oauth_version'=>'1.0', + ); + $files = (IsSet($options['Files']) ? $options['Files'] : array()); + if(count($files)) + { + foreach($files as $name => $value) + { + if(!IsSet($parameters[$name])) + return($this->SetError('it was specified an file parameters named '.$name)); + $file = array(); + switch(IsSet($value['Type']) ? $value['Type'] : 'FileName') + { + case 'FileName': + $file['FileName'] = $parameters[$name]; + break; + case 'Data': + $file['Data'] = $parameters[$name]; + break; + default: + return($this->SetError($value['Type'].' is not a valid type for file '.$name)); + } + $file['ContentType'] = (IsSet($value['Content-Type']) ? $value['Content-Type'] : 'automatic/name'); + $post_files[$name] = $file; + } + UnSet($parameters[$name]); + if($method !== 'POST') + { + $this->OutputDebug('For uploading files the method should be POST not '.$method); + $method = 'POST'; + } + if($type !== 'multipart/form-data') + { + if(IsSet($options['RequestContentType'])) + return($this->SetError('the request content type for uploading files should be multipart/form-data')); + $type = 'multipart/form-data'; + } + $value_parameters = array(); + } + else + { + if($this->url_parameters + && $type === 'application/x-www-form-urlencoded' + && count($parameters)) + { + $first = (strpos($url, '?') === false); + foreach($parameters as $parameter => $value) + { + $url .= ($first ? '?' : '&').UrlEncode($parameter).'='.UrlEncode($value); + $first = false; + } + $parameters = array(); + } + $value_parameters = ($type !== 'application/x-www-form-urlencoded' ? array() : $parameters); + } + $values = array_merge($values, $oauth, $value_parameters); + $key = $this->Encode($this->client_secret).'&'.$this->Encode($this->access_token_secret); + switch($this->signature_method) + { + case 'PLAINTEXT': + $values['oauth_signature'] = $key; + break; + case 'HMAC-SHA1': + $uri = strtok($url, '?'); + $sign = $method.'&'.$this->Encode($uri).'&'; + $first = true; + $sign_values = $values; + $u = parse_url($url); + if(IsSet($u['query'])) + { + parse_str($u['query'], $q); + foreach($q as $parameter => $value) + $sign_values[$parameter] = $value; + } + KSort($sign_values); + foreach($sign_values as $parameter => $value) + { + $sign .= $this->Encode(($first ? '' : '&').$parameter.'='.$this->Encode($value)); + $first = false; + } + $values['oauth_signature'] = base64_encode($this->HMAC('sha1', $sign, $key)); + break; + default: + return $this->SetError($this->signature_method.' signature method is not yet supported'); + } + if($this->authorization_header) + { + $authorization = 'OAuth'; + $first = true; + foreach($values as $parameter => $value) + { + $authorization .= ($first ? ' ' : ',').$parameter.'="'.$this->Encode($value).'"'; + $first = false; + } + } + else + { + if($method === 'GET' + || (IsSet($options['PostValuesInURI']) + && $options['PostValuesInURI'])) + { + $first = (strcspn($url, '?') == strlen($url)); + foreach($values as $parameter => $value) + { + $url .= ($first ? '?' : '&').$parameter.'='.$this->Encode($value); + $first = false; + } + $post_values = array(); + } + else + $post_values = $values; + } + } + if(strlen($error = $http->GetRequestArguments($url, $arguments))) + return($this->SetError('it was not possible to open the '.$options['Resource'].' URL: '.$error)); + if(strlen($error = $http->Open($arguments))) + return($this->SetError('it was not possible to open the '.$options['Resource'].' URL: '.$error)); + if(count($post_files)) + $arguments['PostFiles'] = $post_files; + $arguments['RequestMethod'] = $method; + switch($type) + { + case 'application/x-www-form-urlencoded': + case 'multipart/form-data': + if(IsSet($options['RequestBody'])) + return($this->SetError('the request body is defined automatically from the parameters')); + $arguments['PostValues'] = $parameters; + break; + case 'application/json': + $arguments['Headers']['Content-Type'] = $options['RequestContentType']; + if(!IsSet($options['RequestBody'])) + { + $arguments['Body'] = json_encode($parameters); + break; + } + default: + if(!IsSet($options['RequestBody'])) + return($this->SetError('it was not specified the body value of the of the API call request')); + $arguments['Headers']['Content-Type'] = $options['RequestContentType']; + $arguments['Body'] = $options['RequestBody']; + break; + } + $arguments['Headers']['Accept'] = (IsSet($options['Accept']) ? $options['Accept'] : '*/*'); + if(strlen($authorization)) + $arguments['Headers']['Authorization'] = $authorization; + if(strlen($error = $http->SendRequest($arguments)) + || strlen($error = $http->ReadReplyHeaders($headers))) + { + $http->Close(); + return($this->SetError('it was not possible to retrieve the '.$options['Resource'].': '.$error)); + } + $error = $http->ReadWholeReplyBody($data); + $http->Close(); + if(strlen($error)) + { + return($this->SetError('it was not possible to access the '.$options['Resource'].': '.$error)); + } + $this->response_status = intval($http->response_status); + $content_type = (IsSet($options['ResponseContentType']) ? $options['ResponseContentType'] : (IsSet($headers['content-type']) ? strtolower(trim(strtok($headers['content-type'], ';'))) : 'unspecified')); + switch($content_type) + { + case 'text/javascript': + case 'application/json': + if(!function_exists('json_decode')) + return($this->SetError('the JSON extension is not available in this PHP setup')); + $object = json_decode($data); + switch(GetType($object)) + { + case 'object': + if(!IsSet($options['ConvertObjects']) + || !$options['ConvertObjects']) + $response = $object; + else + { + $response = array(); + foreach($object as $property => $value) + $response[$property] = $value; + } + break; + case 'array': + $response = $object; + break; + default: + if(!IsSet($object)) + return($this->SetError('it was not returned a valid JSON definition of the '.$options['Resource'].' values')); + $response = $object; + break; + } + break; + case 'application/x-www-form-urlencoded': + case 'text/plain': + case 'text/html': + parse_str($data, $response); + break; + default: + $response = $data; + break; + } + if($this->response_status >= 200 + && $this->response_status < 300) + $this->access_token_error = ''; + else + { + $this->access_token_error = 'it was not possible to access the '.$options['Resource'].': it was returned an unexpected response status '.$http->response_status.' Response: '.$data; + if($this->debug) + $this->OutputDebug('Could not retrieve the OAuth access. Error: '.$this->access_token_error); + if(IsSet($options['FailOnAccessError']) + && $options['FailOnAccessError']) + { + $this->error = $this->access_token_error; + return false; + } + } + return true; + } + + Function ProcessToken($code, $refresh) + { + if($refresh) + { + $values = array( + 'client_id'=>$this->client_id, + 'client_secret'=>$this->client_secret, + 'refresh_token'=>$this->refresh_token, + 'grant_type'=>'refresh_token' + ); + } + else + { + if(!$this->GetRedirectURI($redirect_uri)) + return false; + $values = array( + 'code'=>$code, + 'client_id'=>$this->client_id, + 'client_secret'=>$this->client_secret, + 'redirect_uri'=>$redirect_uri, + 'grant_type'=>'authorization_code' + ); + } + if(!$this->GetAccessTokenURL($url)) + return false; + if(!$this->SendAPIRequest($url, 'POST', $values, null, array('Resource'=>'OAuth '.($refresh ? 'refresh' : 'access').' token', 'ConvertObjects'=>true), $response)) + return false; + if(strlen($this->access_token_error)) + { + $this->authorization_error = $this->access_token_error; + return true; + } + if(!IsSet($response['access_token'])) + { + if(IsSet($response['error'])) + { + $this->authorization_error = 'it was not possible to retrieve the access token: it was returned the error: '.$response['error']; + return true; + } + return($this->SetError('OAuth server did not return the access token')); + } + $access_token = array( + 'value'=>$this->access_token = $response['access_token'], + 'authorized'=>true + ); + if($this->debug) + $this->OutputDebug('Access token: '.$this->access_token); + if(IsSet($response['expires']) + || IsSet($response['expires_in'])) + { + $expires = (IsSet($response['expires']) ? $response['expires'] : $response['expires_in']); + if(strval($expires) !== strval(intval($expires)) + || $expires <= 0) + return($this->SetError('OAuth server did not return a supported type of access token expiry time')); + $this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', time() + $expires); + if($this->debug) + $this->OutputDebug('Access token expiry: '.$this->access_token_expiry.' UTC'); + $access_token['expiry'] = $this->access_token_expiry; + } + else + $this->access_token_expiry = ''; + if(IsSet($response['token_type'])) + { + $this->access_token_type = $response['token_type']; + if($this->debug) + $this->OutputDebug('Access token type: '.$this->access_token_type); + $access_token['type'] = $this->access_token_type; + } + else + $this->access_token_type = ''; + if($refresh) + $response['refresh_token'] = $this->refresh_token; + elseif(IsSet($response['refresh_token'])) + { + $this->refresh_token = $response['refresh_token']; + if($this->debug) + $this->OutputDebug('Refresh token: '.$this->refresh_token); + $access_token['refresh'] = $this->refresh_token; + } + else + $this->refresh_token = ''; + if(!$this->StoreAccessToken($access_token)) + return false; + return true; + } + + Function RetrieveToken(&$valid) + { + $valid = false; + if(!$this->GetAccessToken($access_token)) + return false; + if(IsSet($access_token['value'])) + { + $this->access_token_expiry = ''; + if(IsSet($access_token['expiry']) + && strcmp($this->access_token_expiry = $access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) < 0) + { + $this->access_token = ''; + if($this->debug) + $this->OutputDebug('The OAuth access token expired in '.$this->access_token_expiry); + } + else + { + $this->access_token = $access_token['value']; + if(IsSet($access_token['type'])) + $this->access_token_type = $access_token['type']; + else + $this->access_token_type = ''; + if($this->debug) + $this->OutputDebug('The OAuth access token '.$this->access_token.' is valid'); + if(strlen($this->access_token_type) + && $this->debug) + $this->OutputDebug('The OAuth access token is of type '.$this->access_token_type); + if(IsSet($access_token['refresh'])) + $this->refresh_token = $access_token['refresh']; + else + $this->refresh_token = ''; + $valid = true; + } + } + return true; + } +/* +{metadocument} + + CallAPI + BOOLEAN + + Send a HTTP request to the Web services API using a + previously obtained authorization token via OAuth. + This function can be used to call an API after having + previously obtained an access token through the OAuth protocol + using the Process function, or by + directly setting the variables + access_token, as well as + access_token_secret in case of using + OAuth 1.0 or 1.0a services. + This function returns 1 if + the call was done successfully. + + + url + STRING + + URL of the API where the HTTP request will be sent. + + + + method + STRING + + HTTP method that will be used to send the request. It can + be GET, + POST, + DELETE, PUT, + etc.. + + + + parameters + HASH + + Associative array with the names and values of the API + call request parameters. + + + + options + HASH + + Associative array with additional options to configure + the request. Currently it supports the following + options: + 2Legged: boolean option that + determines if the API request should be 2 legged. The default + value is 0. + Accept: content type value of the + Accept HTTP header to be sent in the API call HTTP request. + Some APIs require that a certain value be sent to specify + which version of the API is being called. The default value is + */*. + ConvertObjects: boolean option that + determines if objects should be converted into arrays when the + response is returned in JSON format. The default value is + 0. + FailOnAccessError: boolean option + that determines if this functions should fail when the server + response status is not between 200 and 299. The default value + is 0. + Files: associative array with + details of the parameters that must be passed as file uploads. + The array indexes must have the same name of the parameters + to be sent as files. The respective array entry values must + also be associative arrays with the parameters for each file. + Currently it supports the following parameters: + - Type - defines how the parameter value should be + treated. It can be 'FileName' if the parameter value is + is the name of a local file to be uploaded. It may also be + 'Data' if the parameter value is the actual data of + the file to be uploaded. + - Default: 'FileName' + - ContentType - MIME value of the content type of the + file. It can be 'automatic/name' if the content type + should be determine from the file name extension. + - Default: 'automatic/name' + PostValuesInURI: boolean option to + determine that a POST request should pass the request values + in the URI. The default value is + 0. + FollowRedirection: limit number of + times that HTTP response redirects will be followed. If it is + set to 0, redirection responses + fail in error. The default value is + 0. + RequestBody: request body data of a + custom type. The RequestContentType + option must be specified, so the + RequestBody option is considered. + RequestContentType: content type that + should be used to send the request values. It can be either + application/x-www-form-urlencoded + for sending values like from Web forms, or + application/json for sending the + values encoded in JSON format. Other types are accepted if the + RequestBody option is specified. + The default value is + application/x-www-form-urlencoded. + RequestBody: request body data of a + custom type. The RequestContentType + option must be specified, so the + RequestBody option is considered. + Resource: string with a label that + will be used in the error messages and debug log entries to + identify what operation the request is performing. The default + value is API call. + ResponseContentType: content type + that should be considered when decoding the API request + response. This overrides the Content-Type header + returned by the server. If the content type is + application/x-www-form-urlencoded + the function will parse the data returning an array of + key-value pairs. If the content type is + application/json the response will + be decode as a JSON-encoded data type. Other content type + values will make the function return the original response + value as it was returned from the server. The default value + for this option is to use what the server returned in the + Content-Type header. + + + + response + STRING + + + Return the value of the API response. If the value is + JSON encoded, this function will decode it and return the value + converted to respective types. If the value is form encoded, + this function will decode the response and return it as an + array. Otherwise, the class will return the value as a + string. + + + +{/metadocument} +*/ + Function CallAPI($url, $method, $parameters, $options, &$response) + { + if(!IsSet($options['Resource'])) + $options['Resource'] = 'API call'; + if(!IsSet($options['ConvertObjects'])) + $options['ConvertObjects'] = false; + if(strlen($this->access_token) === 0) + { + if(!$this->RetrieveToken($valid)) + return false; + if(!$valid) + return $this->SetError('the access token is not set to a valid value'); + } + switch(intval($this->oauth_version)) + { + case 1: + $oauth = array( + 'oauth_token'=>((IsSet($options['2Legged']) && $options['2Legged']) ? '' : $this->access_token) + ); + break; + + case 2: + if(strlen($this->access_token_expiry) + && strcmp($this->access_token_expiry, gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0) + { + if(strlen($this->refresh_token) === 0) + return($this->SetError('the access token expired and no refresh token is available')); + if($this->debug) + { + $this->OutputDebug('The access token expired on '.$this->access_token_expiry); + $this->OutputDebug('Refreshing the access token'); + } + if(!$this->ProcessToken(null, true)) + return false; + } + $oauth = null; + $url .= (strcspn($url, '?') < strlen($url) ? '&' : '?').'access_token='.UrlEncode($this->access_token); + break; + + default: + return($this->SetError($this->oauth_version.' is not a supported version of the OAuth protocol')); + } + return($this->SendAPIRequest($url, $method, $parameters, $oauth, $options, $response)); + } +/* +{metadocument} + + +{/metadocument} +*/ + +/* +{metadocument} + + Initialize + BOOLEAN + + Initialize the class variables and internal state. It must + be called before calling other class functions. + Set the server variable before + calling this function to let it initialize the class variables to + work with the specified server type. Alternatively, you can set + other class variables manually to make it work with servers that + are not yet built-in supported. + This function returns 1 if + it was able to successfully initialize the class for the specified + server type. + + +{/metadocument} +*/ + Function Initialize() + { + if(strlen($this->server) === 0) + return true; + $this->request_token_url = ''; + $this->append_state_to_redirect_uri = ''; + $this->authorization_header = true; + $this->url_parameters = false; + $this->token_request_method = 'GET'; + $this->signature_method = 'HMAC-SHA1'; + switch($this->server) + { + case 'Bitbucket': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://bitbucket.org/!api/1.0/oauth/request_token'; + $this->dialog_url = 'https://bitbucket.org/!api/1.0/oauth/authenticate'; + $this->access_token_url = 'https://bitbucket.org/!api/1.0/oauth/access_token'; + $this->url_parameters = true; + break; + + case 'Box': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://www.box.com/api/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}'; + $this->offline_dialog_url = 'https://www.box.com/api/oauth2/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&state={STATE}&access_type=offline&approval_prompt=force'; + $this->access_token_url = 'https://www.box.com/api/oauth2/token'; + break; + + case 'Dropbox': + $this->oauth_version = '1.0'; + $this->request_token_url = 'https://api.dropbox.com/1/oauth/request_token'; + $this->dialog_url = 'https://www.dropbox.com/1/oauth/authorize'; + $this->access_token_url = 'https://api.dropbox.com/1/oauth/access_token'; + $this->authorization_header = false; + break; + + case 'Eventful': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'http://eventful.com/oauth/request_token'; + $this->dialog_url = 'http://eventful.com/oauth/authorize'; + $this->access_token_url = 'http://eventful.com/oauth/access_token'; + $this->authorization_header = false; + $this->url_parameters = true; + $this->token_request_method = 'POST'; + break; + + case 'Evernote': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://sandbox.evernote.com/oauth'; + $this->dialog_url = 'https://sandbox.evernote.com/OAuth.action'; + $this->access_token_url = 'https://sandbox.evernote.com/oauth'; + $this->url_parameters = true; + $this->authorization_header = false; + break; + + case 'Facebook': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://www.facebook.com/dialog/oauth?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}'; + $this->access_token_url = 'https://graph.facebook.com/oauth/access_token'; + break; + + case 'Fitbit': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'http://api.fitbit.com/oauth/request_token'; + $this->dialog_url = 'http://api.fitbit.com/oauth/authorize'; + $this->access_token_url = 'http://api.fitbit.com/oauth/access_token'; + break; + + case 'Flickr': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'http://www.flickr.com/services/oauth/request_token'; + $this->dialog_url = 'http://www.flickr.com/services/oauth/authorize?perms={SCOPE}'; + $this->access_token_url = 'http://www.flickr.com/services/oauth/access_token'; + $this->authorization_header = false; + break; + + case 'Foursquare': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://foursquare.com/oauth2/authorize?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}'; + $this->access_token_url = 'https://foursquare.com/oauth2/access_token'; + break; + + case 'github': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://github.com/login/oauth/authorize?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}'; + $this->access_token_url = 'https://github.com/login/oauth/access_token'; + break; + + case 'Google': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}'; + $this->offline_dialog_url = 'https://accounts.google.com/o/oauth2/auth?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}&access_type=offline&approval_prompt=force'; + $this->access_token_url = 'https://accounts.google.com/o/oauth2/token'; + break; + + case 'Instagram': + $this->oauth_version = '2.0'; + $this->dialog_url ='https://api.instagram.com/oauth/authorize/?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&response_type=code&state={STATE}'; + $this->access_token_url = 'https://api.instagram.com/oauth/access_token'; + break; + + case 'LinkedIn': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken?scope={SCOPE}'; + $this->dialog_url = 'https://api.linkedin.com/uas/oauth/authenticate'; + $this->access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken'; + $this->url_parameters = true; + break; + + case 'Microsoft': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://login.live.com/oauth20_authorize.srf?client_id={CLIENT_ID}&scope={SCOPE}&response_type=code&redirect_uri={REDIRECT_URI}&state={STATE}'; + $this->access_token_url = 'https://login.live.com/oauth20_token.srf'; + break; + + case 'RightSignature': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://rightsignature.com/oauth/request_token'; + $this->dialog_url = 'https://rightsignature.com/oauth/authorize'; + $this->access_token_url = 'https://rightsignature.com/oauth/access_token'; + $this->authorization_header = false; + break; + + case 'Scoop.it': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://www.scoop.it/oauth/request'; + $this->dialog_url = 'https://www.scoop.it/oauth/authorize'; + $this->access_token_url = 'https://www.scoop.it/oauth/access'; + $this->authorization_header = false; + break; + + case 'StockTwits': + $this->oauth_version = '2.0'; + $this->dialog_url = 'https://api.stocktwits.com/api/2/oauth/authorize?client_id={CLIENT_ID}&response_type=code&redirect_uri={REDIRECT_URI}&scope={SCOPE}&state={STATE}'; + $this->access_token_url = 'https://api.stocktwits.com/api/2/oauth/token'; + break; + + case 'Tumblr': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'http://www.tumblr.com/oauth/request_token'; + $this->dialog_url = 'http://www.tumblr.com/oauth/authorize'; + $this->access_token_url = 'http://www.tumblr.com/oauth/access_token'; + break; + + case 'Twitter': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://api.twitter.com/oauth/request_token'; + $this->dialog_url = 'https://api.twitter.com/oauth/authenticate'; + $this->access_token_url = 'https://api.twitter.com/oauth/access_token'; + $this->url_parameters = true; + break; + + case 'XING': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://api.xing.com/v1/request_token'; + $this->dialog_url = 'https://api.xing.com/v1/authorize'; + $this->access_token_url = 'https://api.xing.com/v1/access_token'; + $this->authorization_header = false; + break; + + case 'Yahoo': + $this->oauth_version = '1.0a'; + $this->request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token'; + $this->dialog_url = 'https://api.login.yahoo.com/oauth/v2/request_auth'; + $this->access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token'; + $this->authorization_header = false; + break; + + default: + return($this->SetError($this->server.' is not yet a supported type of OAuth server. Please contact the author Manuel Lemos to request adding built-in support to this type of OAuth server.')); + } + return(true); + } +/* +{metadocument} + + +{/metadocument} +*/ + +/* +{metadocument} + + Process + BOOLEAN + + Process the OAuth protocol interaction with the OAuth + server. + Call this function when you need to retrieve the OAuth access + token. Check the access_token to + determine if the access token was obtained successfully. + This function returns 1 if + the OAuth protocol was processed without errors. + + +{/metadocument} +*/ + Function Process() + { + switch(intval($this->oauth_version)) + { + case 1: + $one_a = ($this->oauth_version === '1.0a'); + if($this->debug) + $this->OutputDebug('Checking the OAuth token authorization state'); + if(!$this->GetAccessToken($access_token)) + return false; + if(IsSet($access_token['authorized']) + && IsSet($access_token['value'])) + { + $expired = (IsSet($access_token['expiry']) && strcmp($access_token['expiry'], gmstrftime('%Y-%m-%d %H:%M:%S')) <= 0); + if(!$access_token['authorized'] + || $expired) + { + if($this->debug) + { + if($expired) + $this->OutputDebug('The OAuth token expired on '.$access_token['expiry'].'UTC'); + else + $this->OutputDebug('The OAuth token is not yet authorized'); + $this->OutputDebug('Checking the OAuth token and verifier'); + } + if(!$this->GetRequestToken($token, $verifier)) + return false; + if(!IsSet($token) + || ($one_a + && !IsSet($verifier))) + { + if(!$this->GetRequestDenied($denied)) + return false; + if(IsSet($denied) + && $denied === $access_token['value']) + { + if($this->debug) + $this->OutputDebug('The authorization request was denied'); + $this->authorization_error = 'the request was denied'; + return true; + } + else + { + if($this->debug) + $this->OutputDebug('Reset the OAuth token state because token and verifier are not both set'); + $access_token = array(); + } + } + elseif($token !== $access_token['value']) + { + if($this->debug) + $this->OutputDebug('Reset the OAuth token state because token does not match what as previously retrieved'); + $access_token = array(); + } + else + { + if(!$this->GetAccessTokenURL($url)) + return false; + $oauth = array( + 'oauth_token'=>$token, + ); + if($one_a) + $oauth['oauth_verifier'] = $verifier; + $this->access_token_secret = $access_token['secret']; + $options = array('Resource'=>'OAuth access token'); + $method = strtoupper($this->token_request_method); + switch($method) + { + case 'GET': + break; + case 'POST': + $options['PostValuesInURI'] = true; + break; + default: + $this->error = $method.' is not a supported method to request tokens'; + break; + } + if(!$this->SendAPIRequest($url, $method, array(), $oauth, $options, $response)) + return false; + if(strlen($this->access_token_error)) + { + $this->authorization_error = $this->access_token_error; + return true; + } + if(!IsSet($response['oauth_token']) + || !IsSet($response['oauth_token_secret'])) + { + $this->authorization_error= 'it was not returned the access token and secret'; + return true; + } + $access_token = array( + 'value'=>$response['oauth_token'], + 'secret'=>$response['oauth_token_secret'], + 'authorized'=>true + ); + if(IsSet($response['oauth_expires_in'])) + { + $expires = $response['oauth_expires_in']; + if(strval($expires) !== strval(intval($expires)) + || $expires <= 0) + return($this->SetError('OAuth server did not return a supported type of access token expiry time')); + $this->access_token_expiry = gmstrftime('%Y-%m-%d %H:%M:%S', time() + $expires); + if($this->debug) + $this->OutputDebug('Access token expiry: '.$this->access_token_expiry.' UTC'); + $access_token['expiry'] = $this->access_token_expiry; + } + else + $this->access_token_expiry = ''; + + if(!$this->StoreAccessToken($access_token)) + return false; + if($this->debug) + $this->OutputDebug('The OAuth token was authorized'); + } + } + elseif($this->debug) + $this->OutputDebug('The OAuth token was already authorized'); + if(IsSet($access_token['authorized']) + && $access_token['authorized']) + { + $this->access_token = $access_token['value']; + $this->access_token_secret = $access_token['secret']; + return true; + } + } + else + { + if($this->debug) + $this->OutputDebug('The OAuth access token is not set'); + $access_token = array(); + } + if(!IsSet($access_token['authorized'])) + { + if($this->debug) + $this->OutputDebug('Requesting the unauthorized OAuth token'); + if(!$this->GetRequestTokenURL($url)) + return false; + $url = str_replace('{SCOPE}', UrlEncode($this->scope), $url); + if(!$this->GetRedirectURI($redirect_uri)) + return false; + $oauth = array( + 'oauth_callback'=>$redirect_uri, + ); + $options = array('Resource'=>'OAuth request token'); + $method = strtoupper($this->token_request_method); + switch($method) + { + case 'GET': + break; + case 'POST': + $options['PostValuesInURI'] = true; + break; + default: + $this->error = $method.' is not a supported method to request tokens'; + break; + } + if(!$this->SendAPIRequest($url, $method, array(), $oauth, $options, $response)) + return false; + if(strlen($this->access_token_error)) + { + $this->authorization_error = $this->access_token_error; + return true; + } + if(!IsSet($response['oauth_token']) + || !IsSet($response['oauth_token_secret'])) + { + $this->authorization_error = 'it was not returned the requested token'; + return true; + } + $access_token = array( + 'value'=>$response['oauth_token'], + 'secret'=>$response['oauth_token_secret'], + 'authorized'=>false + ); + if(!$this->StoreAccessToken($access_token)) + return false; + } + if(!$this->GetDialogURL($url)) + return false; + $url .= (strpos($url, '?') === false ? '?' : '&').'oauth_token='.$access_token['value']; + if(!$one_a) + { + if(!$this->GetRedirectURI($redirect_uri)) + return false; + $url .= '&oauth_callback='.UrlEncode($redirect_uri); + } + if($this->debug) + $this->OutputDebug('Redirecting to OAuth authorize page '.$url); + Header('HTTP/1.0 302 OAuth Redirection'); + Header('Location: '.$url); + $this->exit = true; + return true; + + case 2: + if($this->debug) + $this->OutputDebug('Checking if OAuth access token was already retrieved from '.$this->access_token_url); + if(!$this->RetrieveToken($valid)) + return false; + if($valid) + return true; + if($this->debug) + $this->OutputDebug('Checking the authentication state in URI '.$_SERVER['REQUEST_URI']); + if(!$this->GetStoredState($stored_state)) + return false; + if(strlen($stored_state) == 0) + return($this->SetError('it was not set the OAuth state')); + if(!$this->GetRequestState($state)) + return false; + if($state === $stored_state) + { + if($this->debug) + $this->OutputDebug('Checking the authentication code'); + if(!$this->GetRequestCode($code)) + return false; + if(strlen($code) == 0) + { + if(!$this->GetRequestError($this->authorization_error)) + return false; + if(IsSet($this->authorization_error)) + { + if($this->debug) + $this->OutputDebug('Authorization failed with error code '.$this->authorization_error); + switch($this->authorization_error) + { + case 'invalid_request': + case 'unauthorized_client': + case 'access_denied': + case 'unsupported_response_type': + case 'invalid_scope': + case 'server_error': + case 'temporarily_unavailable': + case 'user_denied': + return true; + default: + return($this->SetError('it was returned an unknown OAuth error code')); + } + } + return($this->SetError('it was not returned the OAuth dialog code')); + } + if(!$this->ProcessToken($code, false)) + return false; + } + else + { + if(!$this->GetRedirectURI($redirect_uri)) + return false; + if(strlen($this->append_state_to_redirect_uri)) + $redirect_uri .= (strpos($redirect_uri, '?') === false ? '?' : '&').$this->append_state_to_redirect_uri.'='.$stored_state; + if(!$this->GetDialogURL($url, $redirect_uri, $stored_state)) + return false; + if(strlen($url) == 0) + return($this->SetError('it was not set the OAuth dialog URL')); + if($this->debug) + $this->OutputDebug('Redirecting to OAuth Dialog '.$url); + Header('HTTP/1.0 302 OAuth Redirection'); + Header('Location: '.$url); + $this->exit = true; + } + break; + + default: + return($this->SetError($this->oauth_version.' is not a supported version of the OAuth protocol')); + } + return(true); + } +/* +{metadocument} + + +{/metadocument} +*/ + +/* +{metadocument} + + Finalize + BOOLEAN + + Cleanup any resources that may have been used during the + OAuth protocol processing or execution of API calls. + Always call this function as the last step after calling the + functions Process or + CallAPI. + This function returns 1 if + the function cleaned up any resources successfully. + + + success + BOOLEAN + + Pass the last success state returned by the class or any + external code processing the class function results. + + + +{/metadocument} +*/ + Function Finalize($success) + { + return($success); + } +/* +{metadocument} + + +{/metadocument} +*/ + +/* +{metadocument} + + Output + VOID + + Display the results of the OAuth protocol processing. + Only call this function if you are debugging the OAuth + authorization process and you need to view what was its + results. + + +{/metadocument} +*/ + Function Output() + { + if(strlen($this->authorization_error) + || strlen($this->access_token_error) + || strlen($this->access_token)) + { +?> + + + +OAuth client result + + +

OAuth client result

+authorization_error)) + { +?> +

It was not possible to authorize the application.debug) + { +?> +
Authorization error: authorization_error); + } +?>

+access_token_error)) + { +?> +

It was not possible to use the application access token. +debug) + { +?> +
Error: access_token_error); + } +?>

+access_token)) + { +?> +

The application authorization was obtained successfully. +debug) + { +?> +
Access token: access_token); + if(IsSet($this->access_token_secret)) + { +?> +
Access token secret: access_token_secret); + } + } +?>

+access_token_expiry)) + { +?> +

Access token expiry: access_token_expiry; ?> UTC

+ + + + +
+{/metadocument} +*/ + +}; + +/* + +{metadocument} +
+{/metadocument} + +*/ + +?> \ No newline at end of file