diff --git a/src/Oauth2/Client/Client.php b/src/Oauth2/Client/Client.php new file mode 100755 index 00000000..2b9a0edb --- /dev/null +++ b/src/Oauth2/Client/Client.php @@ -0,0 +1,35 @@ + + */ +class Client { + + /** + * Create a new provider. + * + * // Load the Twitter provider + * $provider = $this->oauth2->provider('twitter'); + * + * @param string provider name + * @param array provider options + * @return OAuth_Provider + */ + public static function provider($name, array $options = NULL) + { + $name = ucfirst(strtolower($name)); + + include_once 'Provider/'.$name.'.php'; + + return new $name($options); + } + +} \ No newline at end of file diff --git a/src/Oauth2/Client/Exception.php b/src/Oauth2/Client/Exception.php new file mode 100755 index 00000000..0641ba24 --- /dev/null +++ b/src/Oauth2/Client/Exception.php @@ -0,0 +1,85 @@ +. + * @author Update to draft v10 by Edison Wong . + */ +class ClientException extends \Exception { + + /** + * The result from the API server that represents the exception information. + */ + protected $result; + + /** + * Make a new API Exception with the given result. + * + * @param $result + * The result from the API server. + */ + public function __construct($result) + { + $this->result = $result; + + $code = isset($result['code']) ? $result['code'] : 0; + + if (isset($result['error'])) + { + // OAuth 2.0 Draft 10 style + $message = $result['error']; + } + elseif (isset($result['message'])) + { + // cURL style + $message = $result['message']; + } + else + { + $message = 'Unknown Error.'; + } + + parent::__construct($message, $code); + } + + /** + * Returns the associated type for the error. This will default to + * 'Exception' when a type is not available. + * + * @return + * The type for the error. + */ + public function getType() + { + if (isset($this->result['error'])) + { + $message = $this->result['error']; + if (is_string($message)) + { + // OAuth 2.0 Draft 10 style + return $message; + } + } + return 'Exception'; + } + + /** + * To make debugging easier. + * + * @returns + * The string representation of the error. + */ + public function __toString() + { + $str = $this->getType() . ': '; + if ($this->code != 0) + { + $str .= $this->code . ': '; + } + return $str . $this->message; + } + +} diff --git a/src/Oauth2/Client/Provider.php b/src/Oauth2/Client/Provider.php new file mode 100755 index 00000000..12669a29 --- /dev/null +++ b/src/Oauth2/Client/Provider.php @@ -0,0 +1,226 @@ +name) + { + // Attempt to guess the name from the class name + $this->name = strtolower(substr(get_class($this), strlen('OAuth2_Provider_'))); + } + + if (empty($options['id'])) + { + throw new Exception('Required option not provided: id'); + } + + $this->client_id = $options['id']; + + isset($options['callback']) and $this->callback = $options['callback']; + isset($options['secret']) and $this->client_secret = $options['secret']; + isset($options['scope']) and $this->scope = $options['scope']; + + $this->redirect_uri = site_url(get_instance()->uri->uri_string()); + } + + /** + * Return the value of any protected class variable. + * + * // Get the provider signature + * $signature = $provider->signature; + * + * @param string variable name + * @return mixed + */ + public function __get($key) + { + return $this->$key; + } + + /** + * Returns the authorization URL for the provider. + * + * $url = $provider->url_authorize(); + * + * @return string + */ + abstract public function url_authorize(); + + /** + * Returns the access token endpoint for the provider. + * + * $url = $provider->url_access_token(); + * + * @return string + */ + abstract public function url_access_token(); + + /* + * Get an authorization code from Facebook. Redirects to Facebook, which this redirects back to the app using the redirect address you've set. + */ + public function authorize($options = array()) + { + $state = md5(uniqid(rand(), TRUE)); + get_instance()->session->set_userdata('state', $state); + + $params = array( + 'client_id' => $this->client_id, + 'redirect_uri' => isset($options['redirect_uri']) ? $options['redirect_uri'] : $this->redirect_uri, + 'state' => $state, + 'scope' => is_array($this->scope) ? implode($this->scope_seperator, $this->scope) : $this->scope, + 'response_type' => 'code', + 'approval_prompt' => 'force' // - google force-recheck + ); + + redirect($this->url_authorize().'?'.http_build_query($params)); + } + + /* + * Get access to the API + * + * @param string The access code + * @return object Success or failure along with the response details + */ + public function access($code, $options = array()) + { + $params = array( + 'client_id' => $this->client_id, + 'client_secret' => $this->client_secret, + 'grant_type' => isset($options['grant_type']) ? $options['grant_type'] : 'authorization_code', + ); + + switch ($params['grant_type']) + { + case 'authorization_code': + $params['code'] = $code; + $params['redirect_uri'] = isset($options['redirect_uri']) ? $options['redirect_uri'] : $this->redirect_uri; + break; + + case 'refresh_token': + $params['refresh_token'] = $code; + break; + } + + $response = null; + $url = $this->url_access_token(); + + switch ($this->method) + { + case 'GET': + + // Need to switch to Request library, but need to test it on one that works + $url .= '?'.http_build_query($params); + $response = file_get_contents($url); + + parse_str($response, $return); + + break; + + case 'POST': + + /* $ci = get_instance(); + + $ci->load->spark('curl/1.2.1'); + + $ci->curl + ->create($url) + ->post($params, array('failonerror' => false)); + + $response = $ci->curl->execute(); + */ + + $opts = array( + 'http' => array( + 'method' => 'POST', + 'header' => 'Content-type: application/x-www-form-urlencoded', + 'content' => http_build_query($params), + ) + ); + + $_default_opts = stream_context_get_params(stream_context_get_default()); + $context = stream_context_create(array_merge_recursive($_default_opts['options'], $opts)); + $response = file_get_contents($url, false, $context); + + $return = json_decode($response, true); + + break; + + default: + throw new OutOfBoundsException("Method '{$this->method}' must be either GET or POST"); + } + + if ( ! empty($return['error'])) + { + throw new OAuth2_Exception($return); + } + + switch ($params['grant_type']) + { + case 'authorization_code': + return OAuth2_Token::factory('access', $return); + break; + + case 'refresh_token': + return OAuth2_Token::factory('refresh', $return); + break; + } + + } + +} diff --git a/src/Oauth2/Client/Provider/Blooie.php b/src/Oauth2/Client/Provider/Blooie.php new file mode 100755 index 00000000..7c80abbc --- /dev/null +++ b/src/Oauth2/Client/Provider/Blooie.php @@ -0,0 +1,70 @@ + $token->access_token, + )); + + $user = json_decode(file_get_contents($url)); + + // Create a response from the request + return array( + 'uid' => $user->id, + 'nickname' => $user->username, + 'name' => $user->name, + 'first_name' => $user->first_name, + 'last_name' => $user->last_name, + 'email' => isset($user->email) ? $user->email : null, + 'location' => isset($user->hometown->name) ? $user->hometown->name : null, + 'description' => isset($user->bio) ? $user->bio : null, + 'image' => 'https://graph.facebook.com/me/picture?type=normal&access_token='.$token->access_token, + 'urls' => array( + 'Facebook' => $user->link, + ), + ); + } +} diff --git a/src/Oauth2/Client/Provider/Facebook.php b/src/Oauth2/Client/Provider/Facebook.php new file mode 100755 index 00000000..39decb31 --- /dev/null +++ b/src/Oauth2/Client/Provider/Facebook.php @@ -0,0 +1,52 @@ + $token->access_token, + )); + + $user = json_decode(file_get_contents($url)); + + // Create a response from the request + return array( + 'uid' => $user->id, + 'nickname' => isset($user->username) ? $user->username : null, + 'name' => $user->name, + 'first_name' => $user->first_name, + 'last_name' => $user->last_name, + 'email' => isset($user->email) ? $user->email : null, + 'location' => isset($user->hometown->name) ? $user->hometown->name : null, + 'description' => isset($user->bio) ? $user->bio : null, + 'image' => 'https://graph.facebook.com/me/picture?type=normal&access_token='.$token->access_token, + 'urls' => array( + 'Facebook' => $user->link, + ), + ); + } +} diff --git a/src/Oauth2/Client/Provider/Foursquare.php b/src/Oauth2/Client/Provider/Foursquare.php new file mode 100755 index 00000000..275f055b --- /dev/null +++ b/src/Oauth2/Client/Provider/Foursquare.php @@ -0,0 +1,46 @@ + $token->access_token, + )); + + $response = json_decode(file_get_contents($url)); + + $user = $response->response->user; + + // Create a response from the request + return array( + 'uid' => $user->id, + //'nickname' => $user->login, + 'name' => sprintf('%s %s', $user->firstName, $user->lastName), + 'email' => $user->contact->email, + 'image' => $user->photo, + 'location' => $user->homeCity, + ); + } +} \ No newline at end of file diff --git a/src/Oauth2/Client/Provider/Github.php b/src/Oauth2/Client/Provider/Github.php new file mode 100755 index 00000000..cb406167 --- /dev/null +++ b/src/Oauth2/Client/Provider/Github.php @@ -0,0 +1,44 @@ + $token->access_token, + )); + + $user = json_decode(file_get_contents($url)); + + // Create a response from the request + return array( + 'uid' => $user->id, + 'nickname' => $user->login, + 'name' => $user->name, + 'email' => $user->email, + 'urls' => array( + 'GitHub' => 'http://github.com/'.$user->login, + 'Blog' => $user->blog, + ), + ); + } +} \ No newline at end of file diff --git a/src/Oauth2/Client/Provider/Google.php b/src/Oauth2/Client/Provider/Google.php new file mode 100755 index 00000000..b76d343b --- /dev/null +++ b/src/Oauth2/Client/Provider/Google.php @@ -0,0 +1,84 @@ + 'Expected Authorization Code from '.ucfirst($this->name).' is missing')); + } + + return parent::access($code, $options); + } + + public function get_user_info(OAuth2_Token_Access $token) + { + $url = 'https://www.googleapis.com/oauth2/v1/userinfo?alt=json&'.http_build_query(array( + 'access_token' => $token->access_token, + )); + + $user = json_decode(file_get_contents($url), true); + return array( + 'uid' => $user['id'], + 'nickname' => url_title($user['name'], '_', true), + 'name' => $user['name'], + 'first_name' => $user['given_name'], + 'last_name' => $user['family_name'], + 'email' => $user['email'], + 'location' => null, + 'image' => (isset($user['picture'])) ? $user['picture'] : null, + 'description' => null, + 'urls' => array(), + ); + } +} diff --git a/src/Oauth2/Client/Provider/Instagram.php b/src/Oauth2/Client/Provider/Instagram.php new file mode 100755 index 00000000..39c8bef1 --- /dev/null +++ b/src/Oauth2/Client/Provider/Instagram.php @@ -0,0 +1,48 @@ +user; + + return array( + 'uid' => $user->id, + 'nickname' => $user->username, + 'name' => $user->full_name, + 'image' => $user->profile_picture, + 'urls' => array( + 'website' => $user->website, + ), + ); + } +} \ No newline at end of file diff --git a/src/Oauth2/Client/Provider/Mailchimp.php b/src/Oauth2/Client/Provider/Mailchimp.php new file mode 100755 index 00000000..818bd40d --- /dev/null +++ b/src/Oauth2/Client/Provider/Mailchimp.php @@ -0,0 +1,36 @@ + $token->access_token, + ); + } +} diff --git a/src/Oauth2/Client/Provider/Mailru.php b/src/Oauth2/Client/Provider/Mailru.php new file mode 100755 index 00000000..25234a20 --- /dev/null +++ b/src/Oauth2/Client/Provider/Mailru.php @@ -0,0 +1,73 @@ + $value) { + $params .= "$key=$value"; + } + return md5($params . $secret_key); + } + + public function get_user_info(OAuth2_Token_Access $token) + { + $request_params = array( + 'app_id' => $this->client_id, + 'method' => 'users.getInfo', + 'uids' => $token->uid, + 'access_token' => $token->access_token, + 'secure' => 1 + ); + + $sig = $this->sign_server_server($request_params,$this->client_secret); + $url = 'http://www.appsmail.ru/platform/api?'.http_build_query($request_params).'&sig='.$sig; + + $user = json_decode(file_get_contents($url)); + + return array( + 'uid' => $user[0]->uid, + 'nickname' => $user[0]->nick, + 'name' => $user[0]->first_name.' '.$user[0]->last_name, + 'first_name' => $user[0]->first_name, + 'last_name' => $user[0]->last_name, + 'email' => isset($user[0]->email) ? $user[0]->email : null, + 'image' => isset($user[0]->pic_big) ? $user[0]->pic_big : null, + ); + } + + public function authorize($options = array()) + { + $state = md5(uniqid(rand(), TRUE)); + get_instance()->session->set_userdata('state', $state); + + $params = array( + 'client_id' => $this->client_id, + 'redirect_uri' => isset($options['redirect_uri']) ? $options['redirect_uri'] : $this->redirect_uri, + 'response_type' => 'code', + ); + + redirect($this->url_authorize().'?'.http_build_query($params)); + } +} diff --git a/src/Oauth2/Client/Provider/Paypal.php b/src/Oauth2/Client/Provider/Paypal.php new file mode 100755 index 00000000..72d065fe --- /dev/null +++ b/src/Oauth2/Client/Provider/Paypal.php @@ -0,0 +1,59 @@ + $token->access_token + )); + + $user = json_decode(file_get_contents($url)); + $user = $user->identity; + + return array( + 'uid' => $user['userId'], + 'nickname' => url_title($user['fullName'], '_', true), + 'name' => $user['fullName'], + 'first_name' => $user['firstName'], + 'last_name' => $user['lastName'], + 'email' => $user['emails'][0], + 'location' => $user->addresses[0], + 'image' => null, + 'description' => null, + 'urls' => array( + 'PayPal' => null + ) + ); + } + +} diff --git a/src/Oauth2/Client/Provider/Soundcloud.php b/src/Oauth2/Client/Provider/Soundcloud.php new file mode 100755 index 00000000..83d9afbc --- /dev/null +++ b/src/Oauth2/Client/Provider/Soundcloud.php @@ -0,0 +1,51 @@ + $token->access_token, + )); + + $user = json_decode(file_get_contents($url)); + + // Create a response from the request + return array( + 'uid' => $user->id, + 'nickname' => $user->username, + 'name' => $user->full_name, + 'location' => $user->country.' ,'.$user->country, + 'description' => $user->description, + 'image' => $user->avatar_url, + 'urls' => array( + 'MySpace' => $user->myspace_name, + 'Website' => $user->website, + ), + ); + } +} diff --git a/src/Oauth2/Client/Provider/Vkontakte.php b/src/Oauth2/Client/Provider/Vkontakte.php new file mode 100755 index 00000000..bdad78e4 --- /dev/null +++ b/src/Oauth2/Client/Provider/Vkontakte.php @@ -0,0 +1,54 @@ + $token->uid, + 'fields' => implode(",",$scope), + 'access_token' => $token->access_token, + )); + + $user = json_decode(file_get_contents($url))->response; + + if(sizeof($user)==0) + return null; + else + $user = $user[0]; + + return array( + 'uid' => $user->uid, + 'nickname' => isset($user->nickname) ? $user->nickname : null, + 'name' => isset($user->name) ? $user->name : null, + 'first_name' => isset($user->first_name) ? $user->first_name : null, + 'last_name' => isset($user->last_name) ? $user->last_name : null, + 'email' => null, + 'location' => null, + 'description' => null, + 'image' => isset($user->photo_big) ? $user->photo_big : null, + 'urls' => array(), + ); + } +} diff --git a/src/Oauth2/Client/Provider/Windowslive.php b/src/Oauth2/Client/Provider/Windowslive.php new file mode 100755 index 00000000..8d489c3d --- /dev/null +++ b/src/Oauth2/Client/Provider/Windowslive.php @@ -0,0 +1,60 @@ + $token->access_token, + )); + + // perform network request + $user = json_decode(file_get_contents($url)); + + // create a response from the request and return it + return array( + 'uid' => $user->id, + 'name' => $user->name, + 'nickname' => url_title($user->name, '_', true), +// 'location' => $user[''], # scope wl.postal_addresses is required + # but won't be implemented by default + 'locale' => $user->locale, + 'urls' => array('Windows Live' => $user->link), + ); + } +} diff --git a/src/Oauth2/Client/Provider/Yandex.php b/src/Oauth2/Client/Provider/Yandex.php new file mode 100755 index 00000000..7a8f4f80 --- /dev/null +++ b/src/Oauth2/Client/Provider/Yandex.php @@ -0,0 +1,115 @@ + array( + 'method' => 'GET', + 'header' => 'Authorization: OAuth '.$token->access_token + ) + ); + $_default_opts = stream_context_get_params(stream_context_get_default()); + + $opts = array_merge_recursive($_default_opts['options'], $opts); + $context = stream_context_create($opts); + $url = 'http://api-yaru.yandex.ru/me/?format=json'; + + $user = json_decode(file_get_contents($url,false,$context)); + + preg_match("/\d+$/",$user->id,$uid); + + return array( + 'uid' => $uid[0], + 'nickname' => isset($user->name) ? $user->name : null, + 'name' => isset($user->name) ? $user->name : null, + 'first_name' => isset($user->first_name) ? $user->first_name : null, + 'last_name' => isset($user->last_name) ? $user->last_name : null, + 'email' => isset($user->email) ? $user->email : null, + 'location' => isset($user->hometown->name) ? $user->hometown->name : null, + 'description' => isset($user->bio) ? $user->bio : null, + 'image' => $user->links->userpic, + ); + } + + public function access($code, $options = array()) + { + $params = array( + 'client_id' => $this->client_id, + 'client_secret' => $this->client_secret, + 'grant_type' => isset($options['grant_type']) ? $options['grant_type'] : 'authorization_code', + ); + + switch ($params['grant_type']) + { + case 'authorization_code': + $params['code'] = $code; + $params['redirect_uri'] = isset($options['redirect_uri']) ? $options['redirect_uri'] : $this->redirect_uri; + break; + + case 'refresh_token': + $params['refresh_token'] = $code; + break; + } + + $response = null; + $url = $this->url_access_token(); + + $curl = curl_init($url); + + $headers[] = 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8;'; + curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); + +// curl_setopt($curl, CURLOPT_USERAGENT, 'yamolib-php'); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30); + curl_setopt($curl, CURLOPT_TIMEOUT, 80); + curl_setopt($curl, CURLOPT_POST, true); + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($params)); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + // curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); + // curl_setopt($curl, CURLOPT_CAINFO, dirname(__FILE__) . '/../data/ca-certificate.crt'); + + $response = curl_exec($curl); + curl_close($curl); + + $return = json_decode($response, true); + + if ( ! empty($return['error'])) + { + throw new OAuth2_Exception($return); + } + + switch ($params['grant_type']) + { + case 'authorization_code': + return OAuth2_Token::factory('access', $return); + break; + + case 'refresh_token': + return OAuth2_Token::factory('refresh', $return); + break; + } + } + +} diff --git a/src/Oauth2/Client/Token.php b/src/Oauth2/Client/Token.php new file mode 100755 index 00000000..5ca7ecf9 --- /dev/null +++ b/src/Oauth2/Client/Token.php @@ -0,0 +1,64 @@ +secret; + * + * @param string variable name + * @return mixed + */ + public function __get($key) + { + return $this->$key; + } + + /** + * Return a boolean if the property is set + * + * // Get the token secret + * if ($token->secret) exit('YAY SECRET'); + * + * @param string variable name + * @return bool + */ + public function __isset($key) + { + return isset($this->$key); + } + +} // End Token diff --git a/src/Oauth2/Client/Token/Access.php b/src/Oauth2/Client/Token/Access.php new file mode 100755 index 00000000..6e12adfd --- /dev/null +++ b/src/Oauth2/Client/Token/Access.php @@ -0,0 +1,85 @@ +access_token = $options['access_token']; + + // Some providers (not many) give the uid here, so lets take it + isset($options['uid']) and $this->uid = $options['uid']; + + //Vkontakte uses user_id instead of uid + isset($options['user_id']) and $this->uid = $options['user_id']; + + //Mailru uses x_mailru_vid instead of uid + isset($options['x_mailru_vid']) and $this->uid = $options['x_mailru_vid']; + + // We need to know when the token expires, add num. seconds to current time + isset($options['expires_in']) and $this->expires = time() + ((int) $options['expires_in']); + + // Facebook is just being a spec ignoring jerk + isset($options['expires']) and $this->expires = time() + ((int) $options['expires']); + + // Grab a refresh token so we can update access tokens when they expires + isset($options['refresh_token']) and $this->refresh_token = $options['refresh_token']; + } + + /** + * Returns the token key. + * + * @return string + */ + public function __toString() + { + return (string) $this->access_token; + } + +} // End OAuth2_Token_Access \ No newline at end of file diff --git a/src/Oauth2/Client/Token/Authorize.php b/src/Oauth2/Client/Token/Authorize.php new file mode 100755 index 00000000..f220617f --- /dev/null +++ b/src/Oauth2/Client/Token/Authorize.php @@ -0,0 +1,55 @@ +code = $options['code']; + $this->redirect_uri = $options['redirect_uri']; + } + + /** + * Returns the token key. + * + * @return string + */ + public function __toString() + { + return (string) $this->code; + } + +} // End OAuth2_Token_Access \ No newline at end of file