From cbf697338601ded0c917be1e2a34b883c1ee2a1c Mon Sep 17 00:00:00 2001 From: Cameron Date: Mon, 18 Sep 2017 16:27:02 -0700 Subject: [PATCH] HybridAuth upgraded to v2.9.6 --- e107_core/controllers/system/xup.php | 4 +- e107_handlers/hybridauth/Hybrid/Auth.php | 5 +- .../hybridauth/Hybrid/Provider_Adapter.php | 28 +- .../hybridauth/Hybrid/Provider_Model.php | 9 +- .../Hybrid/Provider_Model_OAuth2.php | 2 +- .../hybridauth/Hybrid/Providers/Facebook.php | 803 +++++++------- .../Hybrid/Providers/Foursquare.php | 2 +- .../hybridauth/Hybrid/Providers/Google.php | 41 +- .../hybridauth/Hybrid/Providers/LinkedIn.php | 396 +++---- .../hybridauth/Hybrid/Providers/Live.php | 8 +- .../hybridauth/Hybrid/Providers/Twitter.php | 3 +- .../hybridauth/Hybrid/Providers/Yahoo.php | 439 ++++---- .../hybridauth/Hybrid/User_Profile.php | 11 + .../Hybrid/thirdparty/OAuth/OAuth2Client.php | 20 +- e107_handlers/hybridauth/index.php | 1 + e107_handlers/hybridauth/vendor/autoload.php | 7 + .../vendor/composer/ClassLoader.php | 413 ++++++++ .../hybridauth/vendor/composer/LICENSE | 21 + .../vendor/composer/autoload_classmap.php | 48 + .../vendor/composer/autoload_files.php | 10 + .../vendor/composer/autoload_namespaces.php | 10 + .../vendor/composer/autoload_psr4.php | 10 + .../vendor/composer/autoload_real.php | 59 ++ .../hybridauth/vendor/composer/installed.json | 62 ++ .../vendor/facebook/graph-sdk/LICENSE | 19 + .../vendor/facebook/graph-sdk/composer.json | 42 + .../vendor/facebook/graph-sdk/phpcs.xml.dist | 7 + .../Facebook/Authentication/AccessToken.php | 160 +++ .../Authentication/AccessTokenMetadata.php | 390 +++++++ .../Facebook/Authentication/OAuth2Client.php | 292 ++++++ .../FacebookAuthenticationException.php | 33 + .../FacebookAuthorizationException.php | 33 + .../Exceptions/FacebookClientException.php | 33 + .../Exceptions/FacebookOtherException.php | 33 + .../Exceptions/FacebookResponseException.php | 214 ++++ .../FacebookResumableUploadException.php | 33 + .../Exceptions/FacebookSDKException.php | 33 + .../Exceptions/FacebookServerException.php | 33 + .../Exceptions/FacebookThrottleException.php | 33 + .../graph-sdk/src/Facebook/Facebook.php | 635 +++++++++++ .../graph-sdk/src/Facebook/FacebookApp.php | 110 ++ .../src/Facebook/FacebookBatchRequest.php | 322 ++++++ .../src/Facebook/FacebookBatchResponse.php | 174 +++ .../graph-sdk/src/Facebook/FacebookClient.php | 250 +++++ .../src/Facebook/FacebookRequest.php | 534 ++++++++++ .../src/Facebook/FacebookResponse.php | 410 ++++++++ .../src/Facebook/FileUpload/FacebookFile.php | 169 +++ .../FileUpload/FacebookResumableUploader.php | 167 +++ .../FileUpload/FacebookTransferChunk.php | 133 +++ .../src/Facebook/FileUpload/FacebookVideo.php | 33 + .../src/Facebook/FileUpload/Mimetypes.php | 988 ++++++++++++++++++ .../src/Facebook/GraphNodes/Birthday.php | 85 ++ .../src/Facebook/GraphNodes/Collection.php | 242 +++++ .../Facebook/GraphNodes/GraphAchievement.php | 112 ++ .../src/Facebook/GraphNodes/GraphAlbum.php | 183 ++++ .../Facebook/GraphNodes/GraphApplication.php | 43 + .../Facebook/GraphNodes/GraphCoverPhoto.php | 72 ++ .../src/Facebook/GraphNodes/GraphEdge.php | 252 +++++ .../src/Facebook/GraphNodes/GraphEvent.php | 242 +++++ .../src/Facebook/GraphNodes/GraphGroup.php | 170 +++ .../src/Facebook/GraphNodes/GraphList.php | 36 + .../src/Facebook/GraphNodes/GraphLocation.php | 102 ++ .../src/Facebook/GraphNodes/GraphNode.php | 197 ++++ .../Facebook/GraphNodes/GraphNodeFactory.php | 392 +++++++ .../src/Facebook/GraphNodes/GraphObject.php | 36 + .../GraphNodes/GraphObjectFactory.php | 88 ++ .../src/Facebook/GraphNodes/GraphPage.php | 147 +++ .../src/Facebook/GraphNodes/GraphPicture.php | 72 ++ .../Facebook/GraphNodes/GraphSessionInfo.php | 102 ++ .../src/Facebook/GraphNodes/GraphUser.php | 172 +++ .../Facebook/Helpers/FacebookCanvasHelper.php | 52 + .../Helpers/FacebookJavaScriptHelper.php | 42 + .../Helpers/FacebookPageTabHelper.php | 95 ++ .../Helpers/FacebookRedirectLoginHelper.php | 333 ++++++ .../FacebookSignedRequestFromInputHelper.php | 166 +++ .../src/Facebook/Http/GraphRawResponse.php | 137 +++ .../Facebook/Http/RequestBodyInterface.php | 39 + .../Facebook/Http/RequestBodyMultipart.php | 170 +++ .../Facebook/Http/RequestBodyUrlEncoded.php | 55 + .../src/Facebook/HttpClients/FacebookCurl.php | 129 +++ .../HttpClients/FacebookCurlHttpClient.php | 163 +++ .../HttpClients/FacebookGuzzleHttpClient.php | 97 ++ .../FacebookHttpClientInterface.php | 47 + .../Facebook/HttpClients/FacebookStream.php | 80 ++ .../HttpClients/FacebookStreamHttpClient.php | 94 ++ .../HttpClients/HttpClientsFactory.php | 99 ++ .../certs/DigiCertHighAssuranceEVRootCA.pem | 23 + .../FacebookMemoryPersistentDataHandler.php | 53 + .../FacebookSessionPersistentDataHandler.php | 76 ++ .../PersistentData/PersistentDataFactory.php | 65 ++ .../PersistentDataInterface.php | 49 + .../McryptPseudoRandomStringGenerator.php | 68 ++ .../OpenSslPseudoRandomStringGenerator.php | 67 ++ .../PseudoRandomStringGeneratorFactory.php | 101 ++ .../PseudoRandomStringGeneratorInterface.php | 45 + .../PseudoRandomStringGeneratorTrait.php | 58 + ...RandomBytesPseudoRandomStringGenerator.php | 59 ++ .../UrandomPseudoRandomStringGenerator.php | 89 ++ .../graph-sdk/src/Facebook/SignedRequest.php | 326 ++++++ .../Url/FacebookUrlDetectionHandler.php | 182 ++++ .../Facebook/Url/FacebookUrlManipulator.php | 167 +++ .../Facebook/Url/UrlDetectionInterface.php | 39 + .../graph-sdk/src/Facebook/autoload.php | 81 ++ .../graph-sdk/src/Facebook/polyfills.php | 49 + 104 files changed, 12928 insertions(+), 937 deletions(-) create mode 100644 e107_handlers/hybridauth/vendor/autoload.php create mode 100644 e107_handlers/hybridauth/vendor/composer/ClassLoader.php create mode 100644 e107_handlers/hybridauth/vendor/composer/LICENSE create mode 100644 e107_handlers/hybridauth/vendor/composer/autoload_classmap.php create mode 100644 e107_handlers/hybridauth/vendor/composer/autoload_files.php create mode 100644 e107_handlers/hybridauth/vendor/composer/autoload_namespaces.php create mode 100644 e107_handlers/hybridauth/vendor/composer/autoload_psr4.php create mode 100644 e107_handlers/hybridauth/vendor/composer/autoload_real.php create mode 100644 e107_handlers/hybridauth/vendor/composer/installed.json create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/LICENSE create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/composer.json create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/phpcs.xml.dist create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthorizationException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookClientException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookOtherException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResponseException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookSDKException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookServerException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookThrottleException.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Facebook.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/Mimetypes.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphLocation.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObjectFactory.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyMultipart.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStream.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/certs/DigiCertHighAssuranceEVRootCA.pem create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookMemoryPersistentDataHandler.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataInterface.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/McryptPseudoRandomStringGenerator.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorInterface.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorTrait.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/RandomBytesPseudoRandomStringGenerator.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/autoload.php create mode 100644 e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/polyfills.php diff --git a/e107_core/controllers/system/xup.php b/e107_core/controllers/system/xup.php index 6b36f5d9c..396f7bcb4 100644 --- a/e107_core/controllers/system/xup.php +++ b/e107_core/controllers/system/xup.php @@ -147,7 +147,9 @@ class core_system_xup_controller extends eController public function actionEndpoint() { require_once( e_HANDLER."hybridauth/Hybrid/Auth.php" ); - require_once( e_HANDLER."hybridauth/Hybrid/Endpoint.php" ); + require_once( e_HANDLER."hybridauth/Hybrid/Endpoint.php" ); + require_once( e_HANDLER."hybridauth/vendor/autoload.php"); + try { Hybrid_Endpoint::process(); diff --git a/e107_handlers/hybridauth/Hybrid/Auth.php b/e107_handlers/hybridauth/Hybrid/Auth.php index b3506d561..a7991f709 100644 --- a/e107_handlers/hybridauth/Hybrid/Auth.php +++ b/e107_handlers/hybridauth/Hybrid/Auth.php @@ -15,7 +15,7 @@ */ class Hybrid_Auth { - public static $version = "2.7.0"; + public static $version = "2.9.6"; /** * Configuration array @@ -352,6 +352,9 @@ class Hybrid_Auth { * @param string $mode PHP|JS */ public static function redirect($url, $mode = "PHP") { + if(!$mode){ + $mode = 'PHP'; + } Hybrid_Logger::info("Enter Hybrid_Auth::redirect( $url, $mode )"); // Ensure session is saved before sending response, see https://github.com/symfony/symfony/pull/12341 diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php b/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php index d5bcf40d9..f96a500b1 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Adapter.php @@ -153,11 +153,26 @@ class Hybrid_Provider_Adapter { # for default HybridAuth endpoint url hauth_login_start_url # auth.start required the IDp ID # auth.time optional login request timestamp - $this->params["login_start"] = $HYBRID_AUTH_URL_BASE . ( strpos($HYBRID_AUTH_URL_BASE, '?') ? '&' : '?' ) . "hauth.start={$this->id}&hauth.time={$this->params["hauth_time"]}"; + if (!isset($this->params["login_start"]) ) { + $this->params["login_start"] = $HYBRID_AUTH_URL_BASE . ( strpos($HYBRID_AUTH_URL_BASE, '?') ? '&' : '?' ) . "hauth.start={$this->id}&hauth.time={$this->params["hauth_time"]}"; + } # for default HybridAuth endpoint url hauth_login_done_url # auth.done required the IDp ID - $this->params["login_done"] = $HYBRID_AUTH_URL_BASE . ( strpos($HYBRID_AUTH_URL_BASE, '?') ? '&' : '?' ) . "hauth.done={$this->id}"; + if (!isset($this->params["login_done"]) ) { + $this->params["login_done"] = $HYBRID_AUTH_URL_BASE . ( strpos($HYBRID_AUTH_URL_BASE, '?') ? '&' : '?' ) . "hauth.done={$this->id}"; + } + + # workaround to solve windows live authentication since microsoft disallowed redirect urls to contain any parameters + # http://mywebsite.com/path_to_hybridauth/?hauth.done=Live will not work + if ($this->id=="Live") { + $this->params["login_done"] = $HYBRID_AUTH_URL_BASE."live.php"; + } + + # Workaround to fix broken callback urls for the Facebook OAuth client + if ($this->adapter->useSafeUrls) { + $this->params['login_done'] = str_replace('hauth.done', 'hauth_done', $this->params['login_done']); + } if (isset($this->params["hauth_return_to"])) { Hybrid_Auth::storage()->set("hauth_session.{$this->id}.hauth_return_to", $this->params["hauth_return_to"]); @@ -224,14 +239,7 @@ class Hybrid_Provider_Adapter { throw new Exception("Call to undefined function Hybrid_Providers_{$this->id}::$name()."); } - $counter = count($arguments); - if ($counter == 1) { - return $this->adapter->$name($arguments[0]); - } elseif ($counter == 2) { - return $this->adapter->$name($arguments[0], $arguments[1]); - } else { - return $this->adapter->$name(); - } + return call_user_func_array(array($this->adapter, $name), $arguments); } /** diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Model.php b/e107_handlers/hybridauth/Hybrid/Provider_Model.php index d044bd540..9f5798bcd 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Model.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Model.php @@ -64,6 +64,9 @@ abstract class Hybrid_Provider_Model { */ public $compressed = false; + /** @var bool $useSafeUrls Enable this to replace '.' with '_' characters in the callback urls */ + public $useSafeUrls = false; + /** * Common providers adapter constructor * @@ -118,14 +121,14 @@ abstract class Hybrid_Provider_Model { * @return void * @throws Exception */ - abstract protected function loginBegin(); + abstract public function loginBegin(); /** * Finish login * @return void * @throws Exception */ - abstract protected function loginFinish(); + abstract public function loginFinish(); /** * Generic logout, just erase current provider adapter stored data to let Hybrid_Auth all forget about it @@ -140,7 +143,7 @@ abstract class Hybrid_Provider_Model { /** * Grab the user profile from the IDp api client * @return Hybrid_User_Profile - * @throw Exception + * @throws Exception */ function getUserProfile() { Hybrid_Logger::error("HybridAuth do not provide users contacts list for {$this->providerId} yet."); diff --git a/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php b/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php index 6159b8616..b9de4e2bc 100644 --- a/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php +++ b/e107_handlers/hybridauth/Hybrid/Provider_Model_OAuth2.php @@ -119,7 +119,7 @@ class Hybrid_Provider_Model_OAuth2 extends Hybrid_Provider_Model { try { $this->api->authenticate($code); } catch (Exception $e) { - throw new Exception("User profile request failed! {$this->providerId} returned an error: $e", 6); + throw new Exception("User profile request failed! {$this->providerId} returned an error: " . $e->getMessage(), 6); } // check if authenticated diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php b/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php index bd05baeeb..59c0d69e6 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Facebook.php @@ -1,5 +1,8 @@ config["keys"]["id"] || !$this->config["keys"]["secret"]) { - throw new Exception("Your application id and secret are required in order to connect to {$this->providerId}.", 4); - } - - if (!class_exists('FacebookApiException', false)) { - require_once Hybrid_Auth::$config["path_libraries"] . "Facebook/base_facebook.php"; - require_once Hybrid_Auth::$config["path_libraries"] . "Facebook/facebook.php"; - } - - if (isset(Hybrid_Auth::$config["proxy"])) { - BaseFacebook::$CURL_OPTS[CURLOPT_PROXY] = Hybrid_Auth::$config["proxy"]; - } - - $trustForwarded = isset($this->config['trustForwarded']) ? (bool) $this->config['trustForwarded'] : false; - $this->api = new Facebook(array('appId' => $this->config["keys"]["id"], 'secret' => $this->config["keys"]["secret"], 'trustForwarded' => $trustForwarded)); - - if ($this->token("access_token")) { - $this->api->setAccessToken($this->token("access_token")); - $this->api->setExtendedAccessToken(); - $access_token = $this->api->getAccessToken(); - - if ($access_token) { - $this->token("access_token", $access_token); - $this->api->setAccessToken($access_token); - } - - $this->api->setAccessToken($this->token("access_token")); - } - - $this->api->getUser(); - } - - /** - * {@inheritdoc} - */ - function loginBegin() { - $parameters = array("scope" => $this->scope, "redirect_uri" => $this->endpoint, "display" => "page"); - $optionals = array("scope", "redirect_uri", "display", "auth_type"); - - foreach ($optionals as $parameter) { - if (isset($this->config[$parameter]) && !empty($this->config[$parameter])) { - $parameters[$parameter] = $this->config[$parameter]; - - //If the auth_type parameter is used, we need to generate a nonce and include it as a parameter - if ($parameter == "auth_type") { - $nonce = md5(uniqid(mt_rand(), true)); - $parameters['auth_nonce'] = $nonce; - - Hybrid_Auth::storage()->set('fb_auth_nonce', $nonce); - } - } - } - - if (isset($this->config['force']) && $this->config['force'] === true) { - $parameters['auth_type'] = 'reauthenticate'; - $parameters['auth_nonce'] = md5(uniqid(mt_rand(), true)); - - Hybrid_Auth::storage()->set('fb_auth_nonce', $parameters['auth_nonce']); - } - - // get the login url - $url = $this->api->getLoginUrl($parameters); - - // redirect to facebook - Hybrid_Auth::redirect($url); - } - - /** - * {@inheritdoc} - */ - function loginFinish() { - // in case we get error_reason=user_denied&error=access_denied - if (isset($_REQUEST['error']) && $_REQUEST['error'] == "access_denied") { - throw new Exception("Authentication failed! The user denied your request.", 5); - } - - // in case we are using iOS/Facebook reverse authentication - if (isset($_REQUEST['access_token'])) { - $this->token("access_token", $_REQUEST['access_token']); - $this->api->setAccessToken($this->token("access_token")); - $this->api->setExtendedAccessToken(); - $access_token = $this->api->getAccessToken(); - - if ($access_token) { - $this->token("access_token", $access_token); - $this->api->setAccessToken($access_token); - } - - $this->api->setAccessToken($this->token("access_token")); - } - - - // if auth_type is used, then an auth_nonce is passed back, and we need to check it. - if (isset($_REQUEST['auth_nonce'])) { - - $nonce = Hybrid_Auth::storage()->get('fb_auth_nonce'); - - //Delete the nonce - Hybrid_Auth::storage()->delete('fb_auth_nonce'); - - if ($_REQUEST['auth_nonce'] != $nonce) { - throw new Exception("Authentication failed! Invalid nonce used for reauthentication.", 5); - } - } - - // try to get the UID of the connected user from fb, should be > 0 - if (!$this->api->getUser()) { - throw new Exception("Authentication failed! {$this->providerId} returned an invalid user id.", 5); - } - - // set user as logged in - $this->setUserConnected(); - - // store facebook access token - $this->token("access_token", $this->api->getAccessToken()); - } - - /** - * {@inheritdoc} - */ - function logout() { - $this->api->destroySession(); - parent::logout(); - } - - /** - * {@inheritdoc} - */ - function getUserProfile() { - // request user profile from fb api - try { - $fields = array( - 'id', 'name', 'first_name', 'last_name', 'link', 'website', - 'gender', 'locale', 'about', 'email', 'hometown', 'location', - 'birthday' - ); - - $data = $this->api->api('/me?fields=' . implode(',', $fields)); - } catch (FacebookApiException $e) { - throw new Exception("User profile request failed! {$this->providerId} returned an error: {$e->getMessage()}", 6, $e); - } - - // if the provider identifier is not received, we assume the auth has failed - if (!isset($data["id"])) { - throw new Exception("User profile request failed! {$this->providerId} api returned an invalid response: " . Hybrid_Logger::dumpData( $data ), 6); - } - - # store the user profile. - $this->user->profile->identifier = (array_key_exists('id', $data)) ? $data['id'] : ""; - $this->user->profile->username = (array_key_exists('username', $data)) ? $data['username'] : ""; - $this->user->profile->displayName = (array_key_exists('name', $data)) ? $data['name'] : ""; - $this->user->profile->firstName = (array_key_exists('first_name', $data)) ? $data['first_name'] : ""; - $this->user->profile->lastName = (array_key_exists('last_name', $data)) ? $data['last_name'] : ""; - $this->user->profile->photoURL = "https://graph.facebook.com/" . $this->user->profile->identifier . "/picture?width=150&height=150"; - $this->user->profile->coverInfoURL = "https://graph.facebook.com/" . $this->user->profile->identifier . "?fields=cover&access_token=" . $this->api->getAccessToken(); - $this->user->profile->profileURL = (array_key_exists('link', $data)) ? $data['link'] : ""; - $this->user->profile->webSiteURL = (array_key_exists('website', $data)) ? $data['website'] : ""; - $this->user->profile->gender = (array_key_exists('gender', $data)) ? $data['gender'] : ""; - $this->user->profile->language = (array_key_exists('locale', $data)) ? $data['locale'] : ""; - $this->user->profile->description = (array_key_exists('about', $data)) ? $data['about'] : ""; - $this->user->profile->email = (array_key_exists('email', $data)) ? $data['email'] : ""; - $this->user->profile->emailVerified = (array_key_exists('email', $data)) ? $data['email'] : ""; - $this->user->profile->region = (array_key_exists("location", $data) && array_key_exists("name", $data['location'])) ? $data['location']["name"] : ""; - - if (!empty($this->user->profile->region)) { - $regionArr = explode(',', $this->user->profile->region); - if (count($regionArr) > 1) { - $this->user->profile->city = trim($regionArr[0]); - $this->user->profile->country = trim($regionArr[1]); - } - } - - if (array_key_exists('birthday', $data)) { - list($birthday_month, $birthday_day, $birthday_year) = explode("/", $data['birthday']); - - $this->user->profile->birthDay = (int) $birthday_day; - $this->user->profile->birthMonth = (int) $birthday_month; - $this->user->profile->birthYear = (int) $birthday_year; - } - - return $this->user->profile; - } - - /** - * Attempt to retrieve the url to the cover image given the coverInfoURL - * - * @param string $coverInfoURL coverInfoURL variable - * @return string url to the cover image OR blank string - */ - function getCoverURL($coverInfoURL) { - try { - $headers = get_headers($coverInfoURL); - if (substr($headers[0], 9, 3) != "404") { - $coverOBJ = json_decode(file_get_contents($coverInfoURL)); - if (array_key_exists('cover', $coverOBJ)) { - return $coverOBJ->cover->source; - } - } - } catch (Exception $e) { - - } - - return ""; - } - - /** - * {@inheritdoc} - */ - function getUserContacts() { - $apiCall = '?fields=link,name'; - $returnedContacts = array(); - $pagedList = false; - - do { - try { - $response = $this->api->api('/me/friends' . $apiCall); - } catch (FacebookApiException $e) { - throw new Exception("User contacts request failed! {$this->providerId} returned an error {$e->getMessage()}", 0, $e); - } - - // Prepare the next call if paging links have been returned - if (array_key_exists('paging', $response) && array_key_exists('next', $response['paging'])) { - $pagedList = true; - $next_page = explode('friends', $response['paging']['next']); - $apiCall = $next_page[1]; - } else { - $pagedList = false; - } - - // Add the new page contacts - $returnedContacts = array_merge($returnedContacts, $response['data']); - } while ($pagedList == true); - - $contacts = array(); - - foreach ($returnedContacts as $item) { - - $uc = new Hybrid_User_Contact(); - $uc->identifier = (array_key_exists("id", $item)) ? $item["id"] : ""; - $uc->displayName = (array_key_exists("name", $item)) ? $item["name"] : ""; - $uc->profileURL = (array_key_exists("link", $item)) ? $item["link"] : "https://www.facebook.com/profile.php?id=" . $uc->identifier; - $uc->photoURL = "https://graph.facebook.com/" . $uc->identifier . "/picture?width=150&height=150"; - - $contacts[] = $uc; - } - - return $contacts; - } - - /** - * Update user status - * - * @param mixed $status An array describing the status, or string - * @param string $pageid (optional) User page id - * @return array - * @throw Exception - */ - function setUserStatus($status, $pageid = null) { - if (!is_array($status)) { - $status = array('message' => $status); - } - - if (is_null($pageid)) { - $pageid = 'me'; - - // if post on page, get access_token page - } else { - $access_token = null; - foreach ($this->getUserPages(true) as $p) { - if (isset($p['id']) && intval($p['id']) == intval($pageid)) { - $access_token = $p['access_token']; - break; - } - } - - if (is_null($access_token)) { - throw new Exception("Update user page failed, page not found or not writable!"); - } - - $status['access_token'] = $access_token; - } - - try { - $response = $this->api->api('/' . $pageid . '/feed', 'post', $status); - } catch (FacebookApiException $e) { - throw new Exception("Update user status failed! {$this->providerId} returned an error {$e->getMessage()}", 0, $e); - } - - return $response; - } - - /** - * {@inheridoc} - */ - function getUserStatus($postid) { - try { - $postinfo = $this->api->api("/" . $postid); - } catch (FacebookApiException $e) { - throw new Exception("Cannot retrieve user status! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); - } - - return $postinfo; - } - - /** - * {@inheridoc} - */ - function getUserPages($writableonly = false) { - if (( isset($this->config['scope']) && strpos($this->config['scope'], 'manage_pages') === false ) || (!isset($this->config['scope']) && strpos($this->scope, 'manage_pages') === false )) - throw new Exception("User status requires manage_page permission!"); - - try { - $pages = $this->api->api("/me/accounts", 'get'); - } catch (FacebookApiException $e) { - throw new Exception("Cannot retrieve user pages! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); - } - - if (!isset($pages['data'])) { - return array(); - } - - if (!$writableonly) { - return $pages['data']; - } - - $wrpages = array(); - foreach ($pages['data'] as $p) { - if (isset($p['perms']) && in_array('CREATE_CONTENT', $p['perms'])) { - $wrpages[] = $p; - } - } - - return $wrpages; - } - - /** - * load the user latest activity - * - timeline : all the stream - * - me : the user activity only - * {@inheritdoc} - */ - function getUserActivity($stream) { - try { - if ($stream == "me") { - $response = $this->api->api('/me/feed'); - } else { - $response = $this->api->api('/me/home'); - } - } catch (FacebookApiException $e) { - throw new Exception("User activity stream request failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); - } - - if (!$response || !count($response['data'])) { - return array(); - } - - $activities = array(); - - foreach ($response['data'] as $item) { - if ($stream == "me" && $item["from"]["id"] != $this->api->getUser()) { - continue; - } - - $ua = new Hybrid_User_Activity(); - - $ua->id = (array_key_exists("id", $item)) ? $item["id"] : ""; - $ua->date = (array_key_exists("created_time", $item)) ? strtotime($item["created_time"]) : ""; - - if ($item["type"] == "video") { - $ua->text = (array_key_exists("link", $item)) ? $item["link"] : ""; - } - - if ($item["type"] == "link") { - $ua->text = (array_key_exists("link", $item)) ? $item["link"] : ""; - } - - if (empty($ua->text) && isset($item["story"])) { - $ua->text = (array_key_exists("link", $item)) ? $item["link"] : ""; - } - - if (empty($ua->text) && isset($item["message"])) { - $ua->text = (array_key_exists("message", $item)) ? $item["message"] : ""; - } - - if (!empty($ua->text)) { - $ua->user->identifier = (array_key_exists("id", $item["from"])) ? $item["from"]["id"] : ""; - $ua->user->displayName = (array_key_exists("name", $item["from"])) ? $item["from"]["name"] : ""; - $ua->user->profileURL = "https://www.facebook.com/profile.php?id=" . $ua->user->identifier; - $ua->user->photoURL = "https://graph.facebook.com/" . $ua->user->identifier . "/picture?type=square"; - - $activities[] = $ua; - } - } - - return $activities; - } + /** + * Default permissions, and a lot of them. You can change them from the configuration by setting the scope to what you want/need. + * For a complete list see: https://developers.facebook.com/docs/facebook-login/permissions + * + * @link https://developers.facebook.com/docs/facebook-login/permissions + * @var array $scope + */ + public $scope = ['email', 'user_about_me', 'user_birthday', 'user_hometown', 'user_location', 'user_website', 'publish_actions', 'read_custom_friendlists']; + + /** + * Provider API client + * + * @var \Facebook\Facebook + */ + public $api; + + public $useSafeUrls = true; + + /** + * {@inheritdoc} + */ + function initialize() { + if (!$this->config["keys"]["id"] || !$this->config["keys"]["secret"]) { + throw new Exception("Your application id and secret are required in order to connect to {$this->providerId}.", 4); + } + + if (isset($this->config['scope'])) { + $scope = $this->config['scope']; + if (is_string($scope)) { + $scope = explode(",", $scope); + } + $scope = array_map('trim', $scope); + $this->scope = $scope; + } + + $trustForwarded = isset($this->config['trustForwarded']) ? (bool)$this->config['trustForwarded'] : false; + + // Check if there is Graph SDK in thirdparty/Facebook. + if (file_exists(Hybrid_Auth::$config["path_libraries"] . "Facebook/autoload.php")) { + require_once Hybrid_Auth::$config["path_libraries"] . "Facebook/autoload.php"; + } + else { + // If Composer install was executed, try to find autoload.php. + $vendorDir = dirname(Hybrid_Auth::$config['path_base']); + do { + if (file_exists($vendorDir . "/vendor/autoload.php")) { + require_once $vendorDir . "/vendor/autoload.php"; + break; + } + } while (($vendorDir = dirname($vendorDir)) !== '/'); + } + + $this->api = new FacebookSDK([ + 'app_id' => $this->config["keys"]["id"], + 'app_secret' => $this->config["keys"]["secret"], + 'default_graph_version' => 'v2.8', + 'trustForwarded' => $trustForwarded, + ]); + } + + /** + * {@inheritdoc} + */ + function loginBegin() { + + $this->endpoint = $this->params['login_done']; + $helper = $this->api->getRedirectLoginHelper(); + + // Use re-request, because this will trigger permissions window if not all permissions are granted. + $url = $helper->getReRequestUrl($this->endpoint, $this->scope); + + // Redirect to Facebook + Hybrid_Auth::redirect($url); + } + + /** + * {@inheritdoc} + */ + function loginFinish() { + + $helper = $this->api->getRedirectLoginHelper(); + try { + $accessToken = $helper->getAccessToken($this->params['login_done']); + } catch (Facebook\Exceptions\FacebookResponseException $e) { + throw new Hybrid_Exception('Facebook Graph returned an error: ' . $e->getMessage()); + } catch (Facebook\Exceptions\FacebookSDKException $e) { + throw new Hybrid_Exception('Facebook SDK returned an error: ' . $e->getMessage()); + } + + if (!isset($accessToken)) { + if ($helper->getError()) { + throw new Hybrid_Exception(sprintf("Could not authorize user, reason: %s (%d)", $helper->getErrorDescription(), $helper->getErrorCode())); + } else { + throw new Hybrid_Exception("Could not authorize user. Bad request"); + } + } + + try { + // Validate token + $oAuth2Client = $this->api->getOAuth2Client(); + $tokenMetadata = $oAuth2Client->debugToken($accessToken); + $tokenMetadata->validateAppId($this->config["keys"]["id"]); + $tokenMetadata->validateExpiration(); + + // Exchanges a short-lived access token for a long-lived one + if (!$accessToken->isLongLived()) { + $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken); + } + } catch (FacebookSDKException $e) { + throw new Hybrid_Exception($e->getMessage(), 0, $e); + } + + $this->setUserConnected(); + $this->token("access_token", $accessToken->getValue()); + } + + /** + * {@inheritdoc} + */ + function logout() { + parent::logout(); + } + + /** + * Update user status + * + * @param mixed $status An array describing the status, or string + * @param string $pageid (optional) User page id + * @return array + * @throw Exception + */ + function setUserStatus($status, $pageid = null) { + + if (!is_array($status)) { + $status = array('message' => $status); + } + + $access_token = null; + + if (is_null($pageid)) { + $pageid = 'me'; + $access_token = $this->token('access_token'); + + // if post on page, get access_token page + } else { + + foreach ($this->getUserPages(true) as $p) { + if (isset($p['id']) && intval($p['id']) == intval($pageid)) { + $access_token = $p['access_token']; + break; + } + } + + if (is_null($access_token)) { + throw new Exception("Update user page failed, page not found or not writable!"); + } + } + + try { + $response = $this->api->post('/' . $pageid . '/feed', $status, $access_token); + } catch (FacebookSDKException $e) { + throw new Exception("Update user status failed! {$this->providerId} returned an error {$e->getMessage()}", 0, $e); + } + + return $response; + } + + /** + * {@inheridoc} + */ + function getUserPages($writableonly = false) { + if (( isset($this->config['scope']) && strpos($this->config['scope'], 'manage_pages') === false ) || (!isset($this->config['scope']) && strpos($this->scope, 'manage_pages') === false )) + throw new Exception("User status requires manage_page permission!"); + + try { + $pages = $this->api->get("/me/accounts", $this->token('access_token')); + $pages = $pages->getDecodedBody(); + } catch (FacebookApiException $e) { + throw new Exception("Cannot retrieve user pages! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); + } + + if (!isset($pages['data'])) { + return array(); + } + + if (!$writableonly) { + return $pages['data']; + } + + $wrpages = array(); + foreach ($pages['data'] as $p) { + if (isset($p['perms']) && in_array('CREATE_CONTENT', $p['perms'])) { + $wrpages[] = $p; + } + } + + return $wrpages; + } + + /** + * {@inheritdoc} + */ + function getUserProfile() { + try { + $fields = [ + 'id', + 'name', + 'first_name', + 'last_name', + 'link', + 'website', + 'gender', + 'locale', + 'about', + 'email', + 'hometown', + 'location', + 'birthday' + ]; + $response = $this->api->get('/me?fields=' . implode(',', $fields), $this->token('access_token')); + $data = $response->getDecodedBody(); + } catch (FacebookSDKException $e) { + throw new Exception("User profile request failed! {$this->providerId} returned an error: {$e->getMessage()}", 6, $e); + } + + // Store the user profile. + $this->user->profile->identifier = (array_key_exists('id', $data)) ? $data['id'] : ""; + $this->user->profile->displayName = (array_key_exists('name', $data)) ? $data['name'] : ""; + $this->user->profile->firstName = (array_key_exists('first_name', $data)) ? $data['first_name'] : ""; + $this->user->profile->lastName = (array_key_exists('last_name', $data)) ? $data['last_name'] : ""; + $this->user->profile->photoURL = $this->getUserPhoto($this->user->profile->identifier); + $this->user->profile->profileURL = (array_key_exists('link', $data)) ? $data['link'] : ""; + $this->user->profile->webSiteURL = (array_key_exists('website', $data)) ? $data['website'] : ""; + $this->user->profile->gender = (array_key_exists('gender', $data)) ? $data['gender'] : ""; + $this->user->profile->language = (array_key_exists('locale', $data)) ? $data['locale'] : ""; + $this->user->profile->description = (array_key_exists('about', $data)) ? $data['about'] : ""; + $this->user->profile->email = (array_key_exists('email', $data)) ? $data['email'] : ""; + $this->user->profile->emailVerified = (array_key_exists('email', $data)) ? $data['email'] : ""; + $this->user->profile->region = (array_key_exists("location", $data) && array_key_exists("name", $data['location'])) ? $data['location']["name"] : ""; + + if (!empty($this->user->profile->region)) { + $regionArr = explode(',', $this->user->profile->region); + if (count($regionArr) > 1) { + $this->user->profile->city = trim($regionArr[0]); + $this->user->profile->country = trim(end($regionArr)); + } + } + + if (array_key_exists('birthday', $data)) { + $birtydayPieces = explode('/', $data['birthday']); + + if (count($birtydayPieces) == 1) { + $this->user->profile->birthYear = (int)$birtydayPieces[0]; + } elseif (count($birtydayPieces) == 2) { + $this->user->profile->birthMonth = (int)$birtydayPieces[0]; + $this->user->profile->birthDay = (int)$birtydayPieces[1]; + } elseif (count($birtydayPieces) == 3) { + $this->user->profile->birthMonth = (int)$birtydayPieces[0]; + $this->user->profile->birthDay = (int)$birtydayPieces[1]; + $this->user->profile->birthYear = (int)$birtydayPieces[2]; + } + } + + return $this->user->profile; + } + + /** + * Since the Graph API 2.0, the /friends endpoint only returns friend that also use your Facebook app. + * {@inheritdoc} + */ + function getUserContacts() { + $apiCall = '?fields=link,name'; + $returnedContacts = []; + $pagedList = true; + + while ($pagedList) { + try { + $response = $this->api->get('/me/friends' . $apiCall, $this->token('access_token')); + $response = $response->getDecodedBody(); + } catch (FacebookSDKException $e) { + throw new Hybrid_Exception("User contacts request failed! {$this->providerId} returned an error {$e->getMessage()}", 0, $e); + } + + // Prepare the next call if paging links have been returned + if (array_key_exists('paging', $response) && array_key_exists('next', $response['paging'])) { + $pagedList = true; + $next_page = explode('friends', $response['paging']['next']); + $apiCall = $next_page[1]; + } else { + $pagedList = false; + } + + // Add the new page contacts + $returnedContacts = array_merge($returnedContacts, $response['data']); + } + + $contacts = []; + foreach ($returnedContacts as $item) { + + $uc = new Hybrid_User_Contact(); + $uc->identifier = (array_key_exists("id", $item)) ? $item["id"] : ""; + $uc->displayName = (array_key_exists("name", $item)) ? $item["name"] : ""; + $uc->profileURL = (array_key_exists("link", $item)) ? $item["link"] : "https://www.facebook.com/profile.php?id=" . $uc->identifier; + $uc->photoURL = $this->getUserPhoto($uc->identifier); + + $contacts[] = $uc; + } + + return $contacts; + } + + /** + * Load the user latest activity, needs 'read_stream' permission + * + * @param string $stream Which activity to fetch: + * - timeline : all the stream + * - me : the user activity only + * {@inheritdoc} + */ + function getUserActivity($stream = 'timeline') { + try { + if ($stream == "me") { + $response = $this->api->get('/me/feed', $this->token('access_token')); + } else { + $response = $this->api->get('/me/home', $this->token('access_token')); + } + $response = $response->getDecodedBody(); + } catch (FacebookSDKException $e) { + throw new Hybrid_Exception("User activity stream request failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); + } + + if (!$response || !count($response['data'])) { + return []; + } + + $activities = []; + foreach ($response['data'] as $item) { + + $ua = new Hybrid_User_Activity(); + + $ua->id = (array_key_exists("id", $item)) ? $item["id"] : ""; + $ua->date = (array_key_exists("created_time", $item)) ? strtotime($item["created_time"]) : ""; + + if ($item["type"] == "video") { + $ua->text = (array_key_exists("link", $item)) ? $item["link"] : ""; + } + + if ($item["type"] == "link") { + $ua->text = (array_key_exists("link", $item)) ? $item["link"] : ""; + } + + if (empty($ua->text) && isset($item["story"])) { + $ua->text = (array_key_exists("link", $item)) ? $item["link"] : ""; + } + + if (empty($ua->text) && isset($item["message"])) { + $ua->text = (array_key_exists("message", $item)) ? $item["message"] : ""; + } + + if (!empty($ua->text)) { + $ua->user->identifier = (array_key_exists("id", $item["from"])) ? $item["from"]["id"] : ""; + $ua->user->displayName = (array_key_exists("name", $item["from"])) ? $item["from"]["name"] : ""; + $ua->user->profileURL = "https://www.facebook.com/profile.php?id=" . $ua->user->identifier; + $ua->user->photoURL = $this->getUserPhoto($ua->user->identifier); + + $activities[] = $ua; + } + } + + return $activities; + } + + /** + * Returns a photo URL for give user. + * + * @param string $id + * The User ID. + * + * @return string + * A photo URL. + */ + function getUserPhoto($id) { + $photo_size = isset($this->config['photo_size']) ? $this->config['photo_size'] : 150; + + return "https://graph.facebook.com/{$id}/picture?width={$photo_size}&height={$photo_size}"; + } } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php b/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php index cfbe65730..5c64e969e 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Foursquare.php @@ -82,7 +82,7 @@ class Hybrid_Providers_Foursquare extends Hybrid_Provider_Model_OAuth2 { $contacts = array(); try { $response = $this->api->api("users/self/friends", "GET", Hybrid_Providers_Foursquare::$apiVersion); - } catch (LinkedInException $e) { + } catch (Exception $e) { throw new Exception("User contacts request failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Google.php b/e107_handlers/hybridauth/Hybrid/Providers/Google.php index 4b75ce496..9e650e50a 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Google.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Google.php @@ -19,7 +19,7 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { * default permissions * {@inheritdoc} */ - public $scope = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.profile.emails.read https://www.google.com/m8/feeds/"; + public $scope = "https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/plus.profile.emails.read https://www.google.com/m8/feeds/"; /** * {@inheritdoc} @@ -158,16 +158,16 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { } else { $this->user->profile->webSiteURL = ''; } - // google API returns age ranges or min. age only (with plus.login scope) + // google API returns age ranges min and/or max as of https://developers.google.com/+/web/api/rest/latest/people#resource if (property_exists($response, 'ageRange')) { if (property_exists($response->ageRange, 'min') && property_exists($response->ageRange, 'max')) { $this->user->profile->age = $response->ageRange->min . ' - ' . $response->ageRange->max; } else { if (property_exists($response->ageRange, 'min')) { - $this->user->profile->age = '> ' . $response->ageRange->min; + $this->user->profile->age = '>= ' . $response->ageRange->min; } else { if (property_exists($response->ageRange, 'max')) { - $this->user->profile->age = '< ' . $response->ageRange->max; + $this->user->profile->age = '<= ' . $response->ageRange->max; } else { $this->user->profile->age = ''; } @@ -198,22 +198,22 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { function getUserContacts() { // refresh tokens if needed $this->refreshToken(); - + $contacts = array(); if (!isset($this->config['contacts_param'])) { $this->config['contacts_param'] = array("max-results" => 500); } - + // Google Gmail and Android contacts if (strpos($this->scope, '/m8/feeds/') !== false) { - + $response = $this->api->api("https://www.google.com/m8/feeds/contacts/default/full?" - . http_build_query(array_merge(array('alt' => 'json', 'v' => '3.0'), $this->config['contacts_param']))); - + . http_build_query(array_merge(array('alt' => 'json'), $this->config['contacts_param']))); + if (!$response) { return array(); } - + if (isset($response->feed->entry)) { foreach ($response->feed->entry as $idx => $entry) { $uc = new Hybrid_User_Contact(); @@ -249,40 +249,40 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { } else { $uc->webSiteURL = ''; } - + $contacts[] = $uc; } } } - + // Google social contacts if (strpos($this->scope, '/auth/plus.login') !== false) { - + $response = $this->api->api("https://www.googleapis.com/plus/v1/people/me/people/visible?" . http_build_query($this->config['contacts_param'])); - + if (!$response) { return array(); } - + foreach ($response->items as $idx => $item) { $uc = new Hybrid_User_Contact(); $uc->email = (property_exists($item, 'email')) ? $item->email : ''; $uc->displayName = (property_exists($item, 'displayName')) ? $item->displayName : ''; $uc->identifier = (property_exists($item, 'id')) ? $item->id : ''; - + $uc->description = (property_exists($item, 'objectType')) ? $item->objectType : ''; $uc->photoURL = (property_exists($item, 'image')) ? ((property_exists($item->image, 'url')) ? $item->image->url : '') : ''; $uc->profileURL = (property_exists($item, 'url')) ? $item->url : ''; $uc->webSiteURL = ''; - + $contacts[] = $uc; } } - + return $contacts; } - + /** * Add query parameters to the $url * @@ -290,7 +290,7 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { * @param array $params Parameters to add * @return string */ - function addUrlParam($url, array $params) { + function addUrlParam($url, array $params){ $query = parse_url($url, PHP_URL_QUERY); // Returns the URL string with new parameters @@ -303,3 +303,4 @@ class Hybrid_Providers_Google extends Hybrid_Provider_Model_OAuth2 { } } + diff --git a/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php b/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php index 5e3d8b32f..2a442b2dc 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/LinkedIn.php @@ -1,282 +1,170 @@ config["keys"]["key"] || !$this->config["keys"]["secret"]) { - throw new Exception("Your application key and secret are required in order to connect to {$this->providerId}.", 4); - } + /** + * {@inheritdoc} + */ + function initialize() { + parent::initialize(); - if (empty($this->config['fields'])) { - $this->config['fields'] = [ - 'id', - 'first-name', - 'last-name', - 'public-profile-url', - 'picture-url', - 'email-address', - 'date-of-birth', - 'phone-numbers', - 'summary', - ]; - } + // Provider api end-points. + $this->api->api_base_url = "https://api.linkedin.com/v1/"; + $this->api->authorize_url = "https://www.linkedin.com/oauth/v2/authorization"; + $this->api->token_url = "https://www.linkedin.com/oauth/v2/accessToken"; + } - if (!class_exists('OAuthConsumer', false)) { - require_once Hybrid_Auth::$config["path_libraries"] . "OAuth/OAuth.php"; - } - require_once Hybrid_Auth::$config["path_libraries"] . "LinkedIn/LinkedIn.php"; + /** + * {@inheritdoc} + */ + function loginBegin() { + if (is_array($this->scope)) { + $this->scope = implode(" ", $this->scope); + } + parent::loginBegin(); + } - $this->api = new LinkedIn(array('appKey' => $this->config["keys"]["key"], 'appSecret' => $this->config["keys"]["secret"], 'callbackUrl' => $this->endpoint)); + /** + * {@inheritdoc} + * + * @see https://developer.linkedin.com/docs/rest-api + */ + function getUserProfile() { + // Refresh tokens if needed. + $this->setHeaders("token"); + $this->refreshToken(); - if ($this->token("access_token_linkedin")) { - $this->api->setTokenAccess($this->token("access_token_linkedin")); - } - } + // https://developer.linkedin.com/docs/fields. + $fields = isset($this->config["fields"]) ? $this->config["fields"] : [ + "id", + "email-address", + "first-name", + "last-name", + "headline", + "location", + "industry", + "picture-url", + "public-profile-url", + ]; - /** - * {@inheritdoc} - */ - function loginBegin() { - // send a request for a LinkedIn access token - $response = $this->api->retrieveTokenRequest(); + $this->setHeaders(); + $response = $this->api->get( + "people/~:(" . implode(",", $fields) . ")", + array( + "format" => "json", + ) + ); - if (isset($response['success']) && $response['success'] === true) { - $this->token("oauth_token", $response['linkedin']['oauth_token']); - $this->token("oauth_token_secret", $response['linkedin']['oauth_token_secret']); - - # redirect user to LinkedIn authorisation web page - Hybrid_Auth::redirect(LINKEDIN::_URL_AUTH . $response['linkedin']['oauth_token']); - } else { - throw new Exception("Authentication failed! {$this->providerId} returned an invalid Token in response: " . Hybrid_Logger::dumpData( $response ), 5); - } - } - - /** - * {@inheritdoc} - */ - function loginFinish() { - // in case we get oauth_problem=user_refused - if (isset($_REQUEST['oauth_problem']) && $_REQUEST['oauth_problem'] == "user_refused") { - throw new Exception("Authentication failed! The user denied your request.", 5); + if (!isset($response->id)) { + throw new Exception("User profile request failed! {$this->providerId} returned an invalid response: " . Hybrid_Logger::dumpData($response), 6); } - $oauth_token = isset($_REQUEST['oauth_token']) ? $_REQUEST['oauth_token'] : null; - $oauth_verifier = isset($_REQUEST['oauth_verifier']) ? $_REQUEST['oauth_verifier'] : null; + $this->user->profile->identifier = isset($response->id) ? $response->id : ""; + $this->user->profile->firstName = isset($response->firstName) ? $response->firstName : ""; + $this->user->profile->lastName = isset($response->lastName) ? $response->lastName : ""; + $this->user->profile->photoURL = isset($response->pictureUrl) ? $response->pictureUrl : ""; + $this->user->profile->profileURL = isset($response->publicProfileUrl) ? $response->publicProfileUrl : ""; + $this->user->profile->email = isset($response->emailAddress) ? $response->emailAddress : ""; + $this->user->profile->description = isset($response->headline) ? $response->headline : ""; + $this->user->profile->country = isset($response->location) ? $response->location->name : ""; + $this->user->profile->emailVerified = $this->user->profile->email; + $this->user->profile->displayName = trim($this->user->profile->firstName . " " . $this->user->profile->lastName); - if (!$oauth_token || !$oauth_verifier) { - throw new Exception("Authentication failed! {$this->providerId} returned an invalid Token.", 5); - } + return $this->user->profile; + } - $response = $this->api->retrieveTokenAccess($oauth_token, $this->token("oauth_token_secret"), $oauth_verifier); + /** + * {@inheritdoc} + * + * @param array $status + * An associative array containing: + * - content: A collection of fields describing the shared content. + * - comment: A comment by the member to associated with the share. + * - visibility: A collection of visibility information about the share. + * + * @return object + * An object containing: + * - updateKey - A unique ID for the shared content posting that was just created. + * - updateUrl - A direct link to the newly shared content on LinkedIn.com that you can direct the user's web browser to. + * @throws Exception + * @see https://developer.linkedin.com/docs/share-on-linkedin + */ + function setUserStatus($status) { + // Refresh tokens if needed. + $this->setHeaders("token"); + $this->refreshToken(); - if (isset($response['success']) && $response['success'] === true) { - $this->deleteToken("oauth_token"); - $this->deleteToken("oauth_token_secret"); + try { + // Define default visibility. + if (!isset($status["visibility"])) { + $status["visibility"]["code"] = "anyone"; + } - $this->token("access_token_linkedin", $response['linkedin']); - $this->token("access_token", $response['linkedin']['oauth_token']); - $this->token("access_token_secret", $response['linkedin']['oauth_token_secret']); + $this->setHeaders("share"); + $response = $this->api->post( + "people/~/shares?format=json", + array( + "body" => $status, + ) + ); + } catch (Exception $e) { + throw new Exception("Update user status failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); + } - // set user as logged in - $this->setUserConnected(); - } else { - throw new Exception("Authentication failed! {$this->providerId} returned an invalid Token in response: " . Hybrid_Logger::dumpData( $response ), 5); - } - } + if (!isset($response->updateKey)) { + throw new Exception("Update user status failed! {$this->providerId} returned an error: {$response->message}", $response->errorCode); + } - /** - * {@inheritdoc} - */ - function getUserProfile() { - try { - // http://developer.linkedin.com/docs/DOC-1061 - $response = $this->api->profile('~:('. implode(',', $this->config['fields']) .')'); - } catch (LinkedInException $e) { - throw new Exception("User profile request failed! {$this->providerId} returned an error: {$e->getMessage()}", 6, $e); - } + return $response; + } - if (isset($response['success']) && $response['success'] === true) { - $data = @ new SimpleXMLElement($response['linkedin']); + /** + * Set correct request headers. + * + * @param string $api_type + * (optional) Specify api type. + * + * @return void + */ + private function setHeaders($api_type = null) { + $this->api->curl_header = array( + "Authorization: Bearer {$this->api->access_token}", + ); - if (!is_object($data)) { - throw new Exception("User profile request failed! {$this->providerId} returned an invalid xml data: " . Hybrid_Logger::dumpData( $data ), 6); - } + switch ($api_type) { + case "share": + $this->api->curl_header = array_merge( + $this->api->curl_header, + array( + "Content-Type: application/json", + "x-li-format: json", + ) + ); + break; - $this->user->profile->identifier = (string) $data->{'id'}; - $this->user->profile->firstName = (string) $data->{'first-name'}; - $this->user->profile->lastName = (string) $data->{'last-name'}; - $this->user->profile->displayName = trim($this->user->profile->firstName . " " . $this->user->profile->lastName); - - $this->user->profile->email = (string) $data->{'email-address'}; - $this->user->profile->emailVerified = (string) $data->{'email-address'}; - - if (isset($data->{'picture-url'})) { - $this->user->profile->photoURL = (string) $data->{'picture-url'}; - - } elseif (isset($data->{'picture-urls'})) { - // picture-urls::(original) - $this->user->profile->photoURL = (string) $data->{'picture-urls'}->{'picture-url'}; - - } else { - $this->user->profile->photoURL = ""; - } - - $this->user->profile->profileURL = (string) $data->{'public-profile-url'}; - $this->user->profile->description = (string) $data->{'summary'}; - - if ($data->{'phone-numbers'} && $data->{'phone-numbers'}->{'phone-number'}) { - $this->user->profile->phone = (string) $data->{'phone-numbers'}->{'phone-number'}->{'phone-number'}; - } else { - $this->user->profile->phone = null; - } - - if ($data->{'date-of-birth'}) { - $this->user->profile->birthDay = (string) $data->{'date-of-birth'}->day; - $this->user->profile->birthMonth = (string) $data->{'date-of-birth'}->month; - $this->user->profile->birthYear = (string) $data->{'date-of-birth'}->year; - } - - return $this->user->profile; - } else { - throw new Exception("User profile request failed! {$this->providerId} returned an invalid response: " . Hybrid_Logger::dumpData( $response ), 6); - } - } - - /** - * {@inheritdoc} - */ - function getUserContacts() { - try { - $response = $this->api->profile('~/connections:(id,first-name,last-name,picture-url,public-profile-url,summary)'); - } catch (LinkedInException $e) { - throw new Exception("User contacts request failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); - } - - if (!$response || !$response['success']) { - return array(); - } - - $connections = new SimpleXMLElement($response['linkedin']); - - $contacts = array(); - - foreach ($connections->person as $connection) { - $uc = new Hybrid_User_Contact(); - - $uc->identifier = (string) $connection->id; - $uc->displayName = (string) $connection->{'last-name'} . " " . $connection->{'first-name'}; - $uc->profileURL = (string) $connection->{'public-profile-url'}; - $uc->photoURL = (string) $connection->{'picture-url'}; - $uc->description = (string) $connection->{'summary'}; - - $contacts[] = $uc; - } - - return $contacts; - } - - /** - * {@inheritdoc} - */ - function setUserStatus($status) { - $parameters = array(); - $private = true; // share with your connections only - - if (is_array($status)) { - if (isset($status[0]) && !empty($status[0])) - $parameters["title"] = $status[0]; // post title - if (isset($status[1]) && !empty($status[1])) - $parameters["comment"] = $status[1]; // post comment - if (isset($status[2]) && !empty($status[2])) - $parameters["submitted-url"] = $status[2]; // post url - if (isset($status[3]) && !empty($status[3])) - $parameters["submitted-image-url"] = $status[3]; // post picture url - if (isset($status[4]) && !empty($status[4])) - $private = $status[4]; // true or false - } - else { - $parameters["comment"] = $status; - } - - try { - $response = $this->api->share('new', $parameters, $private); - } catch (LinkedInException $e) { - throw new Exception("Update user status update failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); - } - - if (!$response || !$response['success']) { - throw new Exception("Update user status update failed! {$this->providerId} returned an error in response: " . Hybrid_Logger::dumpData( $response )); - } - - return $response; - } - - /** - * load the user latest activity - * - timeline : all the stream - * - me : the user activity only - * {@inheritdoc} - */ - function getUserActivity($stream) { - try { - if ($stream == "me") { - $response = $this->api->updates('?type=SHAR&scope=self&count=25'); - } else { - $response = $this->api->updates('?type=SHAR&count=25'); - } - } catch (LinkedInException $e) { - throw new Exception("User activity stream request failed! {$this->providerId} returned an error: {$e->getMessage()}", 0, $e); - } - - if (!$response || !$response['success']) { - return array(); - } - - $updates = new SimpleXMLElement($response['linkedin']); - - $activities = array(); - - foreach ($updates->update as $update) { - $person = $update->{'update-content'}->person; - $share = $update->{'update-content'}->person->{'current-share'}; - - $ua = new Hybrid_User_Activity(); - - $ua->id = (string) $update->id; - $ua->date = (string) $update->timestamp; - $ua->text = (string) $share->{'comment'}; - - $ua->user->identifier = (string) $person->id; - $ua->user->displayName = (string) $person->{'first-name'} . ' ' . $person->{'last-name'}; - $ua->user->profileURL = (string) $person->{'site-standard-profile-request'}->url; - $ua->user->photoURL = null; - - $activities[] = $ua; - } - - return $activities; - } + case "token": + $this->api->curl_header = array_merge( + $this->api->curl_header, + array( + "Content-Type: application/x-www-form-urlencoded", + ) + ); + break; + } + } } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Live.php b/e107_handlers/hybridauth/Hybrid/Providers/Live.php index 8468a20e5..0cc295161 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Live.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Live.php @@ -9,7 +9,7 @@ /** * Windows Live OAuth2 Class * - * @package HybridAuth providers package + * @package HybridAuth providers package * @author Lukasz Koprowski * @version 0.2 * @license BSD License @@ -23,7 +23,7 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 { /** * {@inheritdoc} */ - public $scope = "wl.basic wl.contacts_emails wl.emails wl.signin wl.share wl.birthday"; + public $scope = 'wl.basic wl.contacts_emails wl.emails wl.signin wl.share wl.birthday'; /** * {@inheritdoc} @@ -35,8 +35,6 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 { $this->api->api_base_url = 'https://apis.live.net/v5.0/'; $this->api->authorize_url = 'https://login.live.com/oauth20_authorize.srf'; $this->api->token_url = 'https://login.live.com/oauth20_token.srf'; - - $this->api->curl_authenticate_method = "GET"; } /** @@ -59,7 +57,7 @@ class Hybrid_Providers_Live extends Hybrid_Provider_Model_OAuth2 { $this->user->profile->profileURL = (property_exists($data, 'link')) ? $data->link : ""; //wl.emails - $this->user->profile->email = (property_exists($data, 'emails')) ? $data->emails->account : ""; + $this->user->profile->email = (property_exists($data, 'emails')) ? $data->emails->preferred : ""; $this->user->profile->emailVerified = (property_exists($data, 'emails')) ? $data->emails->account : ""; //wl.birthday diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php b/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php index dad718f3f..6ea623134 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Twitter.php @@ -131,7 +131,8 @@ class Hybrid_Providers_Twitter extends Hybrid_Provider_Model_OAuth1 { $this->user->profile->webSiteURL = (property_exists($response, 'url')) ? $response->url : ""; $this->user->profile->region = (property_exists($response, 'location')) ? $response->location : ""; if($includeEmail) $this->user->profile->email = (property_exists($response, 'email')) ? $response->email : ""; - + if($includeEmail) $this->user->profile->emailVerified = (property_exists($response, 'email')) ? $response->email : ""; + return $this->user->profile; } diff --git a/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php b/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php index 35911c297..81c48285f 100644 --- a/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php +++ b/e107_handlers/hybridauth/Hybrid/Providers/Yahoo.php @@ -7,270 +7,263 @@ */ /** - * Yahoo OAuth Class - * - * @package HybridAuth providers package - * @author Lukasz Koprowski - * @version 0.2 - * @license BSD License + * Yahoo OAuth Class. + * + * @package HybridAuth providers package + * @author Lukasz Koprowski + * @author Oleg Kuzava + * @version 1.0 + * @license BSD License */ /** - * Hybrid_Providers_Yahoo - Yahoo provider adapter based on OAuth1 protocol + * Hybrid_Providers_Yahoo - Yahoo provider adapter based on OAuth2 protocol. */ -class Hybrid_Providers_Yahoo extends Hybrid_Provider_Model_OAuth1 { +class Hybrid_Providers_Yahoo extends Hybrid_Provider_Model_OAuth2 { - /** - * {@inheritdoc} - */ - function initialize() { - parent::initialize(); + /** + * Define Yahoo scopes. + * + * @var array $scope + * If empty will be used YDN App scopes. + * @see https://developer.yahoo.com/oauth2/guide/yahoo_scopes. + */ + public $scope = []; - // Provider api end-points - $this->api->api_base_url = 'https://social.yahooapis.com/v1/'; - $this->api->authorize_url = 'https://api.login.yahoo.com/oauth/v2/request_auth'; - $this->api->request_token_url = 'https://api.login.yahoo.com/oauth/v2/get_request_token'; - $this->api->access_token_url = 'https://api.login.yahoo.com/oauth/v2/get_token'; - } + /** + * {@inheritdoc} + */ + function initialize() { + parent::initialize(); - /** - * {@inheritdoc} - */ - function getUserProfile() { - $userId = $this->getCurrentUserId(); + // Provider api end-points. + $this->api->api_base_url = "https://social.yahooapis.com/v1/"; + $this->api->authorize_url = "https://api.login.yahoo.com/oauth2/request_auth"; + $this->api->token_url = "https://api.login.yahoo.com/oauth2/get_token"; - $parameters = array(); - $parameters['format'] = 'json'; + // Set token headers. + $this->setAuthorizationHeaders("basic"); + } - $response = $this->api->get('user/' . $userId . '/profile', $parameters); + /** + * {@inheritdoc} + */ + function loginBegin() { + if (is_array($this->scope)) { + $this->scope = implode(",", $this->scope); + } + parent::loginBegin(); + } - if (!isset($response->profile)) { - throw new Exception("User profile request failed! {$this->providerId} returned an invalid response: " . Hybrid_Logger::dumpData( $response ), 6); - } + /** + * {@inheritdoc} + */ + function getUserProfile() { + $userId = $this->getCurrentUserId(); - $data = $response->profile; + $response = $this->api->get("user/{$userId}/profile", array( + "format" => "json", + )); - $this->user->profile->identifier = (property_exists($data, 'guid')) ? $data->guid : ""; - $this->user->profile->firstName = (property_exists($data, 'givenName')) ? $data->givenName : ""; - $this->user->profile->lastName = (property_exists($data, 'familyName')) ? $data->familyName : ""; - $this->user->profile->displayName = (property_exists($data, 'nickname')) ? trim($data->nickname) : ""; - $this->user->profile->profileURL = (property_exists($data, 'profileUrl')) ? $data->profileUrl : ""; - $this->user->profile->gender = (property_exists($data, 'gender')) ? $data->gender : ""; + if (!isset($response->profile)) { + throw new Exception("User profile request failed! {$this->providerId} returned an invalid response: " . Hybrid_Logger::dumpData($response), 6); + } - if ($this->user->profile->gender == "F") { - $this->user->profile->gender = "female"; - } + $data = $response->profile; - if ($this->user->profile->gender == "M") { - $this->user->profile->gender = "male"; - } + $this->user->profile->identifier = isset($data->guid) ? $data->guid : ""; + $this->user->profile->firstName = isset($data->givenName) ? $data->givenName : ""; + $this->user->profile->lastName = isset($data->familyName) ? $data->familyName : ""; + $this->user->profile->displayName = isset($data->nickname) ? trim($data->nickname) : ""; + $this->user->profile->profileURL = isset($data->profileUrl) ? $data->profileUrl : ""; + $this->user->profile->gender = isset($data->gender) ? $data->gender : ""; - if (isset($data->emails)) { - $email = ""; - foreach ($data->emails as $v) { - if (isset($v->primary) && $v->primary) { - $email = (property_exists($v, 'handle')) ? $v->handle : ""; + if ($this->user->profile->gender === "F") { + $this->user->profile->gender = "female"; + } + elseif ($this->user->profile->gender === "M") { + $this->user->profile->gender = "male"; + } - break; - } - } + if (isset($data->emails)) { + $email = ""; + foreach ($data->emails as $v) { + if (isset($v->primary) && $v->primary) { + $email = isset($v->handle) ? $v->handle : ""; + break; + } + } + $this->user->profile->email = $email; + $this->user->profile->emailVerified = $email; + } - $this->user->profile->email = $email; - $this->user->profile->emailVerified = $email; - } + $this->user->profile->age = isset($data->displayAge) ? $data->displayAge : ""; + $this->user->profile->photoURL = isset($data->image) ? $data->image->imageUrl : ""; - $this->user->profile->age = (property_exists($data, 'displayAge')) ? $data->displayAge : ""; - $this->user->profile->photoURL = (property_exists($data, 'image')) ? $data->image->imageUrl : ""; + $this->user->profile->address = isset($data->location) ? $data->location : ""; + $this->user->profile->language = isset($data->lang) ? $data->lang : ""; - $this->user->profile->address = (property_exists($data, 'location')) ? $data->location : ""; - $this->user->profile->language = (property_exists($data, 'lang')) ? $data->lang : ""; + return $this->user->profile; + } - return $this->user->profile; - } + /** + * {@inheritdoc} + */ + function getUserContacts() { + $userId = $this->getCurrentUserId(); - /** - * {@inheritdoc} - */ - function getUserContacts() { - $userId = $this->getCurrentUserId(); + $response = $this->api->get("user/{$userId}/contacts", array( + "format" => "json", + "count" => "max", + )); - $parameters = array(); - $parameters['format'] = 'json'; - $parameters['count'] = 'max'; + if ($this->api->http_code != 200) { + throw new Exception("User contacts request failed! {$this->providerId} returned an error: " . $this->errorMessageByStatus()); + } - $response = $this->api->get('user/' . $userId . '/contacts', $parameters); + if (!isset($response->contacts) || !isset($response->contacts->contact) || (isset($response->errcode) && $response->errcode != 0)) { + return array(); + } - if ($this->api->http_code != 200) { - throw new Exception('User contacts request failed! ' . $this->providerId . ' returned an error: ' . $this->errorMessageByStatus($this->api->http_code)); - } + $contacts = array(); + foreach ($response->contacts->contact as $item) { + $uc = new Hybrid_User_Contact(); - if (!isset($response->contacts) || !isset($response->contacts->contact) || ( isset($response->errcode) && $response->errcode != 0 )) { - return array(); - } + $uc->identifier = isset($item->id) ? $item->id : ""; + $uc->email = $this->selectEmail($item->fields); + $uc->displayName = $this->selectName($item->fields); + $uc->photoURL = $this->selectPhoto($item->fields); - $contacts = array(); + $contacts[] = $uc; + } - foreach ($response->contacts->contact as $item) { - $uc = new Hybrid_User_Contact(); + return $contacts; + } - $uc->identifier = $this->selectGUID($item); - $uc->email = $this->selectEmail($item->fields); - $uc->displayName = $this->selectName($item->fields); - $uc->photoURL = $this->selectPhoto($item->fields); + /** + * Returns current user id. + * + * @return string + * Current user ID. + * @throws Exception + */ + function getCurrentUserId() { + // Set headers to get refresh token. + $this->setAuthorizationHeaders("basic"); - $contacts[] = $uc; - } + // Refresh tokens if needed. + $this->refreshToken(); - return $contacts; - } + // Set headers to make api call. + $this->setAuthorizationHeaders("bearer"); - /** - * {@inheritdoc} - */ - function getUserActivity($stream) { - $userId = $this->getCurrentUserId(); + $response = $this->api->get("me/guid", array( + "format" => "json", + )); - $parameters = array(); - $parameters['format'] = 'json'; - $parameters['count'] = 'max'; + if (!isset($response->guid->value)) { + throw new Exception("User id request failed! {$this->providerId} returned an invalid response: " . Hybrid_Logger::dumpData($response)); + } - $response = $this->api->get('user/' . $userId . '/updates', $parameters); + return $response->guid->value; + } - if (!$response->updates || $this->api->http_code != 200) { - throw new Exception('User activity request failed! ' . $this->providerId . ' returned an error: ' . $this->errorMessageByStatus($this->api->http_code)); - } + /** + * Utility function for returning values from XML-like objects. + * + * @param stdClass $vs + * Object. + * @param string $t + * Property name. + * @return mixed + */ + private function select($vs, $t) { + foreach ($vs as $v) { + if ($v->type == $t) { + return $v; + } + } - $activities = array(); + return null; + } - foreach ($response->updates as $item) { - $ua = new Hybrid_User_Activity(); + /** + * Parses user name. + * + * @param stdClass $v + * Object. + * @return string + * User name. + */ + private function selectName($v) { + $s = $this->select($v, "name"); + if (!$s) { + $s = $this->select($v, "nickname"); + return isset($s->value) ? $s->value : ""; + } + return isset($s->value) ? "{$s->value->givenName} {$s->value->familyName}" : ""; + } - $ua->id = (property_exists($item, 'collectionID')) ? $item->collectionID : ""; - $ua->date = (property_exists($item, 'lastUpdated')) ? $item->lastUpdated : ""; - $ua->text = (property_exists($item, 'loc_longForm')) ? $item->loc_longForm : ""; + /** + * Parses photo URL. + * + * @param stdClass $v + * Object. + * @return string + * Photo URL. + */ + private function selectPhoto($v) { + $s = $this->select($v, "image"); - $ua->user->identifier = (property_exists($item, 'profile_guid')) ? $item->profile_guid : ""; - $ua->user->displayName = (property_exists($item, 'profile_nickname')) ? $item->profile_nickname : ""; - $ua->user->profileURL = (property_exists($item, 'profile_profileUrl')) ? $item->profile_profileUrl : ""; - $ua->user->photoURL = (property_exists($item, 'profile_displayImage')) ? $item->profile_displayImage : ""; + return isset($s->value) ? $s->value->imageUrl : ""; + } - $activities[] = $ua; - } + /** + * Parses email. + * + * @param stdClass $v + * Object + * @return string + * An email address. + */ + private function selectEmail($v) { + $s = $this->select($v, "email"); + if (empty($s)) { + $s = $this->select($v, "yahooid"); + if (isset($s->value) && strpos($s->value, "@") === FALSE) { + $s->value .= "@yahoo.com"; + } + } - if ($stream == "me") { - $userId = $this->getCurrentUserId(); - $my_activities = array(); + return isset($s->value) ? $s->value : ""; + } - foreach ($activities as $a) { - if ($a->user->identifier == $userId) { - $my_activities[] = $a; - } - } + /** + * Set correct Authorization headers. + * + * @param string $token_type + * Specify token type. + * + * @return void + */ + private function setAuthorizationHeaders($token_type) { + switch ($token_type) { + case "basic": + // The /get_token requires authorization header. + $token = base64_encode("{$this->config["keys"]["id"]}:{$this->config["keys"]["secret"]}"); + $this->api->curl_header = array( + "Authorization: Basic {$token}", + "Content-Type: application/x-www-form-urlencoded", + ); + break; - return $my_activities; - } - - return $activities; - } - - /** - * Utility function for returning values from XML-like objects - * - * @param stdClass $vs Object - * @param string $t Property name - * @return mixed - */ - function select($vs, $t) { - foreach ($vs as $v) { - if ($v->type == $t) { - return $v; - } - } - return null; - } - - /** - * Parses guid - * - * @param stdClass $v Object - * @return string - */ - function selectGUID($v) { - return (property_exists($v, 'id')) ? $v->id : ""; - } - - /** - * Parses user name - * - * @param stdClass $v Object - * @return string - */ - function selectName($v) { - $s = $this->select($v, 'name'); - - if (!$s) { - $s = $this->select($v, 'nickname'); - return ($s) ? $s->value : ""; - } else { - return ($s) ? $s->value->givenName . " " . $s->value->familyName : ""; - } - } - - /** - * Parses nickname - * - * @param stdClass $v Object - * @return string - */ - function selectNickame($v) { - $s = $this->select($v, 'nickname'); - return ($s) ? $s : ""; - } - - /** - * Parses photo URL - * - * @param stdClass $v Object - * @return string - */ - function selectPhoto($v) { - $s = $this->select($v, 'guid'); - return ($s) ? (property_exists($s, 'image')) : ""; - } - - /** - * Parses email - * - * @param stdClass $v Object - * @return string - */ - function selectEmail($v) { - $s = $this->select($v, 'email'); - if (empty($s)) { - $s = $this->select($v, 'yahooid'); - if (!empty($s) && isset($s->value) && strpos($s->value, "@") === false) - $s->value .= "@yahoo.com"; - } - return ($s) ? $s->value : ""; - } - - /** - * Returns current user id - * - * @return int - * @throws Exception - */ - public function getCurrentUserId() { - $parameters = array(); - $parameters['format'] = 'json'; - - $response = $this->api->get('me/guid', $parameters); - - if (!isset($response->guid->value)) { - throw new Exception("User id request failed! {$this->providerId} returned an invalid response: " . Hybrid_Logger::dumpData( $response )); - } - - return $response->guid->value; - } + case "bearer": + // Yahoo API requires the token to be passed as a Bearer within the authorization header. + $this->api->curl_header = array( + "Authorization: Bearer {$this->api->access_token}", + ); + break; + } + } } diff --git a/e107_handlers/hybridauth/Hybrid/User_Profile.php b/e107_handlers/hybridauth/Hybrid/User_Profile.php index 6a4070cd6..403be89c2 100644 --- a/e107_handlers/hybridauth/Hybrid/User_Profile.php +++ b/e107_handlers/hybridauth/Hybrid/User_Profile.php @@ -149,4 +149,15 @@ class Hybrid_User_Profile { */ public $zip = null; + /** + * Job title + * @var string + */ + public $job_title = null; + + /** + * Organization name + * @var string + */ + public $organization_name = null; } diff --git a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php index c9bc769d0..0046d2c58 100644 --- a/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php +++ b/e107_handlers/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php @@ -207,8 +207,10 @@ class OAuth2Client Hybrid_Logger::info( "Enter OAuth2Client::request( $url )" ); Hybrid_Logger::debug( "OAuth2Client::request(). dump request params: ", serialize( $params ) ); + $urlEncodedParams = http_build_query($params, '', '&'); + if( $type == "GET" ){ - $url = $url . ( strpos( $url, '?' ) ? '&' : '?' ) . http_build_query($params, '', '&'); + $url = $url . ( strpos( $url, '?' ) ? '&' : '?' ) . $urlEncodedParams; } $this->http_info = array(); @@ -231,10 +233,22 @@ class OAuth2Client curl_setopt( $ch, CURLOPT_PROXY , $this->curl_proxy); } - if( $type == "POST" ){ + if ($type == "POST") { curl_setopt($ch, CURLOPT_POST, 1); - if($params) curl_setopt( $ch, CURLOPT_POSTFIELDS, $params ); + + // If request body exists then encode it for "application/json". + if (isset($params['body'])) { + $urlEncodedParams = json_encode($params['body']); + } + + // Using URL encoded params here instead of a more convenient array + // cURL will set a wrong HTTP Content-Type header if using an array (cf. http://www.php.net/manual/en/function.curl-setopt.php, Notes section for "CURLOPT_POSTFIELDS") + // OAuth requires application/x-www-form-urlencoded Content-Type (cf. https://tools.ietf.org/html/rfc6749#section-2.3.1) + if ($params) { + curl_setopt($ch, CURLOPT_POSTFIELDS, $urlEncodedParams); + } } + if( $type == "DELETE" ){ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE"); } diff --git a/e107_handlers/hybridauth/index.php b/e107_handlers/hybridauth/index.php index 10b79c150..b067c8d4d 100644 --- a/e107_handlers/hybridauth/index.php +++ b/e107_handlers/hybridauth/index.php @@ -11,5 +11,6 @@ require_once("../../class2.php"); require_once( "Hybrid/Auth.php" ); require_once( "Hybrid/Endpoint.php" ); +require_once("vendor/autoload.php"); Hybrid_Endpoint::process(); diff --git a/e107_handlers/hybridauth/vendor/autoload.php b/e107_handlers/hybridauth/vendor/autoload.php new file mode 100644 index 000000000..898e41021 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + + private $classMapAuthoritative = false; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative) { + return false; + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if ($file === null && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if ($file === null) { + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/e107_handlers/hybridauth/vendor/composer/LICENSE b/e107_handlers/hybridauth/vendor/composer/LICENSE new file mode 100644 index 000000000..1a2812488 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) 2016 Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/e107_handlers/hybridauth/vendor/composer/autoload_classmap.php b/e107_handlers/hybridauth/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..22f9d3703 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/autoload_classmap.php @@ -0,0 +1,48 @@ + $baseDir . '/hybridauth/Hybrid/Auth.php', + 'Hybrid_Endpoint' => $baseDir . '/hybridauth/Hybrid/Endpoint.php', + 'Hybrid_Error' => $baseDir . '/hybridauth/Hybrid/Error.php', + 'Hybrid_Exception' => $baseDir . '/hybridauth/Hybrid/Exception.php', + 'Hybrid_Logger' => $baseDir . '/hybridauth/Hybrid/Logger.php', + 'Hybrid_Provider_Adapter' => $baseDir . '/hybridauth/Hybrid/Provider_Adapter.php', + 'Hybrid_Provider_Model' => $baseDir . '/hybridauth/Hybrid/Provider_Model.php', + 'Hybrid_Provider_Model_OAuth1' => $baseDir . '/hybridauth/Hybrid/Provider_Model_OAuth1.php', + 'Hybrid_Provider_Model_OAuth2' => $baseDir . '/hybridauth/Hybrid/Provider_Model_OAuth2.php', + 'Hybrid_Provider_Model_OpenID' => $baseDir . '/hybridauth/Hybrid/Provider_Model_OpenID.php', + 'Hybrid_Providers_AOL' => $baseDir . '/hybridauth/Hybrid/Providers/AOL.php', + 'Hybrid_Providers_Facebook' => $baseDir . '/hybridauth/Hybrid/Providers/Facebook.php', + 'Hybrid_Providers_Foursquare' => $baseDir . '/hybridauth/Hybrid/Providers/Foursquare.php', + 'Hybrid_Providers_Google' => $baseDir . '/hybridauth/Hybrid/Providers/Google.php', + 'Hybrid_Providers_LinkedIn' => $baseDir . '/hybridauth/Hybrid/Providers/LinkedIn.php', + 'Hybrid_Providers_Live' => $baseDir . '/hybridauth/Hybrid/Providers/Live.php', + 'Hybrid_Providers_OpenID' => $baseDir . '/hybridauth/Hybrid/Providers/OpenID.php', + 'Hybrid_Providers_Twitter' => $baseDir . '/hybridauth/Hybrid/Providers/Twitter.php', + 'Hybrid_Providers_Yahoo' => $baseDir . '/hybridauth/Hybrid/Providers/Yahoo.php', + 'Hybrid_Storage' => $baseDir . '/hybridauth/Hybrid/Storage.php', + 'Hybrid_Storage_Interface' => $baseDir . '/hybridauth/Hybrid/StorageInterface.php', + 'Hybrid_User' => $baseDir . '/hybridauth/Hybrid/User.php', + 'Hybrid_User_Activity' => $baseDir . '/hybridauth/Hybrid/User_Activity.php', + 'Hybrid_User_Contact' => $baseDir . '/hybridauth/Hybrid/User_Contact.php', + 'Hybrid_User_Profile' => $baseDir . '/hybridauth/Hybrid/User_Profile.php', + 'LightOpenID' => $baseDir . '/hybridauth/Hybrid/thirdparty/OpenID/LightOpenID.php', + 'OAuth1Client' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth1Client.php', + 'OAuth2Client' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth2Client.php', + 'OAuthConsumer' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthDataStore' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthException' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthRequest' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthServer' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthSignatureMethod' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthSignatureMethod_HMAC_SHA1' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthSignatureMethod_PLAINTEXT' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthSignatureMethod_RSA_SHA1' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthToken' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', + 'OAuthUtil' => $baseDir . '/hybridauth/Hybrid/thirdparty/OAuth/OAuth.php', +); diff --git a/e107_handlers/hybridauth/vendor/composer/autoload_files.php b/e107_handlers/hybridauth/vendor/composer/autoload_files.php new file mode 100644 index 000000000..8099fae85 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/autoload_files.php @@ -0,0 +1,10 @@ + $vendorDir . '/facebook/graph-sdk/src/Facebook/polyfills.php', +); diff --git a/e107_handlers/hybridauth/vendor/composer/autoload_namespaces.php b/e107_handlers/hybridauth/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..08230cfac --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/autoload_namespaces.php @@ -0,0 +1,10 @@ + array($baseDir . '/hybridauth'), +); diff --git a/e107_handlers/hybridauth/vendor/composer/autoload_psr4.php b/e107_handlers/hybridauth/vendor/composer/autoload_psr4.php new file mode 100644 index 000000000..a5309cfb1 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/autoload_psr4.php @@ -0,0 +1,10 @@ + array($vendorDir . '/facebook/graph-sdk/src/Facebook'), +); diff --git a/e107_handlers/hybridauth/vendor/composer/autoload_real.php b/e107_handlers/hybridauth/vendor/composer/autoload_real.php new file mode 100644 index 000000000..7cad38888 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/autoload_real.php @@ -0,0 +1,59 @@ + $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + $includeFiles = require __DIR__ . '/autoload_files.php'; + foreach ($includeFiles as $fileIdentifier => $file) { + composerRequire511ca3f38d99caa04d5c2a22fdfca775($fileIdentifier, $file); + } + + return $loader; + } +} + +function composerRequire511ca3f38d99caa04d5c2a22fdfca775($fileIdentifier, $file) +{ + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + require $file; + + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + } +} diff --git a/e107_handlers/hybridauth/vendor/composer/installed.json b/e107_handlers/hybridauth/vendor/composer/installed.json new file mode 100644 index 000000000..f3b5896e2 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/composer/installed.json @@ -0,0 +1,62 @@ +[ + { + "name": "facebook/graph-sdk", + "version": "5.6.1", + "version_normalized": "5.6.1.0", + "source": { + "type": "git", + "url": "https://github.com/facebook/php-graph-sdk.git", + "reference": "2f9639c15ae043911f40ffe44080b32bac2c5280" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facebook/php-graph-sdk/zipball/2f9639c15ae043911f40ffe44080b32bac2c5280", + "reference": "2f9639c15ae043911f40ffe44080b32bac2c5280", + "shasum": "" + }, + "require": { + "php": "^5.4|^7.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "~5.0", + "mockery/mockery": "~0.8", + "phpunit/phpunit": "~4.0" + }, + "suggest": { + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client", + "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5" + }, + "time": "2017-08-16 17:28:07", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Facebook\\": "src/Facebook/" + }, + "files": [ + "src/Facebook/polyfills.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Facebook Platform" + ], + "authors": [ + { + "name": "Facebook", + "homepage": "https://github.com/facebook/php-graph-sdk/contributors" + } + ], + "description": "Facebook SDK for PHP", + "homepage": "https://github.com/facebook/php-graph-sdk", + "keywords": [ + "facebook", + "sdk" + ] + } +] diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/LICENSE b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/LICENSE new file mode 100644 index 000000000..8b93109ab --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/LICENSE @@ -0,0 +1,19 @@ +Copyright 2017 Facebook, Inc. + +You are hereby granted a non-exclusive, worldwide, royalty-free license to +use, copy, modify, and distribute this software in source code or binary +form for use in connection with the web services and APIs provided by +Facebook. + +As with any software that integrates with the Facebook platform, your use +of this software is subject to the Facebook Developer Principles and +Policies [http://developers.facebook.com/policy/]. This copyright notice +shall be included in all copies or substantial portions of the software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/composer.json b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/composer.json new file mode 100644 index 000000000..9d54abc37 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/composer.json @@ -0,0 +1,42 @@ +{ + "name": "facebook/graph-sdk", + "description": "Facebook SDK for PHP", + "keywords": ["facebook", "sdk"], + "type": "library", + "homepage": "https://github.com/facebook/php-graph-sdk", + "license": "Facebook Platform", + "authors": [ + { + "name": "Facebook", + "homepage": "https://github.com/facebook/php-graph-sdk/contributors" + } + ], + "require": { + "php": "^5.4|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0", + "mockery/mockery": "~0.8", + "guzzlehttp/guzzle": "~5.0" + }, + "suggest": { + "paragonie/random_compat": "Provides a better CSPRNG option in PHP 5", + "guzzlehttp/guzzle": "Allows for implementation of the Guzzle HTTP client" + }, + "autoload": { + "psr-4": { + "Facebook\\": "src/Facebook/" + }, + "files": ["src/Facebook/polyfills.php"] + }, + "autoload-dev": { + "psr-4": { + "Facebook\\Tests\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/phpcs.xml.dist b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/phpcs.xml.dist new file mode 100644 index 000000000..96c56f886 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/phpcs.xml.dist @@ -0,0 +1,7 @@ + + + src/ + tests/ + + + diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php new file mode 100644 index 000000000..5d7007334 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessToken.php @@ -0,0 +1,160 @@ +value = $accessToken; + if ($expiresAt) { + $this->setExpiresAtFromTimeStamp($expiresAt); + } + } + + /** + * Generate an app secret proof to sign a request to Graph. + * + * @param string $appSecret The app secret. + * + * @return string + */ + public function getAppSecretProof($appSecret) + { + return hash_hmac('sha256', $this->value, $appSecret); + } + + /** + * Getter for expiresAt. + * + * @return \DateTime|null + */ + public function getExpiresAt() + { + return $this->expiresAt; + } + + /** + * Determines whether or not this is an app access token. + * + * @return bool + */ + public function isAppAccessToken() + { + return strpos($this->value, '|') !== false; + } + + /** + * Determines whether or not this is a long-lived token. + * + * @return bool + */ + public function isLongLived() + { + if ($this->expiresAt) { + return $this->expiresAt->getTimestamp() > time() + (60 * 60 * 2); + } + + if ($this->isAppAccessToken()) { + return true; + } + + return false; + } + + /** + * Checks the expiration of the access token. + * + * @return boolean|null + */ + public function isExpired() + { + if ($this->getExpiresAt() instanceof \DateTime) { + return $this->getExpiresAt()->getTimestamp() < time(); + } + + if ($this->isAppAccessToken()) { + return false; + } + + return null; + } + + /** + * Returns the access token as a string. + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the access token as a string. + * + * @return string + */ + public function __toString() + { + return $this->getValue(); + } + + /** + * Setter for expires_at. + * + * @param int $timeStamp + */ + protected function setExpiresAtFromTimeStamp($timeStamp) + { + $dt = new \DateTime(); + $dt->setTimestamp($timeStamp); + $this->expiresAt = $dt; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php new file mode 100644 index 000000000..165433cb6 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/AccessTokenMetadata.php @@ -0,0 +1,390 @@ +metadata = $metadata['data']; + + $this->castTimestampsToDateTime(); + } + + /** + * Returns a value from the metadata. + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getField($field, $default = null) + { + if (isset($this->metadata[$field])) { + return $this->metadata[$field]; + } + + return $default; + } + + /** + * Returns a value from the metadata. + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + * + * @deprecated 5.0.0 getProperty() has been renamed to getField() + * @todo v6: Remove this method + */ + public function getProperty($field, $default = null) + { + return $this->getField($field, $default); + } + + /** + * Returns a value from a child property in the metadata. + * + * @param string $parentField The parent property. + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getChildProperty($parentField, $field, $default = null) + { + if (!isset($this->metadata[$parentField])) { + return $default; + } + + if (!isset($this->metadata[$parentField][$field])) { + return $default; + } + + return $this->metadata[$parentField][$field]; + } + + /** + * Returns a value from the error metadata. + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getErrorProperty($field, $default = null) + { + return $this->getChildProperty('error', $field, $default); + } + + /** + * Returns a value from the "metadata" metadata. *Brain explodes* + * + * @param string $field The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + */ + public function getMetadataProperty($field, $default = null) + { + return $this->getChildProperty('metadata', $field, $default); + } + + /** + * The ID of the application this access token is for. + * + * @return string|null + */ + public function getAppId() + { + return $this->getField('app_id'); + } + + /** + * Name of the application this access token is for. + * + * @return string|null + */ + public function getApplication() + { + return $this->getField('application'); + } + + /** + * Any error that a request to the graph api + * would return due to the access token. + * + * @return bool|null + */ + public function isError() + { + return $this->getField('error') !== null; + } + + /** + * The error code for the error. + * + * @return int|null + */ + public function getErrorCode() + { + return $this->getErrorProperty('code'); + } + + /** + * The error message for the error. + * + * @return string|null + */ + public function getErrorMessage() + { + return $this->getErrorProperty('message'); + } + + /** + * The error subcode for the error. + * + * @return int|null + */ + public function getErrorSubcode() + { + return $this->getErrorProperty('subcode'); + } + + /** + * DateTime when this access token expires. + * + * @return \DateTime|null + */ + public function getExpiresAt() + { + return $this->getField('expires_at'); + } + + /** + * Whether the access token is still valid or not. + * + * @return boolean|null + */ + public function getIsValid() + { + return $this->getField('is_valid'); + } + + /** + * DateTime when this access token was issued. + * + * Note that the issued_at field is not returned + * for short-lived access tokens. + * + * @see https://developers.facebook.com/docs/facebook-login/access-tokens#debug + * + * @return \DateTime|null + */ + public function getIssuedAt() + { + return $this->getField('issued_at'); + } + + /** + * General metadata associated with the access token. + * Can contain data like 'sso', 'auth_type', 'auth_nonce'. + * + * @return array|null + */ + public function getMetadata() + { + return $this->getField('metadata'); + } + + /** + * The 'sso' child property from the 'metadata' parent property. + * + * @return string|null + */ + public function getSso() + { + return $this->getMetadataProperty('sso'); + } + + /** + * The 'auth_type' child property from the 'metadata' parent property. + * + * @return string|null + */ + public function getAuthType() + { + return $this->getMetadataProperty('auth_type'); + } + + /** + * The 'auth_nonce' child property from the 'metadata' parent property. + * + * @return string|null + */ + public function getAuthNonce() + { + return $this->getMetadataProperty('auth_nonce'); + } + + /** + * For impersonated access tokens, the ID of + * the page this token contains. + * + * @return string|null + */ + public function getProfileId() + { + return $this->getField('profile_id'); + } + + /** + * List of permissions that the user has granted for + * the app in this access token. + * + * @return array + */ + public function getScopes() + { + return $this->getField('scopes'); + } + + /** + * The ID of the user this access token is for. + * + * @return string|null + */ + public function getUserId() + { + return $this->getField('user_id'); + } + + /** + * Ensures the app ID from the access token + * metadata is what we expect. + * + * @param string $appId + * + * @throws FacebookSDKException + */ + public function validateAppId($appId) + { + if ($this->getAppId() !== $appId) { + throw new FacebookSDKException('Access token metadata contains unexpected app ID.', 401); + } + } + + /** + * Ensures the user ID from the access token + * metadata is what we expect. + * + * @param string $userId + * + * @throws FacebookSDKException + */ + public function validateUserId($userId) + { + if ($this->getUserId() !== $userId) { + throw new FacebookSDKException('Access token metadata contains unexpected user ID.', 401); + } + } + + /** + * Ensures the access token has not expired yet. + * + * @throws FacebookSDKException + */ + public function validateExpiration() + { + if (!$this->getExpiresAt() instanceof \DateTime) { + return; + } + + if ($this->getExpiresAt()->getTimestamp() < time()) { + throw new FacebookSDKException('Inspection of access token metadata shows that the access token has expired.', 401); + } + } + + /** + * Converts a unix timestamp into a DateTime entity. + * + * @param int $timestamp + * + * @return \DateTime + */ + private function convertTimestampToDateTime($timestamp) + { + $dt = new \DateTime(); + $dt->setTimestamp($timestamp); + + return $dt; + } + + /** + * Casts the unix timestamps as DateTime entities. + */ + private function castTimestampsToDateTime() + { + foreach (static::$dateProperties as $key) { + if (isset($this->metadata[$key]) && $this->metadata[$key] !== 0) { + $this->metadata[$key] = $this->convertTimestampToDateTime($this->metadata[$key]); + } + } + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php new file mode 100644 index 000000000..94df9b7b5 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Authentication/OAuth2Client.php @@ -0,0 +1,292 @@ +app = $app; + $this->client = $client; + $this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION; + } + + /** + * Returns the last FacebookRequest that was sent. + * Useful for debugging and testing. + * + * @return FacebookRequest|null + */ + public function getLastRequest() + { + return $this->lastRequest; + } + + /** + * Get the metadata associated with the access token. + * + * @param AccessToken|string $accessToken The access token to debug. + * + * @return AccessTokenMetadata + */ + public function debugToken($accessToken) + { + $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken; + $params = ['input_token' => $accessToken]; + + $this->lastRequest = new FacebookRequest( + $this->app, + $this->app->getAccessToken(), + 'GET', + '/debug_token', + $params, + null, + $this->graphVersion + ); + $response = $this->client->sendRequest($this->lastRequest); + $metadata = $response->getDecodedBody(); + + return new AccessTokenMetadata($metadata); + } + + /** + * Generates an authorization URL to begin the process of authenticating a user. + * + * @param string $redirectUrl The callback URL to redirect to. + * @param string $state The CSPRNG-generated CSRF value. + * @param array $scope An array of permissions to request. + * @param array $params An array of parameters to generate URL. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getAuthorizationUrl($redirectUrl, $state, array $scope = [], array $params = [], $separator = '&') + { + $params += [ + 'client_id' => $this->app->getId(), + 'state' => $state, + 'response_type' => 'code', + 'sdk' => 'php-sdk-' . Facebook::VERSION, + 'redirect_uri' => $redirectUrl, + 'scope' => implode(',', $scope) + ]; + + return static::BASE_AUTHORIZATION_URL . '/' . $this->graphVersion . '/dialog/oauth?' . http_build_query($params, null, $separator); + } + + /** + * Get a valid access token from a code. + * + * @param string $code + * @param string $redirectUri + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + public function getAccessTokenFromCode($code, $redirectUri = '') + { + $params = [ + 'code' => $code, + 'redirect_uri' => $redirectUri, + ]; + + return $this->requestAnAccessToken($params); + } + + /** + * Exchanges a short-lived access token with a long-lived access token. + * + * @param AccessToken|string $accessToken + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + public function getLongLivedAccessToken($accessToken) + { + $accessToken = $accessToken instanceof AccessToken ? $accessToken->getValue() : $accessToken; + $params = [ + 'grant_type' => 'fb_exchange_token', + 'fb_exchange_token' => $accessToken, + ]; + + return $this->requestAnAccessToken($params); + } + + /** + * Get a valid code from an access token. + * + * @param AccessToken|string $accessToken + * @param string $redirectUri + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + public function getCodeFromLongLivedAccessToken($accessToken, $redirectUri = '') + { + $params = [ + 'redirect_uri' => $redirectUri, + ]; + + $response = $this->sendRequestWithClientParams('/oauth/client_code', $params, $accessToken); + $data = $response->getDecodedBody(); + + if (!isset($data['code'])) { + throw new FacebookSDKException('Code was not returned from Graph.', 401); + } + + return $data['code']; + } + + /** + * Send a request to the OAuth endpoint. + * + * @param array $params + * + * @return AccessToken + * + * @throws FacebookSDKException + */ + protected function requestAnAccessToken(array $params) + { + $response = $this->sendRequestWithClientParams('/oauth/access_token', $params); + $data = $response->getDecodedBody(); + + if (!isset($data['access_token'])) { + throw new FacebookSDKException('Access token was not returned from Graph.', 401); + } + + // Graph returns two different key names for expiration time + // on the same endpoint. Doh! :/ + $expiresAt = 0; + if (isset($data['expires'])) { + // For exchanging a short lived token with a long lived token. + // The expiration time in seconds will be returned as "expires". + $expiresAt = time() + $data['expires']; + } elseif (isset($data['expires_in'])) { + // For exchanging a code for a short lived access token. + // The expiration time in seconds will be returned as "expires_in". + // See: https://developers.facebook.com/docs/facebook-login/access-tokens#long-via-code + $expiresAt = time() + $data['expires_in']; + } + + return new AccessToken($data['access_token'], $expiresAt); + } + + /** + * Send a request to Graph with an app access token. + * + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * + * @return FacebookResponse + * + * @throws FacebookResponseException + */ + protected function sendRequestWithClientParams($endpoint, array $params, $accessToken = null) + { + $params += $this->getClientParams(); + + $accessToken = $accessToken ?: $this->app->getAccessToken(); + + $this->lastRequest = new FacebookRequest( + $this->app, + $accessToken, + 'GET', + $endpoint, + $params, + null, + $this->graphVersion + ); + + return $this->client->sendRequest($this->lastRequest); + } + + /** + * Returns the client_* params for OAuth requests. + * + * @return array + */ + protected function getClientParams() + { + return [ + 'client_id' => $this->app->getId(), + 'client_secret' => $this->app->getSecret(), + ]; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php new file mode 100644 index 000000000..c5e45fa39 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookAuthenticationException.php @@ -0,0 +1,33 @@ +response = $response; + $this->responseData = $response->getDecodedBody(); + + $errorMessage = $this->get('message', 'Unknown error from Graph.'); + $errorCode = $this->get('code', -1); + + parent::__construct($errorMessage, $errorCode, $previousException); + } + + /** + * A factory for creating the appropriate exception based on the response from Graph. + * + * @param FacebookResponse $response The response that threw the exception. + * + * @return FacebookResponseException + */ + public static function create(FacebookResponse $response) + { + $data = $response->getDecodedBody(); + + if (!isset($data['error']['code']) && isset($data['code'])) { + $data = ['error' => $data]; + } + + $code = isset($data['error']['code']) ? $data['error']['code'] : null; + $message = isset($data['error']['message']) ? $data['error']['message'] : 'Unknown error from Graph.'; + + if (isset($data['error']['error_subcode'])) { + switch ($data['error']['error_subcode']) { + // Other authentication issues + case 458: + case 459: + case 460: + case 463: + case 464: + case 467: + return new static($response, new FacebookAuthenticationException($message, $code)); + // Video upload resumable error + case 1363030: + case 1363019: + case 1363037: + case 1363033: + case 1363021: + case 1363041: + return new static($response, new FacebookResumableUploadException($message, $code)); + } + } + + switch ($code) { + // Login status or token expired, revoked, or invalid + case 100: + case 102: + case 190: + return new static($response, new FacebookAuthenticationException($message, $code)); + + // Server issue, possible downtime + case 1: + case 2: + return new static($response, new FacebookServerException($message, $code)); + + // API Throttling + case 4: + case 17: + case 341: + return new static($response, new FacebookThrottleException($message, $code)); + + // Duplicate Post + case 506: + return new static($response, new FacebookClientException($message, $code)); + } + + // Missing Permissions + if ($code == 10 || ($code >= 200 && $code <= 299)) { + return new static($response, new FacebookAuthorizationException($message, $code)); + } + + // OAuth authentication error + if (isset($data['error']['type']) && $data['error']['type'] === 'OAuthException') { + return new static($response, new FacebookAuthenticationException($message, $code)); + } + + // All others + return new static($response, new FacebookOtherException($message, $code)); + } + + /** + * Checks isset and returns that or a default value. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + private function get($key, $default = null) + { + if (isset($this->responseData['error'][$key])) { + return $this->responseData['error'][$key]; + } + + return $default; + } + + /** + * Returns the HTTP status code + * + * @return int + */ + public function getHttpStatusCode() + { + return $this->response->getHttpStatusCode(); + } + + /** + * Returns the sub-error code + * + * @return int + */ + public function getSubErrorCode() + { + return $this->get('error_subcode', -1); + } + + /** + * Returns the error type + * + * @return string + */ + public function getErrorType() + { + return $this->get('type', ''); + } + + /** + * Returns the raw response used to create the exception. + * + * @return string + */ + public function getRawResponse() + { + return $this->response->getBody(); + } + + /** + * Returns the decoded response used to create the exception. + * + * @return array + */ + public function getResponseData() + { + return $this->responseData; + } + + /** + * Returns the response entity used to create the exception. + * + * @return FacebookResponse + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php new file mode 100644 index 000000000..6f4706623 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Exceptions/FacebookResumableUploadException.php @@ -0,0 +1,33 @@ + getenv(static::APP_ID_ENV_NAME), + 'app_secret' => getenv(static::APP_SECRET_ENV_NAME), + 'default_graph_version' => static::DEFAULT_GRAPH_VERSION, + 'enable_beta_mode' => false, + 'http_client_handler' => null, + 'persistent_data_handler' => null, + 'pseudo_random_string_generator' => null, + 'url_detection_handler' => null, + ], $config); + + if (!$config['app_id']) { + throw new FacebookSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"'); + } + if (!$config['app_secret']) { + throw new FacebookSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"'); + } + + $this->app = new FacebookApp($config['app_id'], $config['app_secret']); + $this->client = new FacebookClient( + HttpClientsFactory::createHttpClient($config['http_client_handler']), + $config['enable_beta_mode'] + ); + $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator( + $config['pseudo_random_string_generator'] + ); + $this->setUrlDetectionHandler($config['url_detection_handler'] ?: new FacebookUrlDetectionHandler()); + $this->persistentDataHandler = PersistentDataFactory::createPersistentDataHandler( + $config['persistent_data_handler'] + ); + + if (isset($config['default_access_token'])) { + $this->setDefaultAccessToken($config['default_access_token']); + } + + // @todo v6: Throw an InvalidArgumentException if "default_graph_version" is not set + $this->defaultGraphVersion = $config['default_graph_version']; + } + + /** + * Returns the FacebookApp entity. + * + * @return FacebookApp + */ + public function getApp() + { + return $this->app; + } + + /** + * Returns the FacebookClient service. + * + * @return FacebookClient + */ + public function getClient() + { + return $this->client; + } + + /** + * Returns the OAuth 2.0 client service. + * + * @return OAuth2Client + */ + public function getOAuth2Client() + { + if (!$this->oAuth2Client instanceof OAuth2Client) { + $app = $this->getApp(); + $client = $this->getClient(); + $this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion); + } + + return $this->oAuth2Client; + } + + /** + * Returns the last response returned from Graph. + * + * @return FacebookResponse|FacebookBatchResponse|null + */ + public function getLastResponse() + { + return $this->lastResponse; + } + + /** + * Returns the URL detection handler. + * + * @return UrlDetectionInterface + */ + public function getUrlDetectionHandler() + { + return $this->urlDetectionHandler; + } + + /** + * Changes the URL detection handler. + * + * @param UrlDetectionInterface $urlDetectionHandler + */ + private function setUrlDetectionHandler(UrlDetectionInterface $urlDetectionHandler) + { + $this->urlDetectionHandler = $urlDetectionHandler; + } + + /** + * Returns the default AccessToken entity. + * + * @return AccessToken|null + */ + public function getDefaultAccessToken() + { + return $this->defaultAccessToken; + } + + /** + * Sets the default access token to use with requests. + * + * @param AccessToken|string $accessToken The access token to save. + * + * @throws \InvalidArgumentException + */ + public function setDefaultAccessToken($accessToken) + { + if (is_string($accessToken)) { + $this->defaultAccessToken = new AccessToken($accessToken); + + return; + } + + if ($accessToken instanceof AccessToken) { + $this->defaultAccessToken = $accessToken; + + return; + } + + throw new \InvalidArgumentException('The default access token must be of type "string" or Facebook\AccessToken'); + } + + /** + * Returns the default Graph version. + * + * @return string + */ + public function getDefaultGraphVersion() + { + return $this->defaultGraphVersion; + } + + /** + * Returns the redirect login helper. + * + * @return FacebookRedirectLoginHelper + */ + public function getRedirectLoginHelper() + { + return new FacebookRedirectLoginHelper( + $this->getOAuth2Client(), + $this->persistentDataHandler, + $this->urlDetectionHandler, + $this->pseudoRandomStringGenerator + ); + } + + /** + * Returns the JavaScript helper. + * + * @return FacebookJavaScriptHelper + */ + public function getJavaScriptHelper() + { + return new FacebookJavaScriptHelper($this->app, $this->client, $this->defaultGraphVersion); + } + + /** + * Returns the canvas helper. + * + * @return FacebookCanvasHelper + */ + public function getCanvasHelper() + { + return new FacebookCanvasHelper($this->app, $this->client, $this->defaultGraphVersion); + } + + /** + * Returns the page tab helper. + * + * @return FacebookPageTabHelper + */ + public function getPageTabHelper() + { + return new FacebookPageTabHelper($this->app, $this->client, $this->defaultGraphVersion); + } + + /** + * Sends a GET request to Graph and returns the result. + * + * @param string $endpoint + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function get($endpoint, $accessToken = null, $eTag = null, $graphVersion = null) + { + return $this->sendRequest( + 'GET', + $endpoint, + $params = [], + $accessToken, + $eTag, + $graphVersion + ); + } + + /** + * Sends a POST request to Graph and returns the result. + * + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function post($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + return $this->sendRequest( + 'POST', + $endpoint, + $params, + $accessToken, + $eTag, + $graphVersion + ); + } + + /** + * Sends a DELETE request to Graph and returns the result. + * + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + return $this->sendRequest( + 'DELETE', + $endpoint, + $params, + $accessToken, + $eTag, + $graphVersion + ); + } + + /** + * Sends a request to Graph for the next page of results. + * + * @param GraphEdge $graphEdge The GraphEdge to paginate over. + * + * @return GraphEdge|null + * + * @throws FacebookSDKException + */ + public function next(GraphEdge $graphEdge) + { + return $this->getPaginationResults($graphEdge, 'next'); + } + + /** + * Sends a request to Graph for the previous page of results. + * + * @param GraphEdge $graphEdge The GraphEdge to paginate over. + * + * @return GraphEdge|null + * + * @throws FacebookSDKException + */ + public function previous(GraphEdge $graphEdge) + { + return $this->getPaginationResults($graphEdge, 'previous'); + } + + /** + * Sends a request to Graph for the next page of results. + * + * @param GraphEdge $graphEdge The GraphEdge to paginate over. + * @param string $direction The direction of the pagination: next|previous. + * + * @return GraphEdge|null + * + * @throws FacebookSDKException + */ + public function getPaginationResults(GraphEdge $graphEdge, $direction) + { + $paginationRequest = $graphEdge->getPaginationRequest($direction); + if (!$paginationRequest) { + return null; + } + + $this->lastResponse = $this->client->sendRequest($paginationRequest); + + // Keep the same GraphNode subclass + $subClassName = $graphEdge->getSubClassName(); + $graphEdge = $this->lastResponse->getGraphEdge($subClassName, false); + + return count($graphEdge) > 0 ? $graphEdge : null; + } + + /** + * Sends a request to Graph and returns the result. + * + * @param string $method + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + $request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion); + + return $this->lastResponse = $this->client->sendRequest($request); + } + + /** + * Sends a batched request to Graph and returns the result. + * + * @param array $requests + * @param AccessToken|string|null $accessToken + * @param string|null $graphVersion + * + * @return FacebookBatchResponse + * + * @throws FacebookSDKException + */ + public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + $batchRequest = new FacebookBatchRequest( + $this->app, + $requests, + $accessToken, + $graphVersion + ); + + return $this->lastResponse = $this->client->sendBatchRequest($batchRequest); + } + + /** + * Instantiates an empty FacebookBatchRequest entity. + * + * @param AccessToken|string|null $accessToken The top-level access token. Requests with no access token + * will fallback to this. + * @param string|null $graphVersion The Graph API version to use. + * @return FacebookBatchRequest + */ + public function newBatchRequest($accessToken = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + + return new FacebookBatchRequest( + $this->app, + [], + $accessToken, + $graphVersion + ); + } + + /** + * Instantiates a new FacebookRequest entity. + * + * @param string $method + * @param string $endpoint + * @param array $params + * @param AccessToken|string|null $accessToken + * @param string|null $eTag + * @param string|null $graphVersion + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + + return new FacebookRequest( + $this->app, + $accessToken, + $method, + $endpoint, + $params, + $eTag, + $graphVersion + ); + } + + /** + * Factory to create FacebookFile's. + * + * @param string $pathToFile + * + * @return FacebookFile + * + * @throws FacebookSDKException + */ + public function fileToUpload($pathToFile) + { + return new FacebookFile($pathToFile); + } + + /** + * Factory to create FacebookVideo's. + * + * @param string $pathToFile + * + * @return FacebookVideo + * + * @throws FacebookSDKException + */ + public function videoToUpload($pathToFile) + { + return new FacebookVideo($pathToFile); + } + + /** + * Upload a video in chunks. + * + * @param int $target The id of the target node before the /videos edge. + * @param string $pathToFile The full path to the file. + * @param array $metadata The metadata associated with the video file. + * @param string|null $accessToken The access token. + * @param int $maxTransferTries The max times to retry a failed upload chunk. + * @param string|null $graphVersion The Graph API version to use. + * + * @return array + * + * @throws FacebookSDKException + */ + public function uploadVideo($target, $pathToFile, $metadata = [], $accessToken = null, $maxTransferTries = 5, $graphVersion = null) + { + $accessToken = $accessToken ?: $this->defaultAccessToken; + $graphVersion = $graphVersion ?: $this->defaultGraphVersion; + + $uploader = new FacebookResumableUploader($this->app, $this->client, $accessToken, $graphVersion); + $endpoint = '/'.$target.'/videos'; + $file = $this->videoToUpload($pathToFile); + $chunk = $uploader->start($endpoint, $file); + + do { + $chunk = $this->maxTriesTransfer($uploader, $endpoint, $chunk, $maxTransferTries); + } while (!$chunk->isLastChunk()); + + return [ + 'video_id' => $chunk->getVideoId(), + 'success' => $uploader->finish($endpoint, $chunk->getUploadSessionId(), $metadata), + ]; + } + + /** + * Attempts to upload a chunk of a file in $retryCountdown tries. + * + * @param FacebookResumableUploader $uploader + * @param string $endpoint + * @param FacebookTransferChunk $chunk + * @param int $retryCountdown + * + * @return FacebookTransferChunk + * + * @throws FacebookSDKException + */ + private function maxTriesTransfer(FacebookResumableUploader $uploader, $endpoint, FacebookTransferChunk $chunk, $retryCountdown) + { + $newChunk = $uploader->transfer($endpoint, $chunk, $retryCountdown < 1); + + if ($newChunk !== $chunk) { + return $newChunk; + } + + $retryCountdown--; + + // If transfer() returned the same chunk entity, the transfer failed but is resumable. + return $this->maxTriesTransfer($uploader, $endpoint, $chunk, $retryCountdown); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php new file mode 100644 index 000000000..804c9bb56 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookApp.php @@ -0,0 +1,110 @@ +id = (string) $id; + $this->secret = $secret; + } + + /** + * Returns the app ID. + * + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * Returns the app secret. + * + * @return string + */ + public function getSecret() + { + return $this->secret; + } + + /** + * Returns an app access token. + * + * @return AccessToken + */ + public function getAccessToken() + { + return new AccessToken($this->id . '|' . $this->secret); + } + + /** + * Serializes the FacebookApp entity as a string. + * + * @return string + */ + public function serialize() + { + return implode('|', [$this->id, $this->secret]); + } + + /** + * Unserializes a string as a FacebookApp entity. + * + * @param string $serialized + */ + public function unserialize($serialized) + { + list($id, $secret) = explode('|', $serialized); + + $this->__construct($id, $secret); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php new file mode 100644 index 000000000..3d5d5d563 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchRequest.php @@ -0,0 +1,322 @@ +add($requests); + } + + /** + * Adds a new request to the array. + * + * @param FacebookRequest|array $request + * @param string|null|array $options Array of batch request options e.g. 'name', 'omit_response_on_success'. + * If a string is given, it is the value of the 'name' option. + * + * @return FacebookBatchRequest + * + * @throws \InvalidArgumentException + */ + public function add($request, $options = null) + { + if (is_array($request)) { + foreach ($request as $key => $req) { + $this->add($req, $key); + } + + return $this; + } + + if (!$request instanceof FacebookRequest) { + throw new \InvalidArgumentException('Argument for add() must be of type array or FacebookRequest.'); + } + + if (null === $options) { + $options = []; + } elseif (!is_array($options)) { + $options = ['name' => $options]; + } + + $this->addFallbackDefaults($request); + + // File uploads + $attachedFiles = $this->extractFileAttachments($request); + + $name = isset($options['name']) ? $options['name'] : null; + + unset($options['name']); + + $requestToAdd = [ + 'name' => $name, + 'request' => $request, + 'options' => $options, + 'attached_files' => $attachedFiles, + ]; + + $this->requests[] = $requestToAdd; + + return $this; + } + + /** + * Ensures that the FacebookApp and access token fall back when missing. + * + * @param FacebookRequest $request + * + * @throws FacebookSDKException + */ + public function addFallbackDefaults(FacebookRequest $request) + { + if (!$request->getApp()) { + $app = $this->getApp(); + if (!$app) { + throw new FacebookSDKException('Missing FacebookApp on FacebookRequest and no fallback detected on FacebookBatchRequest.'); + } + $request->setApp($app); + } + + if (!$request->getAccessToken()) { + $accessToken = $this->getAccessToken(); + if (!$accessToken) { + throw new FacebookSDKException('Missing access token on FacebookRequest and no fallback detected on FacebookBatchRequest.'); + } + $request->setAccessToken($accessToken); + } + } + + /** + * Extracts the files from a request. + * + * @param FacebookRequest $request + * + * @return string|null + * + * @throws FacebookSDKException + */ + public function extractFileAttachments(FacebookRequest $request) + { + if (!$request->containsFileUploads()) { + return null; + } + + $files = $request->getFiles(); + $fileNames = []; + foreach ($files as $file) { + $fileName = uniqid(); + $this->addFile($fileName, $file); + $fileNames[] = $fileName; + } + + $request->resetFiles(); + + // @TODO Does Graph support multiple uploads on one endpoint? + return implode(',', $fileNames); + } + + /** + * Return the FacebookRequest entities. + * + * @return array + */ + public function getRequests() + { + return $this->requests; + } + + /** + * Prepares the requests to be sent as a batch request. + */ + public function prepareRequestsForBatch() + { + $this->validateBatchRequestCount(); + + $params = [ + 'batch' => $this->convertRequestsToJson(), + 'include_headers' => true, + ]; + $this->setParams($params); + } + + /** + * Converts the requests into a JSON(P) string. + * + * @return string + */ + public function convertRequestsToJson() + { + $requests = []; + foreach ($this->requests as $request) { + $options = []; + + if (null !== $request['name']) { + $options['name'] = $request['name']; + } + + $options += $request['options']; + + $requests[] = $this->requestEntityToBatchArray($request['request'], $options, $request['attached_files']); + } + + return json_encode($requests); + } + + /** + * Validate the request count before sending them as a batch. + * + * @throws FacebookSDKException + */ + public function validateBatchRequestCount() + { + $batchCount = count($this->requests); + if ($batchCount === 0) { + throw new FacebookSDKException('There are no batch requests to send.'); + } elseif ($batchCount > 50) { + // Per: https://developers.facebook.com/docs/graph-api/making-multiple-requests#limits + throw new FacebookSDKException('You cannot send more than 50 batch requests at a time.'); + } + } + + /** + * Converts a Request entity into an array that is batch-friendly. + * + * @param FacebookRequest $request The request entity to convert. + * @param string|null|array $options Array of batch request options e.g. 'name', 'omit_response_on_success'. + * If a string is given, it is the value of the 'name' option. + * @param string|null $attachedFiles Names of files associated with the request. + * + * @return array + */ + public function requestEntityToBatchArray(FacebookRequest $request, $options = null, $attachedFiles = null) + { + + if (null === $options) { + $options = []; + } elseif (!is_array($options)) { + $options = ['name' => $options]; + } + + $compiledHeaders = []; + $headers = $request->getHeaders(); + foreach ($headers as $name => $value) { + $compiledHeaders[] = $name . ': ' . $value; + } + + $batch = [ + 'headers' => $compiledHeaders, + 'method' => $request->getMethod(), + 'relative_url' => $request->getUrl(), + ]; + + // Since file uploads are moved to the root request of a batch request, + // the child requests will always be URL-encoded. + $body = $request->getUrlEncodedBody()->getBody(); + if ($body) { + $batch['body'] = $body; + } + + $batch += $options; + + if (null !== $attachedFiles) { + $batch['attached_files'] = $attachedFiles; + } + + return $batch; + } + + /** + * Get an iterator for the items. + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->requests); + } + + /** + * @inheritdoc + */ + public function offsetSet($offset, $value) + { + $this->add($value, $offset); + } + + /** + * @inheritdoc + */ + public function offsetExists($offset) + { + return isset($this->requests[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetUnset($offset) + { + unset($this->requests[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetGet($offset) + { + return isset($this->requests[$offset]) ? $this->requests[$offset] : null; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php new file mode 100644 index 000000000..8e1464c98 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookBatchResponse.php @@ -0,0 +1,174 @@ +batchRequest = $batchRequest; + + $request = $response->getRequest(); + $body = $response->getBody(); + $httpStatusCode = $response->getHttpStatusCode(); + $headers = $response->getHeaders(); + parent::__construct($request, $body, $httpStatusCode, $headers); + + $responses = $response->getDecodedBody(); + $this->setResponses($responses); + } + + /** + * Returns an array of FacebookResponse entities. + * + * @return array + */ + public function getResponses() + { + return $this->responses; + } + + /** + * The main batch response will be an array of requests so + * we need to iterate over all the responses. + * + * @param array $responses + */ + public function setResponses(array $responses) + { + $this->responses = []; + + foreach ($responses as $key => $graphResponse) { + $this->addResponse($key, $graphResponse); + } + } + + /** + * Add a response to the list. + * + * @param int $key + * @param array|null $response + */ + public function addResponse($key, $response) + { + $originalRequestName = isset($this->batchRequest[$key]['name']) ? $this->batchRequest[$key]['name'] : $key; + $originalRequest = isset($this->batchRequest[$key]['request']) ? $this->batchRequest[$key]['request'] : null; + + $httpResponseBody = isset($response['body']) ? $response['body'] : null; + $httpResponseCode = isset($response['code']) ? $response['code'] : null; + // @TODO With PHP 5.5 support, this becomes array_column($response['headers'], 'value', 'name') + $httpResponseHeaders = isset($response['headers']) ? $this->normalizeBatchHeaders($response['headers']) : []; + + $this->responses[$originalRequestName] = new FacebookResponse( + $originalRequest, + $httpResponseBody, + $httpResponseCode, + $httpResponseHeaders + ); + } + + /** + * @inheritdoc + */ + public function getIterator() + { + return new ArrayIterator($this->responses); + } + + /** + * @inheritdoc + */ + public function offsetSet($offset, $value) + { + $this->addResponse($offset, $value); + } + + /** + * @inheritdoc + */ + public function offsetExists($offset) + { + return isset($this->responses[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetUnset($offset) + { + unset($this->responses[$offset]); + } + + /** + * @inheritdoc + */ + public function offsetGet($offset) + { + return isset($this->responses[$offset]) ? $this->responses[$offset] : null; + } + + /** + * Converts the batch header array into a standard format. + * @TODO replace with array_column() when PHP 5.5 is supported. + * + * @param array $batchHeaders + * + * @return array + */ + private function normalizeBatchHeaders(array $batchHeaders) + { + $headers = []; + + foreach ($batchHeaders as $header) { + $headers[$header['name']] = $header['value']; + } + + return $headers; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php new file mode 100644 index 000000000..dbf759238 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookClient.php @@ -0,0 +1,250 @@ +httpClientHandler = $httpClientHandler ?: $this->detectHttpClientHandler(); + $this->enableBetaMode = $enableBeta; + } + + /** + * Sets the HTTP client handler. + * + * @param FacebookHttpClientInterface $httpClientHandler + */ + public function setHttpClientHandler(FacebookHttpClientInterface $httpClientHandler) + { + $this->httpClientHandler = $httpClientHandler; + } + + /** + * Returns the HTTP client handler. + * + * @return FacebookHttpClientInterface + */ + public function getHttpClientHandler() + { + return $this->httpClientHandler; + } + + /** + * Detects which HTTP client handler to use. + * + * @return FacebookHttpClientInterface + */ + public function detectHttpClientHandler() + { + return extension_loaded('curl') ? new FacebookCurlHttpClient() : new FacebookStreamHttpClient(); + } + + /** + * Toggle beta mode. + * + * @param boolean $betaMode + */ + public function enableBetaMode($betaMode = true) + { + $this->enableBetaMode = $betaMode; + } + + /** + * Returns the base Graph URL. + * + * @param boolean $postToVideoUrl Post to the video API if videos are being uploaded. + * + * @return string + */ + public function getBaseGraphUrl($postToVideoUrl = false) + { + if ($postToVideoUrl) { + return $this->enableBetaMode ? static::BASE_GRAPH_VIDEO_URL_BETA : static::BASE_GRAPH_VIDEO_URL; + } + + return $this->enableBetaMode ? static::BASE_GRAPH_URL_BETA : static::BASE_GRAPH_URL; + } + + /** + * Prepares the request for sending to the client handler. + * + * @param FacebookRequest $request + * + * @return array + */ + public function prepareRequestMessage(FacebookRequest $request) + { + $postToVideoUrl = $request->containsVideoUploads(); + $url = $this->getBaseGraphUrl($postToVideoUrl) . $request->getUrl(); + + // If we're sending files they should be sent as multipart/form-data + if ($request->containsFileUploads()) { + $requestBody = $request->getMultipartBody(); + $request->setHeaders([ + 'Content-Type' => 'multipart/form-data; boundary=' . $requestBody->getBoundary(), + ]); + } else { + $requestBody = $request->getUrlEncodedBody(); + $request->setHeaders([ + 'Content-Type' => 'application/x-www-form-urlencoded', + ]); + } + + return [ + $url, + $request->getMethod(), + $request->getHeaders(), + $requestBody->getBody(), + ]; + } + + /** + * Makes the request to Graph and returns the result. + * + * @param FacebookRequest $request + * + * @return FacebookResponse + * + * @throws FacebookSDKException + */ + public function sendRequest(FacebookRequest $request) + { + if (get_class($request) === 'Facebook\FacebookRequest') { + $request->validateAccessToken(); + } + + list($url, $method, $headers, $body) = $this->prepareRequestMessage($request); + + // Since file uploads can take a while, we need to give more time for uploads + $timeOut = static::DEFAULT_REQUEST_TIMEOUT; + if ($request->containsFileUploads()) { + $timeOut = static::DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT; + } elseif ($request->containsVideoUploads()) { + $timeOut = static::DEFAULT_VIDEO_UPLOAD_REQUEST_TIMEOUT; + } + + // Should throw `FacebookSDKException` exception on HTTP client error. + // Don't catch to allow it to bubble up. + $rawResponse = $this->httpClientHandler->send($url, $method, $body, $headers, $timeOut); + + static::$requestCount++; + + $returnResponse = new FacebookResponse( + $request, + $rawResponse->getBody(), + $rawResponse->getHttpResponseCode(), + $rawResponse->getHeaders() + ); + + if ($returnResponse->isError()) { + throw $returnResponse->getThrownException(); + } + + return $returnResponse; + } + + /** + * Makes a batched request to Graph and returns the result. + * + * @param FacebookBatchRequest $request + * + * @return FacebookBatchResponse + * + * @throws FacebookSDKException + */ + public function sendBatchRequest(FacebookBatchRequest $request) + { + $request->prepareRequestsForBatch(); + $facebookResponse = $this->sendRequest($request); + + return new FacebookBatchResponse($request, $facebookResponse); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php new file mode 100644 index 000000000..2b1008991 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookRequest.php @@ -0,0 +1,534 @@ +setApp($app); + $this->setAccessToken($accessToken); + $this->setMethod($method); + $this->setEndpoint($endpoint); + $this->setParams($params); + $this->setETag($eTag); + $this->graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION; + } + + /** + * Set the access token for this request. + * + * @param AccessToken|string|null + * + * @return FacebookRequest + */ + public function setAccessToken($accessToken) + { + $this->accessToken = $accessToken; + if ($accessToken instanceof AccessToken) { + $this->accessToken = $accessToken->getValue(); + } + + return $this; + } + + /** + * Sets the access token with one harvested from a URL or POST params. + * + * @param string $accessToken The access token. + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function setAccessTokenFromParams($accessToken) + { + $existingAccessToken = $this->getAccessToken(); + if (!$existingAccessToken) { + $this->setAccessToken($accessToken); + } elseif ($accessToken !== $existingAccessToken) { + throw new FacebookSDKException('Access token mismatch. The access token provided in the FacebookRequest and the one provided in the URL or POST params do not match.'); + } + + return $this; + } + + /** + * Return the access token for this request. + * + * @return string|null + */ + public function getAccessToken() + { + return $this->accessToken; + } + + /** + * Return the access token for this request as an AccessToken entity. + * + * @return AccessToken|null + */ + public function getAccessTokenEntity() + { + return $this->accessToken ? new AccessToken($this->accessToken) : null; + } + + /** + * Set the FacebookApp entity used for this request. + * + * @param FacebookApp|null $app + */ + public function setApp(FacebookApp $app = null) + { + $this->app = $app; + } + + /** + * Return the FacebookApp entity used for this request. + * + * @return FacebookApp + */ + public function getApp() + { + return $this->app; + } + + /** + * Generate an app secret proof to sign this request. + * + * @return string|null + */ + public function getAppSecretProof() + { + if (!$accessTokenEntity = $this->getAccessTokenEntity()) { + return null; + } + + return $accessTokenEntity->getAppSecretProof($this->app->getSecret()); + } + + /** + * Validate that an access token exists for this request. + * + * @throws FacebookSDKException + */ + public function validateAccessToken() + { + $accessToken = $this->getAccessToken(); + if (!$accessToken) { + throw new FacebookSDKException('You must provide an access token.'); + } + } + + /** + * Set the HTTP method for this request. + * + * @param string + */ + public function setMethod($method) + { + $this->method = strtoupper($method); + } + + /** + * Return the HTTP method for this request. + * + * @return string + */ + public function getMethod() + { + return $this->method; + } + + /** + * Validate that the HTTP method is set. + * + * @throws FacebookSDKException + */ + public function validateMethod() + { + if (!$this->method) { + throw new FacebookSDKException('HTTP method not specified.'); + } + + if (!in_array($this->method, ['GET', 'POST', 'DELETE'])) { + throw new FacebookSDKException('Invalid HTTP method specified.'); + } + } + + /** + * Set the endpoint for this request. + * + * @param string + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function setEndpoint($endpoint) + { + // Harvest the access token from the endpoint to keep things in sync + $params = FacebookUrlManipulator::getParamsAsArray($endpoint); + if (isset($params['access_token'])) { + $this->setAccessTokenFromParams($params['access_token']); + } + + // Clean the token & app secret proof from the endpoint. + $filterParams = ['access_token', 'appsecret_proof']; + $this->endpoint = FacebookUrlManipulator::removeParamsFromUrl($endpoint, $filterParams); + + return $this; + } + + /** + * Return the endpoint for this request. + * + * @return string + */ + public function getEndpoint() + { + // For batch requests, this will be empty + return $this->endpoint; + } + + /** + * Generate and return the headers for this request. + * + * @return array + */ + public function getHeaders() + { + $headers = static::getDefaultHeaders(); + + if ($this->eTag) { + $headers['If-None-Match'] = $this->eTag; + } + + return array_merge($this->headers, $headers); + } + + /** + * Set the headers for this request. + * + * @param array $headers + */ + public function setHeaders(array $headers) + { + $this->headers = array_merge($this->headers, $headers); + } + + /** + * Sets the eTag value. + * + * @param string $eTag + */ + public function setETag($eTag) + { + $this->eTag = $eTag; + } + + /** + * Set the params for this request. + * + * @param array $params + * + * @return FacebookRequest + * + * @throws FacebookSDKException + */ + public function setParams(array $params = []) + { + if (isset($params['access_token'])) { + $this->setAccessTokenFromParams($params['access_token']); + } + + // Don't let these buggers slip in. + unset($params['access_token'], $params['appsecret_proof']); + + // @TODO Refactor code above with this + //$params = $this->sanitizeAuthenticationParams($params); + $params = $this->sanitizeFileParams($params); + $this->dangerouslySetParams($params); + + return $this; + } + + /** + * Set the params for this request without filtering them first. + * + * @param array $params + * + * @return FacebookRequest + */ + public function dangerouslySetParams(array $params = []) + { + $this->params = array_merge($this->params, $params); + + return $this; + } + + /** + * Iterate over the params and pull out the file uploads. + * + * @param array $params + * + * @return array + */ + public function sanitizeFileParams(array $params) + { + foreach ($params as $key => $value) { + if ($value instanceof FacebookFile) { + $this->addFile($key, $value); + unset($params[$key]); + } + } + + return $params; + } + + /** + * Add a file to be uploaded. + * + * @param string $key + * @param FacebookFile $file + */ + public function addFile($key, FacebookFile $file) + { + $this->files[$key] = $file; + } + + /** + * Removes all the files from the upload queue. + */ + public function resetFiles() + { + $this->files = []; + } + + /** + * Get the list of files to be uploaded. + * + * @return array + */ + public function getFiles() + { + return $this->files; + } + + /** + * Let's us know if there is a file upload with this request. + * + * @return boolean + */ + public function containsFileUploads() + { + return !empty($this->files); + } + + /** + * Let's us know if there is a video upload with this request. + * + * @return boolean + */ + public function containsVideoUploads() + { + foreach ($this->files as $file) { + if ($file instanceof FacebookVideo) { + return true; + } + } + + return false; + } + + /** + * Returns the body of the request as multipart/form-data. + * + * @return RequestBodyMultipart + */ + public function getMultipartBody() + { + $params = $this->getPostParams(); + + return new RequestBodyMultipart($params, $this->files); + } + + /** + * Returns the body of the request as URL-encoded. + * + * @return RequestBodyUrlEncoded + */ + public function getUrlEncodedBody() + { + $params = $this->getPostParams(); + + return new RequestBodyUrlEncoded($params); + } + + /** + * Generate and return the params for this request. + * + * @return array + */ + public function getParams() + { + $params = $this->params; + + $accessToken = $this->getAccessToken(); + if ($accessToken) { + $params['access_token'] = $accessToken; + $params['appsecret_proof'] = $this->getAppSecretProof(); + } + + return $params; + } + + /** + * Only return params on POST requests. + * + * @return array + */ + public function getPostParams() + { + if ($this->getMethod() === 'POST') { + return $this->getParams(); + } + + return []; + } + + /** + * The graph version used for this request. + * + * @return string + */ + public function getGraphVersion() + { + return $this->graphVersion; + } + + /** + * Generate and return the URL for this request. + * + * @return string + */ + public function getUrl() + { + $this->validateMethod(); + + $graphVersion = FacebookUrlManipulator::forceSlashPrefix($this->graphVersion); + $endpoint = FacebookUrlManipulator::forceSlashPrefix($this->getEndpoint()); + + $url = $graphVersion . $endpoint; + + if ($this->getMethod() !== 'POST') { + $params = $this->getParams(); + $url = FacebookUrlManipulator::appendParamsToUrl($url, $params); + } + + return $url; + } + + /** + * Return the default headers that every request should use. + * + * @return array + */ + public static function getDefaultHeaders() + { + return [ + 'User-Agent' => 'fb-php-' . Facebook::VERSION, + 'Accept-Encoding' => '*', + ]; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php new file mode 100644 index 000000000..251ca2f79 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FacebookResponse.php @@ -0,0 +1,410 @@ +request = $request; + $this->body = $body; + $this->httpStatusCode = $httpStatusCode; + $this->headers = $headers; + + $this->decodeBody(); + } + + /** + * Return the original request that returned this response. + * + * @return FacebookRequest + */ + public function getRequest() + { + return $this->request; + } + + /** + * Return the FacebookApp entity used for this response. + * + * @return FacebookApp + */ + public function getApp() + { + return $this->request->getApp(); + } + + /** + * Return the access token that was used for this response. + * + * @return string|null + */ + public function getAccessToken() + { + return $this->request->getAccessToken(); + } + + /** + * Return the HTTP status code for this response. + * + * @return int + */ + public function getHttpStatusCode() + { + return $this->httpStatusCode; + } + + /** + * Return the HTTP headers for this response. + * + * @return array + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * Return the raw body response. + * + * @return string + */ + public function getBody() + { + return $this->body; + } + + /** + * Return the decoded body response. + * + * @return array + */ + public function getDecodedBody() + { + return $this->decodedBody; + } + + /** + * Get the app secret proof that was used for this response. + * + * @return string|null + */ + public function getAppSecretProof() + { + return $this->request->getAppSecretProof(); + } + + /** + * Get the ETag associated with the response. + * + * @return string|null + */ + public function getETag() + { + return isset($this->headers['ETag']) ? $this->headers['ETag'] : null; + } + + /** + * Get the version of Graph that returned this response. + * + * @return string|null + */ + public function getGraphVersion() + { + return isset($this->headers['Facebook-API-Version']) ? $this->headers['Facebook-API-Version'] : null; + } + + /** + * Returns true if Graph returned an error message. + * + * @return boolean + */ + public function isError() + { + return isset($this->decodedBody['error']); + } + + /** + * Throws the exception. + * + * @throws FacebookSDKException + */ + public function throwException() + { + throw $this->thrownException; + } + + /** + * Instantiates an exception to be thrown later. + */ + public function makeException() + { + $this->thrownException = FacebookResponseException::create($this); + } + + /** + * Returns the exception that was thrown for this request. + * + * @return FacebookResponseException|null + */ + public function getThrownException() + { + return $this->thrownException; + } + + /** + * Convert the raw response into an array if possible. + * + * Graph will return 2 types of responses: + * - JSON(P) + * Most responses from Graph are JSON(P) + * - application/x-www-form-urlencoded key/value pairs + * Happens on the `/oauth/access_token` endpoint when exchanging + * a short-lived access token for a long-lived access token + * - And sometimes nothing :/ but that'd be a bug. + */ + public function decodeBody() + { + $this->decodedBody = json_decode($this->body, true); + + if ($this->decodedBody === null) { + $this->decodedBody = []; + parse_str($this->body, $this->decodedBody); + } elseif (is_bool($this->decodedBody)) { + // Backwards compatibility for Graph < 2.1. + // Mimics 2.1 responses. + // @TODO Remove this after Graph 2.0 is no longer supported + $this->decodedBody = ['success' => $this->decodedBody]; + } elseif (is_numeric($this->decodedBody)) { + $this->decodedBody = ['id' => $this->decodedBody]; + } + + if (!is_array($this->decodedBody)) { + $this->decodedBody = []; + } + + if ($this->isError()) { + $this->makeException(); + } + } + + /** + * Instantiate a new GraphObject from response. + * + * @param string|null $subclassName The GraphNode subclass to cast to. + * + * @return \Facebook\GraphNodes\GraphObject + * + * @throws FacebookSDKException + * + * @deprecated 5.0.0 getGraphObject() has been renamed to getGraphNode() + * @todo v6: Remove this method + */ + public function getGraphObject($subclassName = null) + { + return $this->getGraphNode($subclassName); + } + + /** + * Instantiate a new GraphNode from response. + * + * @param string|null $subclassName The GraphNode subclass to cast to. + * + * @return \Facebook\GraphNodes\GraphNode + * + * @throws FacebookSDKException + */ + public function getGraphNode($subclassName = null) + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphNode($subclassName); + } + + /** + * Convenience method for creating a GraphAlbum collection. + * + * @return \Facebook\GraphNodes\GraphAlbum + * + * @throws FacebookSDKException + */ + public function getGraphAlbum() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphAlbum(); + } + + /** + * Convenience method for creating a GraphPage collection. + * + * @return \Facebook\GraphNodes\GraphPage + * + * @throws FacebookSDKException + */ + public function getGraphPage() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphPage(); + } + + /** + * Convenience method for creating a GraphSessionInfo collection. + * + * @return \Facebook\GraphNodes\GraphSessionInfo + * + * @throws FacebookSDKException + */ + public function getGraphSessionInfo() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphSessionInfo(); + } + + /** + * Convenience method for creating a GraphUser collection. + * + * @return \Facebook\GraphNodes\GraphUser + * + * @throws FacebookSDKException + */ + public function getGraphUser() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphUser(); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return \Facebook\GraphNodes\GraphEvent + * + * @throws FacebookSDKException + */ + public function getGraphEvent() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphEvent(); + } + + /** + * Convenience method for creating a GraphGroup collection. + * + * @return \Facebook\GraphNodes\GraphGroup + * + * @throws FacebookSDKException + */ + public function getGraphGroup() + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphGroup(); + } + + /** + * Instantiate a new GraphList from response. + * + * @param string|null $subclassName The GraphNode subclass to cast list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return \Facebook\GraphNodes\GraphList + * + * @throws FacebookSDKException + * + * @deprecated 5.0.0 getGraphList() has been renamed to getGraphEdge() + * @todo v6: Remove this method + */ + public function getGraphList($subclassName = null, $auto_prefix = true) + { + return $this->getGraphEdge($subclassName, $auto_prefix); + } + + /** + * Instantiate a new GraphEdge from response. + * + * @param string|null $subclassName The GraphNode subclass to cast list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return \Facebook\GraphNodes\GraphEdge + * + * @throws FacebookSDKException + */ + public function getGraphEdge($subclassName = null, $auto_prefix = true) + { + $factory = new GraphNodeFactory($this); + + return $factory->makeGraphEdge($subclassName, $auto_prefix); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php new file mode 100644 index 000000000..3c1536d43 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookFile.php @@ -0,0 +1,169 @@ +path = $filePath; + $this->maxLength = $maxLength; + $this->offset = $offset; + $this->open(); + } + + /** + * Closes the stream when destructed. + */ + public function __destruct() + { + $this->close(); + } + + /** + * Opens a stream for the file. + * + * @throws FacebookSDKException + */ + public function open() + { + if (!$this->isRemoteFile($this->path) && !is_readable($this->path)) { + throw new FacebookSDKException('Failed to create FacebookFile entity. Unable to read resource: ' . $this->path . '.'); + } + + $this->stream = fopen($this->path, 'r'); + + if (!$this->stream) { + throw new FacebookSDKException('Failed to create FacebookFile entity. Unable to open resource: ' . $this->path . '.'); + } + } + + /** + * Stops the file stream. + */ + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + } + + /** + * Return the contents of the file. + * + * @return string + */ + public function getContents() + { + return stream_get_contents($this->stream, $this->maxLength, $this->offset); + } + + /** + * Return the name of the file. + * + * @return string + */ + public function getFileName() + { + return basename($this->path); + } + + /** + * Return the path of the file. + * + * @return string + */ + public function getFilePath() + { + return $this->path; + } + + /** + * Return the size of the file. + * + * @return int + */ + public function getSize() + { + return filesize($this->path); + } + + /** + * Return the mimetype of the file. + * + * @return string + */ + public function getMimetype() + { + return Mimetypes::getInstance()->fromFilename($this->path) ?: 'text/plain'; + } + + /** + * Returns true if the path to the file is remote. + * + * @param string $pathToFile + * + * @return boolean + */ + protected function isRemoteFile($pathToFile) + { + return preg_match('/^(https?|ftp):\/\/.*/', $pathToFile) === 1; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php new file mode 100644 index 000000000..92a22f140 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookResumableUploader.php @@ -0,0 +1,167 @@ +app = $app; + $this->client = $client; + $this->accessToken = $accessToken; + $this->graphVersion = $graphVersion; + } + + /** + * Upload by chunks - start phase + * + * @param string $endpoint + * @param FacebookFile $file + * + * @return FacebookTransferChunk + * + * @throws FacebookSDKException + */ + public function start($endpoint, FacebookFile $file) + { + $params = [ + 'upload_phase' => 'start', + 'file_size' => $file->getSize(), + ]; + $response = $this->sendUploadRequest($endpoint, $params); + + return new FacebookTransferChunk($file, $response['upload_session_id'], $response['video_id'], $response['start_offset'], $response['end_offset']); + } + + /** + * Upload by chunks - transfer phase + * + * @param string $endpoint + * @param FacebookTransferChunk $chunk + * @param boolean $allowToThrow + * + * @return FacebookTransferChunk + * + * @throws FacebookResponseException + */ + public function transfer($endpoint, FacebookTransferChunk $chunk, $allowToThrow = false) + { + $params = [ + 'upload_phase' => 'transfer', + 'upload_session_id' => $chunk->getUploadSessionId(), + 'start_offset' => $chunk->getStartOffset(), + 'video_file_chunk' => $chunk->getPartialFile(), + ]; + + try { + $response = $this->sendUploadRequest($endpoint, $params); + } catch (FacebookResponseException $e) { + $preException = $e->getPrevious(); + if ($allowToThrow || !$preException instanceof FacebookResumableUploadException) { + throw $e; + } + + // Return the same chunk entity so it can be retried. + return $chunk; + } + + return new FacebookTransferChunk($chunk->getFile(), $chunk->getUploadSessionId(), $chunk->getVideoId(), $response['start_offset'], $response['end_offset']); + } + + /** + * Upload by chunks - finish phase + * + * @param string $endpoint + * @param string $uploadSessionId + * @param array $metadata The metadata associated with the file. + * + * @return boolean + * + * @throws FacebookSDKException + */ + public function finish($endpoint, $uploadSessionId, $metadata = []) + { + $params = array_merge($metadata, [ + 'upload_phase' => 'finish', + 'upload_session_id' => $uploadSessionId, + ]); + $response = $this->sendUploadRequest($endpoint, $params); + + return $response['success']; + } + + /** + * Helper to make a FacebookRequest and send it. + * + * @param string $endpoint The endpoint to POST to. + * @param array $params The params to send with the request. + * + * @return array + */ + private function sendUploadRequest($endpoint, $params = []) + { + $request = new FacebookRequest($this->app, $this->accessToken, 'POST', $endpoint, $params, null, $this->graphVersion); + + return $this->client->sendRequest($request)->getDecodedBody(); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php new file mode 100644 index 000000000..a909e8751 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookTransferChunk.php @@ -0,0 +1,133 @@ +file = $file; + $this->uploadSessionId = $uploadSessionId; + $this->videoId = $videoId; + $this->startOffset = $startOffset; + $this->endOffset = $endOffset; + } + + /** + * Return the file entity. + * + * @return FacebookFile + */ + public function getFile() + { + return $this->file; + } + + /** + * Return a FacebookFile entity with partial content. + * + * @return FacebookFile + */ + public function getPartialFile() + { + $maxLength = $this->endOffset - $this->startOffset; + + return new FacebookFile($this->file->getFilePath(), $maxLength, $this->startOffset); + } + + /** + * Return upload session Id + * + * @return int + */ + public function getUploadSessionId() + { + return $this->uploadSessionId; + } + + /** + * Check whether is the last chunk + * + * @return bool + */ + public function isLastChunk() + { + return $this->startOffset === $this->endOffset; + } + + /** + * @return int + */ + public function getStartOffset() + { + return $this->startOffset; + } + + /** + * Get uploaded video Id + * + * @return int + */ + public function getVideoId() + { + return $this->videoId; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php new file mode 100644 index 000000000..ee6dd5389 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/FileUpload/FacebookVideo.php @@ -0,0 +1,33 @@ + 'text/vnd.in3d.3dml', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'application' => 'application/x-ms-application', + 'apr' => 'application/vnd.lotus-approach', + 'asa' => 'text/plain', + 'asax' => 'application/octet-stream', + 'asc' => 'application/pgp-signature', + 'ascx' => 'text/plain', + 'asf' => 'video/x-ms-asf', + 'ashx' => 'text/plain', + 'asm' => 'text/x-asm', + 'asmx' => 'text/plain', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asp' => 'text/plain', + 'aspx' => 'text/plain', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'axd' => 'text/plain', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfc' => 'application/x-coldfusion', + 'cfm' => 'application/x-coldfusion', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'cryptonote' => 'application/vnd.rig.cryptonote', + 'cs' => 'text/plain', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxt' => 'application/vnd.geonext', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'hta' => 'application/octet-stream', + 'htc' => 'text/html', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ini' => 'text/plain', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/octet-stream', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'text/javascript', + 'json' => 'application/json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/octet-stream', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/octet-stream', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/mp4', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsf' => 'application/vnd.lotus-notes', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'text/x-php', + 'phps' => 'application/x-httpd-phps', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rb' => 'text/plain', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'resx' => 'text/xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sig' => 'application/pgp-signature', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'src' => 'application/x-wais-source', + 'srt' => 'application/octet-stream', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'image/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvx' => 'application/vnd.dece.unspecified', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-ms-wmz', + 'woff' => 'application/x-font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'application/vnd.hzn-3d-crossword', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'yaml' => 'text/yaml', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'yml' => 'text/yaml', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml' + ]; + + /** + * Get a singleton instance of the class + * + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Get a mimetype value from a file extension + * + * @param string $extension File extension + * + * @return string|null + */ + public function fromExtension($extension) + { + $extension = strtolower($extension); + + return isset($this->mimetypes[$extension]) ? $this->mimetypes[$extension] : null; + } + + /** + * Get a mimetype from a filename + * + * @param string $filename Filename to generate a mimetype from + * + * @return string|null + */ + public function fromFilename($filename) + { + return $this->fromExtension(pathinfo($filename, PATHINFO_EXTENSION)); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php new file mode 100644 index 000000000..4338b65e4 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Birthday.php @@ -0,0 +1,85 @@ +hasYear = count($parts) === 3 || count($parts) === 1; + $this->hasDate = count($parts) === 3 || count($parts) === 2; + + parent::__construct($date); + } + + /** + * Returns whether date object contains birth day and month + * + * @return bool + */ + public function hasDate() + { + return $this->hasDate; + } + + /** + * Returns whether date object contains birth year + * + * @return bool + */ + public function hasYear() + { + return $this->hasYear; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php new file mode 100644 index 000000000..424b7cf3b --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/Collection.php @@ -0,0 +1,242 @@ +items = $items; + } + + /** + * Gets the value of a field from the Graph node. + * + * @param string $name The field to retrieve. + * @param mixed $default The default to return if the field doesn't exist. + * + * @return mixed + */ + public function getField($name, $default = null) + { + if (isset($this->items[$name])) { + return $this->items[$name]; + } + + return $default; + } + + /** + * Gets the value of the named property for this graph object. + * + * @param string $name The property to retrieve. + * @param mixed $default The default to return if the property doesn't exist. + * + * @return mixed + * + * @deprecated 5.0.0 getProperty() has been renamed to getField() + * @todo v6: Remove this method + */ + public function getProperty($name, $default = null) + { + return $this->getField($name, $default); + } + + /** + * Returns a list of all fields set on the object. + * + * @return array + */ + public function getFieldNames() + { + return array_keys($this->items); + } + + /** + * Returns a list of all properties set on the object. + * + * @return array + * + * @deprecated 5.0.0 getPropertyNames() has been renamed to getFieldNames() + * @todo v6: Remove this method + */ + public function getPropertyNames() + { + return $this->getFieldNames(); + } + + /** + * Get all of the items in the collection. + * + * @return array + */ + public function all() + { + return $this->items; + } + + /** + * Get the collection of items as a plain array. + * + * @return array + */ + public function asArray() + { + return array_map(function ($value) { + return $value instanceof Collection ? $value->asArray() : $value; + }, $this->items); + } + + /** + * Run a map over each of the items. + * + * @param \Closure $callback + * + * @return static + */ + public function map(\Closure $callback) + { + return new static(array_map($callback, $this->items, array_keys($this->items))); + } + + /** + * Get the collection of items as JSON. + * + * @param int $options + * + * @return string + */ + public function asJson($options = 0) + { + return json_encode($this->asArray(), $options); + } + + /** + * Count the number of items in the collection. + * + * @return int + */ + public function count() + { + return count($this->items); + } + + /** + * Get an iterator for the items. + * + * @return ArrayIterator + */ + public function getIterator() + { + return new ArrayIterator($this->items); + } + + /** + * Determine if an item exists at an offset. + * + * @param mixed $key + * + * @return bool + */ + public function offsetExists($key) + { + return array_key_exists($key, $this->items); + } + + /** + * Get an item at a given offset. + * + * @param mixed $key + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->items[$key]; + } + + /** + * Set the item at a given offset. + * + * @param mixed $key + * @param mixed $value + * + * @return void + */ + public function offsetSet($key, $value) + { + if (is_null($key)) { + $this->items[] = $value; + } else { + $this->items[$key] = $value; + } + } + + /** + * Unset the item at a given offset. + * + * @param string $key + * + * @return void + */ + public function offsetUnset($key) + { + unset($this->items[$key]); + } + + /** + * Convert the collection to its string representation. + * + * @return string + */ + public function __toString() + { + return $this->asJson(); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php new file mode 100644 index 000000000..31508ee45 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAchievement.php @@ -0,0 +1,112 @@ + '\Facebook\GraphNodes\GraphUser', + 'application' => '\Facebook\GraphNodes\GraphApplication', + ]; + + /** + * Returns the ID for the achievement. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the user who achieved this. + * + * @return GraphUser|null + */ + public function getFrom() + { + return $this->getField('from'); + } + + /** + * Returns the time at which this was achieved. + * + * @return \DateTime|null + */ + public function getPublishTime() + { + return $this->getField('publish_time'); + } + + /** + * Returns the app in which the user achieved this. + * + * @return GraphApplication|null + */ + public function getApplication() + { + return $this->getField('application'); + } + + /** + * Returns information about the achievement type this instance is connected with. + * + * @return array|null + */ + public function getData() + { + return $this->getField('data'); + } + + /** + * Returns the type of achievement. + * + * @see https://developers.facebook.com/docs/graph-api/reference/achievement + * + * @return string + */ + public function getType() + { + return 'game.achievement'; + } + + /** + * Indicates whether gaining the achievement published a feed story for the user. + * + * @return boolean|null + */ + public function isNoFeedStory() + { + return $this->getField('no_feed_story'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php new file mode 100644 index 000000000..52f19b51f --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphAlbum.php @@ -0,0 +1,183 @@ + '\Facebook\GraphNodes\GraphUser', + 'place' => '\Facebook\GraphNodes\GraphPage', + ]; + + /** + * Returns the ID for the album. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns whether the viewer can upload photos to this album. + * + * @return boolean|null + */ + public function getCanUpload() + { + return $this->getField('can_upload'); + } + + /** + * Returns the number of photos in this album. + * + * @return int|null + */ + public function getCount() + { + return $this->getField('count'); + } + + /** + * Returns the ID of the album's cover photo. + * + * @return string|null + */ + public function getCoverPhoto() + { + return $this->getField('cover_photo'); + } + + /** + * Returns the time the album was initially created. + * + * @return \DateTime|null + */ + public function getCreatedTime() + { + return $this->getField('created_time'); + } + + /** + * Returns the time the album was updated. + * + * @return \DateTime|null + */ + public function getUpdatedTime() + { + return $this->getField('updated_time'); + } + + /** + * Returns the description of the album. + * + * @return string|null + */ + public function getDescription() + { + return $this->getField('description'); + } + + /** + * Returns profile that created the album. + * + * @return GraphUser|null + */ + public function getFrom() + { + return $this->getField('from'); + } + + /** + * Returns profile that created the album. + * + * @return GraphPage|null + */ + public function getPlace() + { + return $this->getField('place'); + } + + /** + * Returns a link to this album on Facebook. + * + * @return string|null + */ + public function getLink() + { + return $this->getField('link'); + } + + /** + * Returns the textual location of the album. + * + * @return string|null + */ + public function getLocation() + { + return $this->getField('location'); + } + + /** + * Returns the title of the album. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the privacy settings for the album. + * + * @return string|null + */ + public function getPrivacy() + { + return $this->getField('privacy'); + } + + /** + * Returns the type of the album. + * + * enum{ profile, mobile, wall, normal, album } + * + * @return string|null + */ + public function getType() + { + return $this->getField('type'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php new file mode 100644 index 000000000..aa07c825d --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphApplication.php @@ -0,0 +1,43 @@ +getField('id'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php new file mode 100644 index 000000000..824275bbe --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphCoverPhoto.php @@ -0,0 +1,72 @@ +getField('id'); + } + + /** + * Returns the source of cover if it exists + * + * @return string|null + */ + public function getSource() + { + return $this->getField('source'); + } + + /** + * Returns the offset_x of cover if it exists + * + * @return int|null + */ + public function getOffsetX() + { + return $this->getField('offset_x'); + } + + /** + * Returns the offset_y of cover if it exists + * + * @return int|null + */ + public function getOffsetY() + { + return $this->getField('offset_y'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php new file mode 100644 index 000000000..f6f4970c0 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEdge.php @@ -0,0 +1,252 @@ +request = $request; + $this->metaData = $metaData; + $this->parentEdgeEndpoint = $parentEdgeEndpoint; + $this->subclassName = $subclassName; + + parent::__construct($data); + } + + /** + * Gets the parent Graph edge endpoint that generated the list. + * + * @return string|null + */ + public function getParentGraphEdge() + { + return $this->parentEdgeEndpoint; + } + + /** + * Gets the subclass name that the child GraphNode's are cast as. + * + * @return string|null + */ + public function getSubClassName() + { + return $this->subclassName; + } + + /** + * Returns the raw meta data associated with this GraphEdge. + * + * @return array + */ + public function getMetaData() + { + return $this->metaData; + } + + /** + * Returns the next cursor if it exists. + * + * @return string|null + */ + public function getNextCursor() + { + return $this->getCursor('after'); + } + + /** + * Returns the previous cursor if it exists. + * + * @return string|null + */ + public function getPreviousCursor() + { + return $this->getCursor('before'); + } + + /** + * Returns the cursor for a specific direction if it exists. + * + * @param string $direction The direction of the page: after|before + * + * @return string|null + */ + public function getCursor($direction) + { + if (isset($this->metaData['paging']['cursors'][$direction])) { + return $this->metaData['paging']['cursors'][$direction]; + } + + return null; + } + + /** + * Generates a pagination URL based on a cursor. + * + * @param string $direction The direction of the page: next|previous + * + * @return string|null + * + * @throws FacebookSDKException + */ + public function getPaginationUrl($direction) + { + $this->validateForPagination(); + + // Do we have a paging URL? + if (!isset($this->metaData['paging'][$direction])) { + return null; + } + + $pageUrl = $this->metaData['paging'][$direction]; + + return FacebookUrlManipulator::baseGraphUrlEndpoint($pageUrl); + } + + /** + * Validates whether or not we can paginate on this request. + * + * @throws FacebookSDKException + */ + public function validateForPagination() + { + if ($this->request->getMethod() !== 'GET') { + throw new FacebookSDKException('You can only paginate on a GET request.', 720); + } + } + + /** + * Gets the request object needed to make a next|previous page request. + * + * @param string $direction The direction of the page: next|previous + * + * @return FacebookRequest|null + * + * @throws FacebookSDKException + */ + public function getPaginationRequest($direction) + { + $pageUrl = $this->getPaginationUrl($direction); + if (!$pageUrl) { + return null; + } + + $newRequest = clone $this->request; + $newRequest->setEndpoint($pageUrl); + + return $newRequest; + } + + /** + * Gets the request object needed to make a "next" page request. + * + * @return FacebookRequest|null + * + * @throws FacebookSDKException + */ + public function getNextPageRequest() + { + return $this->getPaginationRequest('next'); + } + + /** + * Gets the request object needed to make a "previous" page request. + * + * @return FacebookRequest|null + * + * @throws FacebookSDKException + */ + public function getPreviousPageRequest() + { + return $this->getPaginationRequest('previous'); + } + + /** + * The total number of results according to Graph if it exists. + * + * This will be returned if the summary=true modifier is present in the request. + * + * @return int|null + */ + public function getTotalCount() + { + if (isset($this->metaData['summary']['total_count'])) { + return $this->metaData['summary']['total_count']; + } + + return null; + } + + /** + * @inheritDoc + */ + public function map(\Closure $callback) + { + return new static( + $this->request, + array_map($callback, $this->items, array_keys($this->items)), + $this->metaData, + $this->parentEdgeEndpoint, + $this->subclassName + ); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php new file mode 100644 index 000000000..a470d89f9 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphEvent.php @@ -0,0 +1,242 @@ + '\Facebook\GraphNodes\GraphCoverPhoto', + 'place' => '\Facebook\GraphNodes\GraphPage', + 'picture' => '\Facebook\GraphNodes\GraphPicture', + 'parent_group' => '\Facebook\GraphNodes\GraphGroup', + ]; + + /** + * Returns the `id` (The event ID) as string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the `cover` (Cover picture) as GraphCoverPhoto if present. + * + * @return GraphCoverPhoto|null + */ + public function getCover() + { + return $this->getField('cover'); + } + + /** + * Returns the `description` (Long-form description) as string if present. + * + * @return string|null + */ + public function getDescription() + { + return $this->getField('description'); + } + + /** + * Returns the `end_time` (End time, if one has been set) as DateTime if present. + * + * @return \DateTime|null + */ + public function getEndTime() + { + return $this->getField('end_time'); + } + + /** + * Returns the `is_date_only` (Whether the event only has a date specified, but no time) as bool if present. + * + * @return bool|null + */ + public function getIsDateOnly() + { + return $this->getField('is_date_only'); + } + + /** + * Returns the `name` (Event name) as string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the `owner` (The profile that created the event) as GraphNode if present. + * + * @return GraphNode|null + */ + public function getOwner() + { + return $this->getField('owner'); + } + + /** + * Returns the `parent_group` (The group the event belongs to) as GraphGroup if present. + * + * @return GraphGroup|null + */ + public function getParentGroup() + { + return $this->getField('parent_group'); + } + + /** + * Returns the `place` (Event Place information) as GraphPage if present. + * + * @return GraphPage|null + */ + public function getPlace() + { + return $this->getField('place'); + } + + /** + * Returns the `privacy` (Who can see the event) as string if present. + * + * @return string|null + */ + public function getPrivacy() + { + return $this->getField('privacy'); + } + + /** + * Returns the `start_time` (Start time) as DateTime if present. + * + * @return \DateTime|null + */ + public function getStartTime() + { + return $this->getField('start_time'); + } + + /** + * Returns the `ticket_uri` (The link users can visit to buy a ticket to this event) as string if present. + * + * @return string|null + */ + public function getTicketUri() + { + return $this->getField('ticket_uri'); + } + + /** + * Returns the `timezone` (Timezone) as string if present. + * + * @return string|null + */ + public function getTimezone() + { + return $this->getField('timezone'); + } + + /** + * Returns the `updated_time` (Last update time) as DateTime if present. + * + * @return \DateTime|null + */ + public function getUpdatedTime() + { + return $this->getField('updated_time'); + } + + /** + * Returns the `picture` (Event picture) as GraphPicture if present. + * + * @return GraphPicture|null + */ + public function getPicture() + { + return $this->getField('picture'); + } + + /** + * Returns the `attending_count` (Number of people attending the event) as int if present. + * + * @return int|null + */ + public function getAttendingCount() + { + return $this->getField('attending_count'); + } + + /** + * Returns the `declined_count` (Number of people who declined the event) as int if present. + * + * @return int|null + */ + public function getDeclinedCount() + { + return $this->getField('declined_count'); + } + + /** + * Returns the `maybe_count` (Number of people who maybe going to the event) as int if present. + * + * @return int|null + */ + public function getMaybeCount() + { + return $this->getField('maybe_count'); + } + + /** + * Returns the `noreply_count` (Number of people who did not reply to the event) as int if present. + * + * @return int|null + */ + public function getNoreplyCount() + { + return $this->getField('noreply_count'); + } + + /** + * Returns the `invited_count` (Number of people invited to the event) as int if present. + * + * @return int|null + */ + public function getInvitedCount() + { + return $this->getField('invited_count'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php new file mode 100644 index 000000000..6217bd4dc --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphGroup.php @@ -0,0 +1,170 @@ + '\Facebook\GraphNodes\GraphCoverPhoto', + 'venue' => '\Facebook\GraphNodes\GraphLocation', + ]; + + /** + * Returns the `id` (The Group ID) as string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the `cover` (The cover photo of the Group) as GraphCoverPhoto if present. + * + * @return GraphCoverPhoto|null + */ + public function getCover() + { + return $this->getField('cover'); + } + + /** + * Returns the `description` (A brief description of the Group) as string if present. + * + * @return string|null + */ + public function getDescription() + { + return $this->getField('description'); + } + + /** + * Returns the `email` (The email address to upload content to the Group. Only current members of the Group can use this) as string if present. + * + * @return string|null + */ + public function getEmail() + { + return $this->getField('email'); + } + + /** + * Returns the `icon` (The URL for the Group's icon) as string if present. + * + * @return string|null + */ + public function getIcon() + { + return $this->getField('icon'); + } + + /** + * Returns the `link` (The Group's website) as string if present. + * + * @return string|null + */ + public function getLink() + { + return $this->getField('link'); + } + + /** + * Returns the `name` (The name of the Group) as string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the `member_request_count` (Number of people asking to join the group.) as int if present. + * + * @return int|null + */ + public function getMemberRequestCount() + { + return $this->getField('member_request_count'); + } + + /** + * Returns the `owner` (The profile that created this Group) as GraphNode if present. + * + * @return GraphNode|null + */ + public function getOwner() + { + return $this->getField('owner'); + } + + /** + * Returns the `parent` (The parent Group of this Group, if it exists) as GraphNode if present. + * + * @return GraphNode|null + */ + public function getParent() + { + return $this->getField('parent'); + } + + /** + * Returns the `privacy` (The privacy setting of the Group) as string if present. + * + * @return string|null + */ + public function getPrivacy() + { + return $this->getField('privacy'); + } + + /** + * Returns the `updated_time` (The last time the Group was updated (this includes changes in the Group's properties and changes in posts and comments if user can see them)) as \DateTime if present. + * + * @return \DateTime|null + */ + public function getUpdatedTime() + { + return $this->getField('updated_time'); + } + + /** + * Returns the `venue` (The location for the Group) as GraphLocation if present. + * + * @return GraphLocation|null + */ + public function getVenue() + { + return $this->getField('venue'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php new file mode 100644 index 000000000..3dfbd4975 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphList.php @@ -0,0 +1,36 @@ +getField('street'); + } + + /** + * Returns the city component of the location + * + * @return string|null + */ + public function getCity() + { + return $this->getField('city'); + } + + /** + * Returns the state component of the location + * + * @return string|null + */ + public function getState() + { + return $this->getField('state'); + } + + /** + * Returns the country component of the location + * + * @return string|null + */ + public function getCountry() + { + return $this->getField('country'); + } + + /** + * Returns the zipcode component of the location + * + * @return string|null + */ + public function getZip() + { + return $this->getField('zip'); + } + + /** + * Returns the latitude component of the location + * + * @return float|null + */ + public function getLatitude() + { + return $this->getField('latitude'); + } + + /** + * Returns the street component of the location + * + * @return float|null + */ + public function getLongitude() + { + return $this->getField('longitude'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php new file mode 100644 index 000000000..061e74494 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNode.php @@ -0,0 +1,197 @@ +castItems($data)); + } + + /** + * Iterates over an array and detects the types each node + * should be cast to and returns all the items as an array. + * + * @TODO Add auto-casting to AccessToken entities. + * + * @param array $data The array to iterate over. + * + * @return array + */ + public function castItems(array $data) + { + $items = []; + + foreach ($data as $k => $v) { + if ($this->shouldCastAsDateTime($k) + && (is_numeric($v) + || $this->isIso8601DateString($v)) + ) { + $items[$k] = $this->castToDateTime($v); + } elseif ($k === 'birthday') { + $items[$k] = $this->castToBirthday($v); + } else { + $items[$k] = $v; + } + } + + return $items; + } + + /** + * Uncasts any auto-casted datatypes. + * Basically the reverse of castItems(). + * + * @return array + */ + public function uncastItems() + { + $items = $this->asArray(); + + return array_map(function ($v) { + if ($v instanceof \DateTime) { + return $v->format(\DateTime::ISO8601); + } + + return $v; + }, $items); + } + + /** + * Get the collection of items as JSON. + * + * @param int $options + * + * @return string + */ + public function asJson($options = 0) + { + return json_encode($this->uncastItems(), $options); + } + + /** + * Detects an ISO 8601 formatted string. + * + * @param string $string + * + * @return boolean + * + * @see https://developers.facebook.com/docs/graph-api/using-graph-api/#readmodifiers + * @see http://www.cl.cam.ac.uk/~mgk25/iso-time.html + * @see http://en.wikipedia.org/wiki/ISO_8601 + */ + public function isIso8601DateString($string) + { + // This insane regex was yoinked from here: + // http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ + // ...and I'm all like: + // http://thecodinglove.com/post/95378251969/when-code-works-and-i-dont-know-why + $crazyInsaneRegexThatSomehowDetectsIso8601 = '/^([\+-]?\d{4}(?!\d{2}\b))' + . '((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?' + . '|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d' + . '|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])' + . '((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d' + . '([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/'; + + return preg_match($crazyInsaneRegexThatSomehowDetectsIso8601, $string) === 1; + } + + /** + * Determines if a value from Graph should be cast to DateTime. + * + * @param string $key + * + * @return boolean + */ + public function shouldCastAsDateTime($key) + { + return in_array($key, [ + 'created_time', + 'updated_time', + 'start_time', + 'end_time', + 'backdated_time', + 'issued_at', + 'expires_at', + 'publish_time' + ], true); + } + + /** + * Casts a date value from Graph to DateTime. + * + * @param int|string $value + * + * @return \DateTime + */ + public function castToDateTime($value) + { + if (is_int($value)) { + $dt = new \DateTime(); + $dt->setTimestamp($value); + } else { + $dt = new \DateTime($value); + } + + return $dt; + } + + /** + * Casts a birthday value from Graph to Birthday + * + * @param string $value + * + * @return Birthday + */ + public function castToBirthday($value) + { + return new Birthday($value); + } + + /** + * Getter for $graphObjectMap. + * + * @return array + */ + public static function getObjectMap() + { + return static::$graphObjectMap; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php new file mode 100644 index 000000000..6a3709198 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php @@ -0,0 +1,392 @@ +response = $response; + $this->decodedBody = $response->getDecodedBody(); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphNode. + * + * @param string|null $subclassName The GraphNode sub class to cast to. + * + * @return GraphNode + * + * @throws FacebookSDKException + */ + public function makeGraphNode($subclassName = null) + { + $this->validateResponseAsArray(); + $this->validateResponseCastableAsGraphNode(); + + return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); + } + + /** + * Convenience method for creating a GraphAchievement collection. + * + * @return GraphAchievement + * + * @throws FacebookSDKException + */ + public function makeGraphAchievement() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAchievement'); + } + + /** + * Convenience method for creating a GraphAlbum collection. + * + * @return GraphAlbum + * + * @throws FacebookSDKException + */ + public function makeGraphAlbum() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAlbum'); + } + + /** + * Convenience method for creating a GraphPage collection. + * + * @return GraphPage + * + * @throws FacebookSDKException + */ + public function makeGraphPage() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphPage'); + } + + /** + * Convenience method for creating a GraphSessionInfo collection. + * + * @return GraphSessionInfo + * + * @throws FacebookSDKException + */ + public function makeGraphSessionInfo() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphSessionInfo'); + } + + /** + * Convenience method for creating a GraphUser collection. + * + * @return GraphUser + * + * @throws FacebookSDKException + */ + public function makeGraphUser() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphUser'); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return GraphEvent + * + * @throws FacebookSDKException + */ + public function makeGraphEvent() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent'); + } + + /** + * Convenience method for creating a GraphGroup collection. + * + * @return GraphGroup + * + * @throws FacebookSDKException + */ + public function makeGraphGroup() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphGroup'); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphEdge. + * + * @param string|null $subclassName The GraphNode sub class to cast the list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return GraphEdge + * + * @throws FacebookSDKException + */ + public function makeGraphEdge($subclassName = null, $auto_prefix = true) + { + $this->validateResponseAsArray(); + $this->validateResponseCastableAsGraphEdge(); + + if ($subclassName && $auto_prefix) { + $subclassName = static::BASE_GRAPH_OBJECT_PREFIX . $subclassName; + } + + return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); + } + + /** + * Validates the decoded body. + * + * @throws FacebookSDKException + */ + public function validateResponseAsArray() + { + if (!is_array($this->decodedBody)) { + throw new FacebookSDKException('Unable to get response from Graph as array.', 620); + } + } + + /** + * Validates that the return data can be cast as a GraphNode. + * + * @throws FacebookSDKException + */ + public function validateResponseCastableAsGraphNode() + { + if (isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data'])) { + throw new FacebookSDKException( + 'Unable to convert response from Graph to a GraphNode because the response looks like a GraphEdge. Try using GraphNodeFactory::makeGraphEdge() instead.', + 620 + ); + } + } + + /** + * Validates that the return data can be cast as a GraphEdge. + * + * @throws FacebookSDKException + */ + public function validateResponseCastableAsGraphEdge() + { + if (!(isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data']))) { + throw new FacebookSDKException( + 'Unable to convert response from Graph to a GraphEdge because the response does not look like a GraphEdge. Try using GraphNodeFactory::makeGraphNode() instead.', + 620 + ); + } + } + + /** + * Safely instantiates a GraphNode of $subclassName. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The subclass to cast this collection to. + * + * @return GraphNode + * + * @throws FacebookSDKException + */ + public function safelyMakeGraphNode(array $data, $subclassName = null) + { + $subclassName = $subclassName ?: static::BASE_GRAPH_NODE_CLASS; + static::validateSubclass($subclassName); + + // Remember the parent node ID + $parentNodeId = isset($data['id']) ? $data['id'] : null; + + $items = []; + + foreach ($data as $k => $v) { + // Array means could be recurable + if (is_array($v)) { + // Detect any smart-casting from the $graphObjectMap array. + // This is always empty on the GraphNode collection, but subclasses can define + // their own array of smart-casting types. + $graphObjectMap = $subclassName::getObjectMap(); + $objectSubClass = isset($graphObjectMap[$k]) + ? $graphObjectMap[$k] + : null; + + // Could be a GraphEdge or GraphNode + $items[$k] = $this->castAsGraphNodeOrGraphEdge($v, $objectSubClass, $k, $parentNodeId); + } else { + $items[$k] = $v; + } + } + + return new $subclassName($items); + } + + /** + * Takes an array of values and determines how to cast each node. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The subclass to cast this collection to. + * @param string|null $parentKey The key of this data (Graph edge). + * @param string|null $parentNodeId The parent Graph node ID. + * + * @return GraphNode|GraphEdge + * + * @throws FacebookSDKException + */ + public function castAsGraphNodeOrGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) + { + if (isset($data['data'])) { + // Create GraphEdge + if (static::isCastableAsGraphEdge($data['data'])) { + return $this->safelyMakeGraphEdge($data, $subclassName, $parentKey, $parentNodeId); + } + // Sometimes Graph is a weirdo and returns a GraphNode under the "data" key + $data = $data['data']; + } + + // Create GraphNode + return $this->safelyMakeGraphNode($data, $subclassName); + } + + /** + * Return an array of GraphNode's. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The GraphNode subclass to cast each item in the list to. + * @param string|null $parentKey The key of this data (Graph edge). + * @param string|null $parentNodeId The parent Graph node ID. + * + * @return GraphEdge + * + * @throws FacebookSDKException + */ + public function safelyMakeGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) + { + if (!isset($data['data'])) { + throw new FacebookSDKException('Cannot cast data to GraphEdge. Expected a "data" key.', 620); + } + + $dataList = []; + foreach ($data['data'] as $graphNode) { + $dataList[] = $this->safelyMakeGraphNode($graphNode, $subclassName); + } + + $metaData = $this->getMetaData($data); + + // We'll need to make an edge endpoint for this in case it's a GraphEdge (for cursor pagination) + $parentGraphEdgeEndpoint = $parentNodeId && $parentKey ? '/' . $parentNodeId . '/' . $parentKey : null; + $className = static::BASE_GRAPH_EDGE_CLASS; + + return new $className($this->response->getRequest(), $dataList, $metaData, $parentGraphEdgeEndpoint, $subclassName); + } + + /** + * Get the meta data from a list in a Graph response. + * + * @param array $data The Graph response. + * + * @return array + */ + public function getMetaData(array $data) + { + unset($data['data']); + + return $data; + } + + /** + * Determines whether or not the data should be cast as a GraphEdge. + * + * @param array $data + * + * @return boolean + */ + public static function isCastableAsGraphEdge(array $data) + { + if ($data === []) { + return true; + } + + // Checks for a sequential numeric array which would be a GraphEdge + return array_keys($data) === range(0, count($data) - 1); + } + + /** + * Ensures that the subclass in question is valid. + * + * @param string $subclassName The GraphNode subclass to validate. + * + * @throws FacebookSDKException + */ + public static function validateSubclass($subclassName) + { + if ($subclassName == static::BASE_GRAPH_NODE_CLASS || is_subclass_of($subclassName, static::BASE_GRAPH_NODE_CLASS)) { + return; + } + + throw new FacebookSDKException('The given subclass "' . $subclassName . '" is not valid. Cannot cast to an object that is not a GraphNode subclass.', 620); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php new file mode 100644 index 000000000..0633c405b --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphObject.php @@ -0,0 +1,36 @@ +makeGraphNode($subclassName); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return GraphEvent + * + * @throws FacebookSDKException + */ + public function makeGraphEvent() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent'); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphEdge. + * + * @param string|null $subclassName The GraphNode sub class to cast the list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return GraphEdge + * + * @deprecated 5.0.0 GraphObjectFactory has been renamed to GraphNodeFactory + */ + public function makeGraphList($subclassName = null, $auto_prefix = true) + { + return $this->makeGraphEdge($subclassName, $auto_prefix); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php new file mode 100644 index 000000000..3dfb0e031 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPage.php @@ -0,0 +1,147 @@ + '\Facebook\GraphNodes\GraphPage', + 'global_brand_parent_page' => '\Facebook\GraphNodes\GraphPage', + 'location' => '\Facebook\GraphNodes\GraphLocation', + 'cover' => '\Facebook\GraphNodes\GraphCoverPhoto', + 'picture' => '\Facebook\GraphNodes\GraphPicture', + ]; + + /** + * Returns the ID for the user's page as a string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the Category for the user's page as a string if present. + * + * @return string|null + */ + public function getCategory() + { + return $this->getField('category'); + } + + /** + * Returns the Name of the user's page as a string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the best available Page on Facebook. + * + * @return GraphPage|null + */ + public function getBestPage() + { + return $this->getField('best_page'); + } + + /** + * Returns the brand's global (parent) Page. + * + * @return GraphPage|null + */ + public function getGlobalBrandParentPage() + { + return $this->getField('global_brand_parent_page'); + } + + /** + * Returns the location of this place. + * + * @return GraphLocation|null + */ + public function getLocation() + { + return $this->getField('location'); + } + + /** + * Returns CoverPhoto of the Page. + * + * @return GraphCoverPhoto|null + */ + public function getCover() + { + return $this->getField('cover'); + } + + /** + * Returns Picture of the Page. + * + * @return GraphPicture|null + */ + public function getPicture() + { + return $this->getField('picture'); + } + + /** + * Returns the page access token for the admin user. + * + * Only available in the `/me/accounts` context. + * + * @return string|null + */ + public function getAccessToken() + { + return $this->getField('access_token'); + } + + /** + * Returns the roles of the page admin user. + * + * Only available in the `/me/accounts` context. + * + * @return array|null + */ + public function getPerms() + { + return $this->getField('perms'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php new file mode 100644 index 000000000..10274ec50 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphPicture.php @@ -0,0 +1,72 @@ +getField('is_silhouette'); + } + + /** + * Returns the url of user picture if it exists + * + * @return string|null + */ + public function getUrl() + { + return $this->getField('url'); + } + + /** + * Returns the width of user picture if it exists + * + * @return int|null + */ + public function getWidth() + { + return $this->getField('width'); + } + + /** + * Returns the height of user picture if it exists + * + * @return int|null + */ + public function getHeight() + { + return $this->getField('height'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php new file mode 100644 index 000000000..df8dd358b --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphSessionInfo.php @@ -0,0 +1,102 @@ +getField('app_id'); + } + + /** + * Returns the application name the token was issued for. + * + * @return string|null + */ + public function getApplication() + { + return $this->getField('application'); + } + + /** + * Returns the date & time that the token expires. + * + * @return \DateTime|null + */ + public function getExpiresAt() + { + return $this->getField('expires_at'); + } + + /** + * Returns whether the token is valid. + * + * @return boolean + */ + public function getIsValid() + { + return $this->getField('is_valid'); + } + + /** + * Returns the date & time the token was issued at. + * + * @return \DateTime|null + */ + public function getIssuedAt() + { + return $this->getField('issued_at'); + } + + /** + * Returns the scope permissions associated with the token. + * + * @return array + */ + public function getScopes() + { + return $this->getField('scopes'); + } + + /** + * Returns the login id of the user associated with the token. + * + * @return string|null + */ + public function getUserId() + { + return $this->getField('user_id'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php new file mode 100644 index 000000000..c50d7efd2 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/GraphNodes/GraphUser.php @@ -0,0 +1,172 @@ + '\Facebook\GraphNodes\GraphPage', + 'location' => '\Facebook\GraphNodes\GraphPage', + 'significant_other' => '\Facebook\GraphNodes\GraphUser', + 'picture' => '\Facebook\GraphNodes\GraphPicture', + ]; + + /** + * Returns the ID for the user as a string if present. + * + * @return string|null + */ + public function getId() + { + return $this->getField('id'); + } + + /** + * Returns the name for the user as a string if present. + * + * @return string|null + */ + public function getName() + { + return $this->getField('name'); + } + + /** + * Returns the first name for the user as a string if present. + * + * @return string|null + */ + public function getFirstName() + { + return $this->getField('first_name'); + } + + /** + * Returns the middle name for the user as a string if present. + * + * @return string|null + */ + public function getMiddleName() + { + return $this->getField('middle_name'); + } + + /** + * Returns the last name for the user as a string if present. + * + * @return string|null + */ + public function getLastName() + { + return $this->getField('last_name'); + } + + /** + * Returns the email for the user as a string if present. + * + * @return string|null + */ + public function getEmail() + { + return $this->getField('email'); + } + + /** + * Returns the gender for the user as a string if present. + * + * @return string|null + */ + public function getGender() + { + return $this->getField('gender'); + } + + /** + * Returns the Facebook URL for the user as a string if available. + * + * @return string|null + */ + public function getLink() + { + return $this->getField('link'); + } + + /** + * Returns the users birthday, if available. + * + * @return \DateTime|null + */ + public function getBirthday() + { + return $this->getField('birthday'); + } + + /** + * Returns the current location of the user as a GraphPage. + * + * @return GraphPage|null + */ + public function getLocation() + { + return $this->getField('location'); + } + + /** + * Returns the current location of the user as a GraphPage. + * + * @return GraphPage|null + */ + public function getHometown() + { + return $this->getField('hometown'); + } + + /** + * Returns the current location of the user as a GraphUser. + * + * @return GraphUser|null + */ + public function getSignificantOther() + { + return $this->getField('significant_other'); + } + + /** + * Returns the picture of the user as a GraphPicture + * + * @return GraphPicture|null + */ + public function getPicture() + { + return $this->getField('picture'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php new file mode 100644 index 000000000..7f3466ff7 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookCanvasHelper.php @@ -0,0 +1,52 @@ +signedRequest ? $this->signedRequest->get('app_data') : null; + } + + /** + * Get raw signed request from POST. + * + * @return string|null + */ + public function getRawSignedRequest() + { + return $this->getRawSignedRequestFromPost() ?: null; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php new file mode 100644 index 000000000..01a76b8b2 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookJavaScriptHelper.php @@ -0,0 +1,42 @@ +getRawSignedRequestFromCookie(); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php new file mode 100644 index 000000000..da2c356c7 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookPageTabHelper.php @@ -0,0 +1,95 @@ +signedRequest) { + return; + } + + $this->pageData = $this->signedRequest->get('page'); + } + + /** + * Returns a value from the page data. + * + * @param string $key + * @param mixed|null $default + * + * @return mixed|null + */ + public function getPageData($key, $default = null) + { + if (isset($this->pageData[$key])) { + return $this->pageData[$key]; + } + + return $default; + } + + /** + * Returns true if the user is an admin. + * + * @return boolean + */ + public function isAdmin() + { + return $this->getPageData('admin') === true; + } + + /** + * Returns the page id if available. + * + * @return string|null + */ + public function getPageId() + { + return $this->getPageData('id'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php new file mode 100644 index 000000000..4a0755a44 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookRedirectLoginHelper.php @@ -0,0 +1,333 @@ +oAuth2Client = $oAuth2Client; + $this->persistentDataHandler = $persistentDataHandler ?: new FacebookSessionPersistentDataHandler(); + $this->urlDetectionHandler = $urlHandler ?: new FacebookUrlDetectionHandler(); + $this->pseudoRandomStringGenerator = PseudoRandomStringGeneratorFactory::createPseudoRandomStringGenerator($prsg); + } + + /** + * Returns the persistent data handler. + * + * @return PersistentDataInterface + */ + public function getPersistentDataHandler() + { + return $this->persistentDataHandler; + } + + /** + * Returns the URL detection handler. + * + * @return UrlDetectionInterface + */ + public function getUrlDetectionHandler() + { + return $this->urlDetectionHandler; + } + + /** + * Returns the cryptographically secure pseudo-random string generator. + * + * @return PseudoRandomStringGeneratorInterface + */ + public function getPseudoRandomStringGenerator() + { + return $this->pseudoRandomStringGenerator; + } + + /** + * Stores CSRF state and returns a URL to which the user should be sent to in order to continue the login process with Facebook. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param array $params An array of parameters to generate URL. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&') + { + $state = $this->persistentDataHandler->get('state') ?: $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH); + $this->persistentDataHandler->set('state', $state); + + return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator); + } + + /** + * Returns the URL to send the user in order to login to Facebook. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getLoginUrl($redirectUrl, array $scope = [], $separator = '&') + { + return $this->makeUrl($redirectUrl, $scope, [], $separator); + } + + /** + * Returns the URL to send the user in order to log out of Facebook. + * + * @param AccessToken|string $accessToken The access token that will be logged out. + * @param string $next The url Facebook should redirect the user to after a successful logout. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + * + * @throws FacebookSDKException + */ + public function getLogoutUrl($accessToken, $next, $separator = '&') + { + if (!$accessToken instanceof AccessToken) { + $accessToken = new AccessToken($accessToken); + } + + if ($accessToken->isAppAccessToken()) { + throw new FacebookSDKException('Cannot generate a logout URL with an app access token.', 722); + } + + $params = [ + 'next' => $next, + 'access_token' => $accessToken->getValue(), + ]; + + return 'https://www.facebook.com/logout.php?' . http_build_query($params, null, $separator); + } + + /** + * Returns the URL to send the user in order to login to Facebook with permission(s) to be re-asked. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getReRequestUrl($redirectUrl, array $scope = [], $separator = '&') + { + $params = ['auth_type' => 'rerequest']; + + return $this->makeUrl($redirectUrl, $scope, $params, $separator); + } + + /** + * Returns the URL to send the user in order to login to Facebook with user to be re-authenticated. + * + * @param string $redirectUrl The URL Facebook should redirect users to after login. + * @param array $scope List of permissions to request during login. + * @param string $separator The separator to use in http_build_query(). + * + * @return string + */ + public function getReAuthenticationUrl($redirectUrl, array $scope = [], $separator = '&') + { + $params = ['auth_type' => 'reauthenticate']; + + return $this->makeUrl($redirectUrl, $scope, $params, $separator); + } + + /** + * Takes a valid code from a login redirect, and returns an AccessToken entity. + * + * @param string|null $redirectUrl The redirect URL. + * + * @return AccessToken|null + * + * @throws FacebookSDKException + */ + public function getAccessToken($redirectUrl = null) + { + if (!$code = $this->getCode()) { + return null; + } + + $this->validateCsrf(); + $this->resetCsrf(); + + $redirectUrl = $redirectUrl ?: $this->urlDetectionHandler->getCurrentUrl(); + // At minimum we need to remove the state param + $redirectUrl = FacebookUrlManipulator::removeParamsFromUrl($redirectUrl, ['state']); + + return $this->oAuth2Client->getAccessTokenFromCode($code, $redirectUrl); + } + + /** + * Validate the request against a cross-site request forgery. + * + * @throws FacebookSDKException + */ + protected function validateCsrf() + { + $state = $this->getState(); + if (!$state) { + throw new FacebookSDKException('Cross-site request forgery validation failed. Required GET param "state" missing.'); + } + $savedState = $this->persistentDataHandler->get('state'); + if (!$savedState) { + throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing from persistent data.'); + } + + if (\hash_equals($savedState, $state)) { + return; + } + + throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.'); + } + + /** + * Resets the CSRF so that it doesn't get reused. + */ + private function resetCsrf() + { + $this->persistentDataHandler->set('state', null); + } + + /** + * Return the code. + * + * @return string|null + */ + protected function getCode() + { + return $this->getInput('code'); + } + + /** + * Return the state. + * + * @return string|null + */ + protected function getState() + { + return $this->getInput('state'); + } + + /** + * Return the error code. + * + * @return string|null + */ + public function getErrorCode() + { + return $this->getInput('error_code'); + } + + /** + * Returns the error. + * + * @return string|null + */ + public function getError() + { + return $this->getInput('error'); + } + + /** + * Returns the error reason. + * + * @return string|null + */ + public function getErrorReason() + { + return $this->getInput('error_reason'); + } + + /** + * Returns the error description. + * + * @return string|null + */ + public function getErrorDescription() + { + return $this->getInput('error_description'); + } + + /** + * Returns a value from a GET param. + * + * @param string $key + * + * @return string|null + */ + private function getInput($key) + { + return isset($_GET[$key]) ? $_GET[$key] : null; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php new file mode 100644 index 000000000..4044da107 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Helpers/FacebookSignedRequestFromInputHelper.php @@ -0,0 +1,166 @@ +app = $app; + $graphVersion = $graphVersion ?: Facebook::DEFAULT_GRAPH_VERSION; + $this->oAuth2Client = new OAuth2Client($this->app, $client, $graphVersion); + + $this->instantiateSignedRequest(); + } + + /** + * Instantiates a new SignedRequest entity. + * + * @param string|null + */ + public function instantiateSignedRequest($rawSignedRequest = null) + { + $rawSignedRequest = $rawSignedRequest ?: $this->getRawSignedRequest(); + + if (!$rawSignedRequest) { + return; + } + + $this->signedRequest = new SignedRequest($this->app, $rawSignedRequest); + } + + /** + * Returns an AccessToken entity from the signed request. + * + * @return AccessToken|null + * + * @throws \Facebook\Exceptions\FacebookSDKException + */ + public function getAccessToken() + { + if ($this->signedRequest && $this->signedRequest->hasOAuthData()) { + $code = $this->signedRequest->get('code'); + $accessToken = $this->signedRequest->get('oauth_token'); + + if ($code && !$accessToken) { + return $this->oAuth2Client->getAccessTokenFromCode($code); + } + + $expiresAt = $this->signedRequest->get('expires', 0); + + return new AccessToken($accessToken, $expiresAt); + } + + return null; + } + + /** + * Returns the SignedRequest entity. + * + * @return SignedRequest|null + */ + public function getSignedRequest() + { + return $this->signedRequest; + } + + /** + * Returns the user_id if available. + * + * @return string|null + */ + public function getUserId() + { + return $this->signedRequest ? $this->signedRequest->getUserId() : null; + } + + /** + * Get raw signed request from input. + * + * @return string|null + */ + abstract public function getRawSignedRequest(); + + /** + * Get raw signed request from POST input. + * + * @return string|null + */ + public function getRawSignedRequestFromPost() + { + if (isset($_POST['signed_request'])) { + return $_POST['signed_request']; + } + + return null; + } + + /** + * Get raw signed request from cookie set from the Javascript SDK. + * + * @return string|null + */ + public function getRawSignedRequestFromCookie() + { + if (isset($_COOKIE['fbsr_' . $this->app->getId()])) { + return $_COOKIE['fbsr_' . $this->app->getId()]; + } + + return null; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php new file mode 100644 index 000000000..d1a7241c8 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/GraphRawResponse.php @@ -0,0 +1,137 @@ +httpResponseCode = (int)$httpStatusCode; + } + + if (is_array($headers)) { + $this->headers = $headers; + } else { + $this->setHeadersFromString($headers); + } + + $this->body = $body; + } + + /** + * Return the response headers. + * + * @return array + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * Return the body of the response. + * + * @return string + */ + public function getBody() + { + return $this->body; + } + + /** + * Return the HTTP response code. + * + * @return int + */ + public function getHttpResponseCode() + { + return $this->httpResponseCode; + } + + /** + * Sets the HTTP response code from a raw header. + * + * @param string $rawResponseHeader + */ + public function setHttpResponseCodeFromHeader($rawResponseHeader) + { + preg_match('|HTTP/\d\.\d\s+(\d+)\s+.*|', $rawResponseHeader, $match); + $this->httpResponseCode = (int)$match[1]; + } + + /** + * Parse the raw headers and set as an array. + * + * @param string $rawHeaders The raw headers from the response. + */ + protected function setHeadersFromString($rawHeaders) + { + // Normalize line breaks + $rawHeaders = str_replace("\r\n", "\n", $rawHeaders); + + // There will be multiple headers if a 301 was followed + // or a proxy was followed, etc + $headerCollection = explode("\n\n", trim($rawHeaders)); + // We just want the last response (at the end) + $rawHeader = array_pop($headerCollection); + + $headerComponents = explode("\n", $rawHeader); + foreach ($headerComponents as $line) { + if (strpos($line, ': ') === false) { + $this->setHttpResponseCodeFromHeader($line); + } else { + list($key, $value) = explode(': ', $line, 2); + $this->headers[$key] = $value; + } + } + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php new file mode 100644 index 000000000..1c03f4fd7 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyInterface.php @@ -0,0 +1,39 @@ +params = $params; + $this->files = $files; + $this->boundary = $boundary ?: uniqid(); + } + + /** + * @inheritdoc + */ + public function getBody() + { + $body = ''; + + // Compile normal params + $params = $this->getNestedParams($this->params); + foreach ($params as $k => $v) { + $body .= $this->getParamString($k, $v); + } + + // Compile files + foreach ($this->files as $k => $v) { + $body .= $this->getFileString($k, $v); + } + + // Peace out + $body .= "--{$this->boundary}--\r\n"; + + return $body; + } + + /** + * Get the boundary + * + * @return string + */ + public function getBoundary() + { + return $this->boundary; + } + + /** + * Get the string needed to transfer a file. + * + * @param string $name + * @param FacebookFile $file + * + * @return string + */ + private function getFileString($name, FacebookFile $file) + { + return sprintf( + "--%s\r\nContent-Disposition: form-data; name=\"%s\"; filename=\"%s\"%s\r\n\r\n%s\r\n", + $this->boundary, + $name, + $file->getFileName(), + $this->getFileHeaders($file), + $file->getContents() + ); + } + + /** + * Get the string needed to transfer a POST field. + * + * @param string $name + * @param string $value + * + * @return string + */ + private function getParamString($name, $value) + { + return sprintf( + "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", + $this->boundary, + $name, + $value + ); + } + + /** + * Returns the params as an array of nested params. + * + * @param array $params + * + * @return array + */ + private function getNestedParams(array $params) + { + $query = http_build_query($params, null, '&'); + $params = explode('&', $query); + $result = []; + + foreach ($params as $param) { + list($key, $value) = explode('=', $param, 2); + $result[urldecode($key)] = urldecode($value); + } + + return $result; + } + + /** + * Get the headers needed before transferring the content of a POST file. + * + * @param FacebookFile $file + * + * @return string + */ + protected function getFileHeaders(FacebookFile $file) + { + return "\r\nContent-Type: {$file->getMimetype()}"; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php new file mode 100644 index 000000000..c1e35f43d --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Http/RequestBodyUrlEncoded.php @@ -0,0 +1,55 @@ +params = $params; + } + + /** + * @inheritdoc + */ + public function getBody() + { + return http_build_query($this->params, null, '&'); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php new file mode 100644 index 000000000..28e4ba598 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurl.php @@ -0,0 +1,129 @@ +curl = curl_init(); + } + + /** + * Set a curl option + * + * @param $key + * @param $value + */ + public function setopt($key, $value) + { + curl_setopt($this->curl, $key, $value); + } + + /** + * Set an array of options to a curl resource + * + * @param array $options + */ + public function setoptArray(array $options) + { + curl_setopt_array($this->curl, $options); + } + + /** + * Send a curl request + * + * @return mixed + */ + public function exec() + { + return curl_exec($this->curl); + } + + /** + * Return the curl error number + * + * @return int + */ + public function errno() + { + return curl_errno($this->curl); + } + + /** + * Return the curl error message + * + * @return string + */ + public function error() + { + return curl_error($this->curl); + } + + /** + * Get info from a curl reference + * + * @param $type + * + * @return mixed + */ + public function getinfo($type) + { + return curl_getinfo($this->curl, $type); + } + + /** + * Get the currently installed curl version + * + * @return array + */ + public function version() + { + return curl_version(); + } + + /** + * Close the resource connection to curl + */ + public function close() + { + curl_close($this->curl); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php new file mode 100644 index 000000000..059e75a50 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookCurlHttpClient.php @@ -0,0 +1,163 @@ +facebookCurl = $facebookCurl ?: new FacebookCurl(); + } + + /** + * @inheritdoc + */ + public function send($url, $method, $body, array $headers, $timeOut) + { + $this->openConnection($url, $method, $body, $headers, $timeOut); + $this->sendRequest(); + + if ($curlErrorCode = $this->facebookCurl->errno()) { + throw new FacebookSDKException($this->facebookCurl->error(), $curlErrorCode); + } + + // Separate the raw headers from the raw body + list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody(); + + $this->closeConnection(); + + return new GraphRawResponse($rawHeaders, $rawBody); + } + + /** + * Opens a new curl connection. + * + * @param string $url The endpoint to send the request to. + * @param string $method The request method. + * @param string $body The body of the request. + * @param array $headers The request headers. + * @param int $timeOut The timeout in seconds for the request. + */ + public function openConnection($url, $method, $body, array $headers, $timeOut) + { + $options = [ + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_HTTPHEADER => $this->compileRequestHeaders($headers), + CURLOPT_URL => $url, + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_TIMEOUT => $timeOut, + CURLOPT_RETURNTRANSFER => true, // Follow 301 redirects + CURLOPT_HEADER => true, // Enable header processing + CURLOPT_SSL_VERIFYHOST => 2, + CURLOPT_SSL_VERIFYPEER => true, + CURLOPT_CAINFO => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', + ]; + + if ($method !== "GET") { + $options[CURLOPT_POSTFIELDS] = $body; + } + + $this->facebookCurl->init(); + $this->facebookCurl->setoptArray($options); + } + + /** + * Closes an existing curl connection + */ + public function closeConnection() + { + $this->facebookCurl->close(); + } + + /** + * Send the request and get the raw response from curl + */ + public function sendRequest() + { + $this->rawResponse = $this->facebookCurl->exec(); + } + + /** + * Compiles the request headers into a curl-friendly format. + * + * @param array $headers The request headers. + * + * @return array + */ + public function compileRequestHeaders(array $headers) + { + $return = []; + + foreach ($headers as $key => $value) { + $return[] = $key . ': ' . $value; + } + + return $return; + } + + /** + * Extracts the headers and the body into a two-part array + * + * @return array + */ + public function extractResponseHeadersAndBody() + { + $parts = explode("\r\n\r\n", $this->rawResponse); + $rawBody = array_pop($parts); + $rawHeaders = implode("\r\n\r\n", $parts); + + return [trim($rawHeaders), trim($rawBody)]; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php new file mode 100644 index 000000000..8feb7cb6d --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookGuzzleHttpClient.php @@ -0,0 +1,97 @@ +guzzleClient = $guzzleClient ?: new Client(); + } + + /** + * @inheritdoc + */ + public function send($url, $method, $body, array $headers, $timeOut) + { + $options = [ + 'headers' => $headers, + 'body' => $body, + 'timeout' => $timeOut, + 'connect_timeout' => 10, + 'verify' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', + ]; + $request = $this->guzzleClient->createRequest($method, $url, $options); + + try { + $rawResponse = $this->guzzleClient->send($request); + } catch (RequestException $e) { + $rawResponse = $e->getResponse(); + + if ($e->getPrevious() instanceof RingException || !$rawResponse instanceof ResponseInterface) { + throw new FacebookSDKException($e->getMessage(), $e->getCode()); + } + } + + $rawHeaders = $this->getHeadersAsString($rawResponse); + $rawBody = $rawResponse->getBody(); + $httpStatusCode = $rawResponse->getStatusCode(); + + return new GraphRawResponse($rawHeaders, $rawBody, $httpStatusCode); + } + + /** + * Returns the Guzzle array of headers as a string. + * + * @param ResponseInterface $response The Guzzle response. + * + * @return string + */ + public function getHeadersAsString(ResponseInterface $response) + { + $headers = $response->getHeaders(); + $rawHeaders = []; + foreach ($headers as $name => $values) { + $rawHeaders[] = $name . ": " . implode(", ", $values); + } + + return implode("\r\n", $rawHeaders); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php new file mode 100644 index 000000000..1fbf953d8 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookHttpClientInterface.php @@ -0,0 +1,47 @@ +stream = stream_context_create($options); + } + + /** + * The response headers from the stream wrapper + * + * @return array + */ + public function getResponseHeaders() + { + return $this->responseHeaders; + } + + /** + * Send a stream wrapped request + * + * @param string $url + * + * @return mixed + */ + public function fileGetContents($url) + { + $rawResponse = file_get_contents($url, false, $this->stream); + $this->responseHeaders = $http_response_header ?: []; + + return $rawResponse; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php new file mode 100644 index 000000000..1cdfd5398 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/FacebookStreamHttpClient.php @@ -0,0 +1,94 @@ +facebookStream = $facebookStream ?: new FacebookStream(); + } + + /** + * @inheritdoc + */ + public function send($url, $method, $body, array $headers, $timeOut) + { + $options = [ + 'http' => [ + 'method' => $method, + 'header' => $this->compileHeader($headers), + 'content' => $body, + 'timeout' => $timeOut, + 'ignore_errors' => true + ], + 'ssl' => [ + 'verify_peer' => true, + 'verify_peer_name' => true, + 'allow_self_signed' => true, // All root certificates are self-signed + 'cafile' => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', + ], + ]; + + $this->facebookStream->streamContextCreate($options); + $rawBody = $this->facebookStream->fileGetContents($url); + $rawHeaders = $this->facebookStream->getResponseHeaders(); + + if ($rawBody === false || empty($rawHeaders)) { + throw new FacebookSDKException('Stream returned an empty response', 660); + } + + $rawHeaders = implode("\r\n", $rawHeaders); + + return new GraphRawResponse($rawHeaders, $rawBody); + } + + /** + * Formats the headers for use in the stream wrapper. + * + * @param array $headers The request headers. + * + * @return string + */ + public function compileHeader(array $headers) + { + $header = []; + foreach ($headers as $k => $v) { + $header[] = $k . ': ' . $v; + } + + return implode("\r\n", $header); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php new file mode 100644 index 000000000..d9f2a8d3d --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/HttpClients/HttpClientsFactory.php @@ -0,0 +1,99 @@ +sessionData[$key]) ? $this->sessionData[$key] : null; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + $this->sessionData[$key] = $value; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php new file mode 100644 index 000000000..9123e3dc7 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/FacebookSessionPersistentDataHandler.php @@ -0,0 +1,76 @@ +sessionPrefix . $key])) { + return $_SESSION[$this->sessionPrefix . $key]; + } + + return null; + } + + /** + * @inheritdoc + */ + public function set($key, $value) + { + $_SESSION[$this->sessionPrefix . $key] = $value; + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php new file mode 100644 index 000000000..18fb8fd5b --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PersistentData/PersistentDataFactory.php @@ -0,0 +1,65 @@ +validateLength($length); + + $binaryString = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); + + if ($binaryString === false) { + throw new FacebookSDKException( + static::ERROR_MESSAGE . + 'mcrypt_create_iv() returned an error.' + ); + } + + return $this->binToHex($binaryString, $length); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php new file mode 100644 index 000000000..4b4276dc7 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/OpenSslPseudoRandomStringGenerator.php @@ -0,0 +1,67 @@ +validateLength($length); + + $wasCryptographicallyStrong = false; + $binaryString = openssl_random_pseudo_bytes($length, $wasCryptographicallyStrong); + + if ($binaryString === false) { + throw new FacebookSDKException(static::ERROR_MESSAGE . 'openssl_random_pseudo_bytes() returned an unknown error.'); + } + + if ($wasCryptographicallyStrong !== true) { + throw new FacebookSDKException(static::ERROR_MESSAGE . 'openssl_random_pseudo_bytes() returned a pseudo-random string but it was not cryptographically secure and cannot be used.'); + } + + return $this->binToHex($binaryString, $length); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php new file mode 100644 index 000000000..412f48135 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/PseudoRandomStringGeneratorFactory.php @@ -0,0 +1,101 @@ +validateLength($length); + + return $this->binToHex(random_bytes($length), $length); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php new file mode 100644 index 000000000..5ab434e6e --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/PseudoRandomString/UrandomPseudoRandomStringGenerator.php @@ -0,0 +1,89 @@ +validateLength($length); + + $stream = fopen('/dev/urandom', 'rb'); + if (!is_resource($stream)) { + throw new FacebookSDKException( + static::ERROR_MESSAGE . + 'Unable to open stream to /dev/urandom.' + ); + } + + if (!defined('HHVM_VERSION')) { + stream_set_read_buffer($stream, 0); + } + + $binaryString = fread($stream, $length); + fclose($stream); + + if (!$binaryString) { + throw new FacebookSDKException( + static::ERROR_MESSAGE . + 'Stream to /dev/urandom returned no data.' + ); + } + + return $this->binToHex($binaryString, $length); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php new file mode 100644 index 000000000..6a175a0a2 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/SignedRequest.php @@ -0,0 +1,326 @@ +app = $facebookApp; + + if (!$rawSignedRequest) { + return; + } + + $this->rawSignedRequest = $rawSignedRequest; + + $this->parse(); + } + + /** + * Returns the raw signed request data. + * + * @return string|null + */ + public function getRawSignedRequest() + { + return $this->rawSignedRequest; + } + + /** + * Returns the parsed signed request data. + * + * @return array|null + */ + public function getPayload() + { + return $this->payload; + } + + /** + * Returns a property from the signed request data if available. + * + * @param string $key + * @param mixed|null $default + * + * @return mixed|null + */ + public function get($key, $default = null) + { + if (isset($this->payload[$key])) { + return $this->payload[$key]; + } + + return $default; + } + + /** + * Returns user_id from signed request data if available. + * + * @return string|null + */ + public function getUserId() + { + return $this->get('user_id'); + } + + /** + * Checks for OAuth data in the payload. + * + * @return boolean + */ + public function hasOAuthData() + { + return $this->get('oauth_token') || $this->get('code'); + } + + /** + * Creates a signed request from an array of data. + * + * @param array $payload + * + * @return string + */ + public function make(array $payload) + { + $payload['algorithm'] = isset($payload['algorithm']) ? $payload['algorithm'] : 'HMAC-SHA256'; + $payload['issued_at'] = isset($payload['issued_at']) ? $payload['issued_at'] : time(); + $encodedPayload = $this->base64UrlEncode(json_encode($payload)); + + $hashedSig = $this->hashSignature($encodedPayload); + $encodedSig = $this->base64UrlEncode($hashedSig); + + return $encodedSig . '.' . $encodedPayload; + } + + /** + * Validates and decodes a signed request and saves + * the payload to an array. + */ + protected function parse() + { + list($encodedSig, $encodedPayload) = $this->split(); + + // Signature validation + $sig = $this->decodeSignature($encodedSig); + $hashedSig = $this->hashSignature($encodedPayload); + $this->validateSignature($hashedSig, $sig); + + $this->payload = $this->decodePayload($encodedPayload); + + // Payload validation + $this->validateAlgorithm(); + } + + /** + * Splits a raw signed request into signature and payload. + * + * @return array + * + * @throws FacebookSDKException + */ + protected function split() + { + if (strpos($this->rawSignedRequest, '.') === false) { + throw new FacebookSDKException('Malformed signed request.', 606); + } + + return explode('.', $this->rawSignedRequest, 2); + } + + /** + * Decodes the raw signature from a signed request. + * + * @param string $encodedSig + * + * @return string + * + * @throws FacebookSDKException + */ + protected function decodeSignature($encodedSig) + { + $sig = $this->base64UrlDecode($encodedSig); + + if (!$sig) { + throw new FacebookSDKException('Signed request has malformed encoded signature data.', 607); + } + + return $sig; + } + + /** + * Decodes the raw payload from a signed request. + * + * @param string $encodedPayload + * + * @return array + * + * @throws FacebookSDKException + */ + protected function decodePayload($encodedPayload) + { + $payload = $this->base64UrlDecode($encodedPayload); + + if ($payload) { + $payload = json_decode($payload, true); + } + + if (!is_array($payload)) { + throw new FacebookSDKException('Signed request has malformed encoded payload data.', 607); + } + + return $payload; + } + + /** + * Validates the algorithm used in a signed request. + * + * @throws FacebookSDKException + */ + protected function validateAlgorithm() + { + if ($this->get('algorithm') !== 'HMAC-SHA256') { + throw new FacebookSDKException('Signed request is using the wrong algorithm.', 605); + } + } + + /** + * Hashes the signature used in a signed request. + * + * @param string $encodedData + * + * @return string + * + * @throws FacebookSDKException + */ + protected function hashSignature($encodedData) + { + $hashedSig = hash_hmac( + 'sha256', + $encodedData, + $this->app->getSecret(), + $raw_output = true + ); + + if (!$hashedSig) { + throw new FacebookSDKException('Unable to hash signature from encoded payload data.', 602); + } + + return $hashedSig; + } + + /** + * Validates the signature used in a signed request. + * + * @param string $hashedSig + * @param string $sig + * + * @throws FacebookSDKException + */ + protected function validateSignature($hashedSig, $sig) + { + if (\hash_equals($hashedSig, $sig)) { + return; + } + + throw new FacebookSDKException('Signed request has an invalid signature.', 602); + } + + /** + * Base64 decoding which replaces characters: + * + instead of - + * / instead of _ + * + * @link http://en.wikipedia.org/wiki/Base64#URL_applications + * + * @param string $input base64 url encoded input + * + * @return string decoded string + */ + public function base64UrlDecode($input) + { + $urlDecodedBase64 = strtr($input, '-_', '+/'); + $this->validateBase64($urlDecodedBase64); + + return base64_decode($urlDecodedBase64); + } + + /** + * Base64 encoding which replaces characters: + * + instead of - + * / instead of _ + * + * @link http://en.wikipedia.org/wiki/Base64#URL_applications + * + * @param string $input string to encode + * + * @return string base64 url encoded input + */ + public function base64UrlEncode($input) + { + return strtr(base64_encode($input), '+/', '-_'); + } + + /** + * Validates a base64 string. + * + * @param string $input base64 value to validate + * + * @throws FacebookSDKException + */ + protected function validateBase64($input) + { + if (!preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $input)) { + throw new FacebookSDKException('Signed request contains malformed base64 encoding.', 608); + } + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php new file mode 100644 index 000000000..1d134ddcb --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlDetectionHandler.php @@ -0,0 +1,182 @@ +getHttpScheme() . '://' . $this->getHostName() . $this->getServerVar('REQUEST_URI'); + } + + /** + * Get the currently active URL scheme. + * + * @return string + */ + protected function getHttpScheme() + { + return $this->isBehindSsl() ? 'https' : 'http'; + } + + /** + * Tries to detect if the server is running behind an SSL. + * + * @return boolean + */ + protected function isBehindSsl() + { + // Check for proxy first + $protocol = $this->getHeader('X_FORWARDED_PROTO'); + if ($protocol) { + return $this->protocolWithActiveSsl($protocol); + } + + $protocol = $this->getServerVar('HTTPS'); + if ($protocol) { + return $this->protocolWithActiveSsl($protocol); + } + + return (string)$this->getServerVar('SERVER_PORT') === '443'; + } + + /** + * Detects an active SSL protocol value. + * + * @param string $protocol + * + * @return boolean + */ + protected function protocolWithActiveSsl($protocol) + { + $protocol = strtolower((string)$protocol); + + return in_array($protocol, ['on', '1', 'https', 'ssl'], true); + } + + /** + * Tries to detect the host name of the server. + * + * Some elements adapted from + * + * @see https://github.com/symfony/HttpFoundation/blob/master/Request.php + * + * @return string + */ + protected function getHostName() + { + // Check for proxy first + $header = $this->getHeader('X_FORWARDED_HOST'); + if ($header && $this->isValidForwardedHost($header)) { + $elements = explode(',', $header); + $host = $elements[count($elements) - 1]; + } elseif (!$host = $this->getHeader('HOST')) { + if (!$host = $this->getServerVar('SERVER_NAME')) { + $host = $this->getServerVar('SERVER_ADDR'); + } + } + + // trim and remove port number from host + // host is lowercase as per RFC 952/2181 + $host = strtolower(preg_replace('/:\d+$/', '', trim($host))); + + // Port number + $scheme = $this->getHttpScheme(); + $port = $this->getCurrentPort(); + $appendPort = ':' . $port; + + // Don't append port number if a normal port. + if (($scheme == 'http' && $port == '80') || ($scheme == 'https' && $port == '443')) { + $appendPort = ''; + } + + return $host . $appendPort; + } + + protected function getCurrentPort() + { + // Check for proxy first + $port = $this->getHeader('X_FORWARDED_PORT'); + if ($port) { + return (string)$port; + } + + $protocol = (string)$this->getHeader('X_FORWARDED_PROTO'); + if ($protocol === 'https') { + return '443'; + } + + return (string)$this->getServerVar('SERVER_PORT'); + } + + /** + * Returns the a value from the $_SERVER super global. + * + * @param string $key + * + * @return string + */ + protected function getServerVar($key) + { + return isset($_SERVER[$key]) ? $_SERVER[$key] : ''; + } + + /** + * Gets a value from the HTTP request headers. + * + * @param string $key + * + * @return string + */ + protected function getHeader($key) + { + return $this->getServerVar('HTTP_' . $key); + } + + /** + * Checks if the value in X_FORWARDED_HOST is a valid hostname + * Could prevent unintended redirections + * + * @param string $header + * + * @return boolean + */ + protected function isValidForwardedHost($header) + { + $elements = explode(',', $header); + $host = $elements[count($elements) - 1]; + + return preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $host) //valid chars check + && 0 < strlen($host) && strlen($host) < 254 //overall length check + && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $host); //length of each label + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php new file mode 100644 index 000000000..daeab9c52 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/FacebookUrlManipulator.php @@ -0,0 +1,167 @@ + 0) { + $query = '?' . http_build_query($params, null, '&'); + } + } + + $scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : ''; + $host = isset($parts['host']) ? $parts['host'] : ''; + $port = isset($parts['port']) ? ':' . $parts['port'] : ''; + $path = isset($parts['path']) ? $parts['path'] : ''; + $fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : ''; + + return $scheme . $host . $port . $path . $query . $fragment; + } + + /** + * Gracefully appends params to the URL. + * + * @param string $url The URL that will receive the params. + * @param array $newParams The params to append to the URL. + * + * @return string + */ + public static function appendParamsToUrl($url, array $newParams = []) + { + if (empty($newParams)) { + return $url; + } + + if (strpos($url, '?') === false) { + return $url . '?' . http_build_query($newParams, null, '&'); + } + + list($path, $query) = explode('?', $url, 2); + $existingParams = []; + parse_str($query, $existingParams); + + // Favor params from the original URL over $newParams + $newParams = array_merge($newParams, $existingParams); + + // Sort for a predicable order + ksort($newParams); + + return $path . '?' . http_build_query($newParams, null, '&'); + } + + /** + * Returns the params from a URL in the form of an array. + * + * @param string $url The URL to parse the params from. + * + * @return array + */ + public static function getParamsAsArray($url) + { + $query = parse_url($url, PHP_URL_QUERY); + if (!$query) { + return []; + } + $params = []; + parse_str($query, $params); + + return $params; + } + + /** + * Adds the params of the first URL to the second URL. + * + * Any params that already exist in the second URL will go untouched. + * + * @param string $urlToStealFrom The URL harvest the params from. + * @param string $urlToAddTo The URL that will receive the new params. + * + * @return string The $urlToAddTo with any new params from $urlToStealFrom. + */ + public static function mergeUrlParams($urlToStealFrom, $urlToAddTo) + { + $newParams = static::getParamsAsArray($urlToStealFrom); + // Nothing new to add, return as-is + if (!$newParams) { + return $urlToAddTo; + } + + return static::appendParamsToUrl($urlToAddTo, $newParams); + } + + /** + * Check for a "/" prefix and prepend it if not exists. + * + * @param string|null $string + * + * @return string|null + */ + public static function forceSlashPrefix($string) + { + if (!$string) { + return $string; + } + + return strpos($string, '/') === 0 ? $string : '/' . $string; + } + + /** + * Trims off the hostname and Graph version from a URL. + * + * @param string $urlToTrim The URL the needs the surgery. + * + * @return string The $urlToTrim with the hostname and Graph version removed. + */ + public static function baseGraphUrlEndpoint($urlToTrim) + { + return '/' . preg_replace('/^https:\/\/.+\.facebook\.com(\/v.+?)?\//', '', $urlToTrim); + } +} diff --git a/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php new file mode 100644 index 000000000..dca38a0c3 --- /dev/null +++ b/e107_handlers/hybridauth/vendor/facebook/graph-sdk/src/Facebook/Url/UrlDetectionInterface.php @@ -0,0 +1,39 @@ +