Passed
Push — master ( 9b5e8a...c84f58 )
by
unknown
01:02 queued 12s
created
src/Provider/Slack.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -52,7 +52,7 @@  discard block
 block discarded – undo
52 52
 
53 53
         $data = new Data\Collection($response);
54 54
 
55
-        if (!$data->exists('ok') || !$data->get('ok')) {
55
+        if ( ! $data->exists('ok') || ! $data->get('ok')) {
56 56
             throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
57 57
         }
58 58
 
@@ -87,14 +87,14 @@  discard block
 block discarded – undo
87 87
         $maxSize = 0;
88 88
         foreach ($data->filter('user')->properties() as $property) {
89 89
             if (preg_match('/^image_(\d+)$/', $property, $matches) === 1) {
90
-                $availableSize = (int)$matches[1];
90
+                $availableSize = (int) $matches[1];
91 91
                 if ($maxSize < $availableSize) {
92 92
                     $maxSize = $availableSize;
93 93
                 }
94 94
             }
95 95
         }
96 96
         if ($maxSize > 0) {
97
-            return $data->filter('user')->get('image_' . $maxSize);
97
+            return $data->filter('user')->get('image_'.$maxSize);
98 98
         }
99 99
         return null;
100 100
     }
Please login to merge, or discard this patch.
Indentation   +69 added lines, -69 removed lines patch added patch discarded remove patch
@@ -17,84 +17,84 @@
 block discarded – undo
17 17
  */
18 18
 class Slack extends OAuth2
19 19
 {
20
-    /**
21
-     * {@inheritdoc}
22
-     */
23
-    protected $scope = 'identity.basic identity.email identity.avatar';
20
+	/**
21
+	 * {@inheritdoc}
22
+	 */
23
+	protected $scope = 'identity.basic identity.email identity.avatar';
24 24
 
25
-    /**
26
-     * {@inheritdoc}
27
-     */
28
-    protected $apiBaseUrl = 'https://slack.com/';
25
+	/**
26
+	 * {@inheritdoc}
27
+	 */
28
+	protected $apiBaseUrl = 'https://slack.com/';
29 29
 
30
-    /**
31
-     * {@inheritdoc}
32
-     */
33
-    protected $authorizeUrl = 'https://slack.com/oauth/authorize';
30
+	/**
31
+	 * {@inheritdoc}
32
+	 */
33
+	protected $authorizeUrl = 'https://slack.com/oauth/authorize';
34 34
 
35
-    /**
36
-     * {@inheritdoc}
37
-     */
38
-    protected $accessTokenUrl = 'https://slack.com/api/oauth.access';
35
+	/**
36
+	 * {@inheritdoc}
37
+	 */
38
+	protected $accessTokenUrl = 'https://slack.com/api/oauth.access';
39 39
 
40
-    /**
41
-     * {@inheritdoc}
42
-     */
43
-    protected $apiDocumentation = 'https://api.slack.com/docs/sign-in-with-slack';
40
+	/**
41
+	 * {@inheritdoc}
42
+	 */
43
+	protected $apiDocumentation = 'https://api.slack.com/docs/sign-in-with-slack';
44 44
 
45
-    /**
46
-     * {@inheritdoc}
47
-     */
48
-    public function getUserProfile()
49
-    {
50
-        $response = $this->apiRequest('api/users.identity');
45
+	/**
46
+	 * {@inheritdoc}
47
+	 */
48
+	public function getUserProfile()
49
+	{
50
+		$response = $this->apiRequest('api/users.identity');
51 51
 
52
-        $data = new Data\Collection($response);
52
+		$data = new Data\Collection($response);
53 53
 
54
-        if (!$data->exists('ok') || !$data->get('ok')) {
55
-            throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
56
-        }
54
+		if (!$data->exists('ok') || !$data->get('ok')) {
55
+			throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
56
+		}
57 57
 
58
-        $userProfile = new User\Profile();
58
+		$userProfile = new User\Profile();
59 59
 
60
-        $userProfile->identifier = $data->filter('user')->get('id');
61
-        $userProfile->displayName = $data->filter('user')->get('name');
62
-        $userProfile->email = $data->filter('user')->get('email');
63
-        $userProfile->photoURL = $this->findLargestImage($data);
60
+		$userProfile->identifier = $data->filter('user')->get('id');
61
+		$userProfile->displayName = $data->filter('user')->get('name');
62
+		$userProfile->email = $data->filter('user')->get('email');
63
+		$userProfile->photoURL = $this->findLargestImage($data);
64 64
 
65
-        return $userProfile;
66
-    }
65
+		return $userProfile;
66
+	}
67 67
 
68
-    /**
69
-     * Returns the url of the image with the highest resolution in the user
70
-     * object.
71
-     *
72
-     * Slack sends multiple image urls with different resolutions. As they make
73
-     * no guarantees which resolutions will be included we have to search all
74
-     * <code>image_*</code> properties for the one with the highest resolution.
75
-     * The resolution is attached to the property name such as
76
-     * <code>image_32</code> or <code>image_192</code>.
77
-     *
78
-     * @param Data\Collection $data response object as returned by
79
-     *     <code>api/users.identity</code>
80
-     *
81
-     * @return string|null the value of the <code>image_*</code> property with
82
-     *     the highest resolution.
83
-     */
84
-    private function findLargestImage(Data\Collection $data)
85
-    {
86
-        $maxSize = 0;
87
-        foreach ($data->filter('user')->properties() as $property) {
88
-            if (preg_match('/^image_(\d+)$/', $property, $matches) === 1) {
89
-                $availableSize = (int)$matches[1];
90
-                if ($maxSize < $availableSize) {
91
-                    $maxSize = $availableSize;
92
-                }
93
-            }
94
-        }
95
-        if ($maxSize > 0) {
96
-            return $data->filter('user')->get('image_' . $maxSize);
97
-        }
98
-        return null;
99
-    }
68
+	/**
69
+	 * Returns the url of the image with the highest resolution in the user
70
+	 * object.
71
+	 *
72
+	 * Slack sends multiple image urls with different resolutions. As they make
73
+	 * no guarantees which resolutions will be included we have to search all
74
+	 * <code>image_*</code> properties for the one with the highest resolution.
75
+	 * The resolution is attached to the property name such as
76
+	 * <code>image_32</code> or <code>image_192</code>.
77
+	 *
78
+	 * @param Data\Collection $data response object as returned by
79
+	 *     <code>api/users.identity</code>
80
+	 *
81
+	 * @return string|null the value of the <code>image_*</code> property with
82
+	 *     the highest resolution.
83
+	 */
84
+	private function findLargestImage(Data\Collection $data)
85
+	{
86
+		$maxSize = 0;
87
+		foreach ($data->filter('user')->properties() as $property) {
88
+			if (preg_match('/^image_(\d+)$/', $property, $matches) === 1) {
89
+				$availableSize = (int)$matches[1];
90
+				if ($maxSize < $availableSize) {
91
+					$maxSize = $availableSize;
92
+				}
93
+			}
94
+		}
95
+		if ($maxSize > 0) {
96
+			return $data->filter('user')->get('image_' . $maxSize);
97
+		}
98
+		return null;
99
+	}
100 100
 }
Please login to merge, or discard this patch.
src/Provider/Discord.php 2 patches
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
 
66 66
         $data = new Data\Collection($response);
67 67
 
68
-        if (!$data->exists('id')) {
68
+        if ( ! $data->exists('id')) {
69 69
             throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
70 70
         }
71 71
 
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
 
88 88
         if ($data->get('avatar')) {
89 89
             $userProfile->photoURL = 'https://cdn.discordapp.com/avatars/';
90
-            $userProfile->photoURL .= $data->get('id') . '/' . $data->get('avatar') . '.png';
90
+            $userProfile->photoURL .= $data->get('id').'/'.$data->get('avatar').'.png';
91 91
         }
92 92
 
93 93
         return $userProfile;
Please login to merge, or discard this patch.
Indentation   +76 added lines, -76 removed lines patch added patch discarded remove patch
@@ -17,80 +17,80 @@
 block discarded – undo
17 17
  */
18 18
 class Discord extends OAuth2
19 19
 {
20
-    /**
21
-     * {@inheritdoc}
22
-     */
23
-    protected $scope = 'identify email';
24
-
25
-    /**
26
-     * {@inheritdoc}
27
-     */
28
-    protected $apiBaseUrl = 'https://discordapp.com/api/';
29
-
30
-    /**
31
-     * {@inheritdoc}
32
-     */
33
-    protected $authorizeUrl = 'https://discordapp.com/api/oauth2/authorize';
34
-
35
-    /**
36
-     * {@inheritdoc}
37
-     */
38
-    protected $accessTokenUrl = 'https://discordapp.com/api/oauth2/token';
39
-
40
-    /**
41
-     * {@inheritdoc}
42
-     */
43
-    protected $apiDocumentation = 'https://discordapp.com/developers/docs/topics/oauth2';
44
-
45
-    /**
46
-     * {@inheritdoc}
47
-     */
48
-    protected function initialize()
49
-    {
50
-        parent::initialize();
51
-
52
-        if ($this->isRefreshTokenAvailable()) {
53
-            $this->tokenRefreshParameters += [
54
-                'client_id' => $this->clientId,
55
-                'client_secret' => $this->clientSecret,
56
-            ];
57
-        }
58
-    }
59
-
60
-    /**
61
-     * {@inheritdoc}
62
-     */
63
-    public function getUserProfile()
64
-    {
65
-        $response = $this->apiRequest('users/@me');
66
-
67
-        $data = new Data\Collection($response);
68
-
69
-        if (!$data->exists('id')) {
70
-            throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
71
-        }
72
-
73
-        // Makes display name more unique.
74
-        $displayName = $data->get('username') ?: $data->get('login');
75
-        if ($discriminator = $data->get('discriminator')) {
76
-            $displayName .= "#{$discriminator}";
77
-        }
78
-
79
-        $userProfile = new User\Profile();
80
-
81
-        $userProfile->identifier = $data->get('id');
82
-        $userProfile->displayName = $displayName;
83
-        $userProfile->email = $data->get('email');
84
-
85
-        if ($data->get('verified')) {
86
-            $userProfile->emailVerified = $data->get('email');
87
-        }
88
-
89
-        if ($data->get('avatar')) {
90
-            $userProfile->photoURL = 'https://cdn.discordapp.com/avatars/';
91
-            $userProfile->photoURL .= $data->get('id') . '/' . $data->get('avatar') . '.png';
92
-        }
93
-
94
-        return $userProfile;
95
-    }
20
+	/**
21
+	 * {@inheritdoc}
22
+	 */
23
+	protected $scope = 'identify email';
24
+
25
+	/**
26
+	 * {@inheritdoc}
27
+	 */
28
+	protected $apiBaseUrl = 'https://discordapp.com/api/';
29
+
30
+	/**
31
+	 * {@inheritdoc}
32
+	 */
33
+	protected $authorizeUrl = 'https://discordapp.com/api/oauth2/authorize';
34
+
35
+	/**
36
+	 * {@inheritdoc}
37
+	 */
38
+	protected $accessTokenUrl = 'https://discordapp.com/api/oauth2/token';
39
+
40
+	/**
41
+	 * {@inheritdoc}
42
+	 */
43
+	protected $apiDocumentation = 'https://discordapp.com/developers/docs/topics/oauth2';
44
+
45
+	/**
46
+	 * {@inheritdoc}
47
+	 */
48
+	protected function initialize()
49
+	{
50
+		parent::initialize();
51
+
52
+		if ($this->isRefreshTokenAvailable()) {
53
+			$this->tokenRefreshParameters += [
54
+				'client_id' => $this->clientId,
55
+				'client_secret' => $this->clientSecret,
56
+			];
57
+		}
58
+	}
59
+
60
+	/**
61
+	 * {@inheritdoc}
62
+	 */
63
+	public function getUserProfile()
64
+	{
65
+		$response = $this->apiRequest('users/@me');
66
+
67
+		$data = new Data\Collection($response);
68
+
69
+		if (!$data->exists('id')) {
70
+			throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
71
+		}
72
+
73
+		// Makes display name more unique.
74
+		$displayName = $data->get('username') ?: $data->get('login');
75
+		if ($discriminator = $data->get('discriminator')) {
76
+			$displayName .= "#{$discriminator}";
77
+		}
78
+
79
+		$userProfile = new User\Profile();
80
+
81
+		$userProfile->identifier = $data->get('id');
82
+		$userProfile->displayName = $displayName;
83
+		$userProfile->email = $data->get('email');
84
+
85
+		if ($data->get('verified')) {
86
+			$userProfile->emailVerified = $data->get('email');
87
+		}
88
+
89
+		if ($data->get('avatar')) {
90
+			$userProfile->photoURL = 'https://cdn.discordapp.com/avatars/';
91
+			$userProfile->photoURL .= $data->get('id') . '/' . $data->get('avatar') . '.png';
92
+		}
93
+
94
+		return $userProfile;
95
+	}
96 96
 }
Please login to merge, or discard this patch.
src/Provider/Dropbox.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -51,7 +51,7 @@
 block discarded – undo
51 51
 
52 52
         $data = new Data\Collection($response);
53 53
 
54
-        if (!$data->exists('account_id') || !$data->get('account_id')) {
54
+        if ( ! $data->exists('account_id') || ! $data->get('account_id')) {
55 55
             throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
56 56
         }
57 57
 
Please login to merge, or discard this patch.
Indentation   +44 added lines, -44 removed lines patch added patch discarded remove patch
@@ -17,58 +17,58 @@
 block discarded – undo
17 17
  */
18 18
 class Dropbox extends OAuth2
19 19
 {
20
-    /**
21
-     * {@inheritdoc}
22
-     */
23
-    protected $scope = 'account_info.read';
20
+	/**
21
+	 * {@inheritdoc}
22
+	 */
23
+	protected $scope = 'account_info.read';
24 24
 
25
-    /**
26
-     * {@inheritdoc}
27
-     */
28
-    protected $apiBaseUrl = 'https://api.dropbox.com/2/';
25
+	/**
26
+	 * {@inheritdoc}
27
+	 */
28
+	protected $apiBaseUrl = 'https://api.dropbox.com/2/';
29 29
 
30
-    /**
31
-     * {@inheritdoc}
32
-     */
33
-    protected $authorizeUrl = 'https://www.dropbox.com/1/oauth2/authorize';
30
+	/**
31
+	 * {@inheritdoc}
32
+	 */
33
+	protected $authorizeUrl = 'https://www.dropbox.com/1/oauth2/authorize';
34 34
 
35
-    /**
36
-     * {@inheritdoc}
37
-     */
38
-    protected $accessTokenUrl = 'https://api.dropbox.com/1/oauth2/token';
35
+	/**
36
+	 * {@inheritdoc}
37
+	 */
38
+	protected $accessTokenUrl = 'https://api.dropbox.com/1/oauth2/token';
39 39
 
40
-    /**
41
-     * {@inheritdoc}
42
-     */
43
-    protected $apiDocumentation = 'https://www.dropbox.com/developers/documentation/http/documentation';
40
+	/**
41
+	 * {@inheritdoc}
42
+	 */
43
+	protected $apiDocumentation = 'https://www.dropbox.com/developers/documentation/http/documentation';
44 44
 
45
-    /**
46
-     * {@inheritdoc}
47
-     */
48
-    public function getUserProfile()
49
-    {
50
-        $response = $this->apiRequest('users/get_current_account', 'POST', [], [], true);
45
+	/**
46
+	 * {@inheritdoc}
47
+	 */
48
+	public function getUserProfile()
49
+	{
50
+		$response = $this->apiRequest('users/get_current_account', 'POST', [], [], true);
51 51
 
52
-        $data = new Data\Collection($response);
52
+		$data = new Data\Collection($response);
53 53
 
54
-        if (!$data->exists('account_id') || !$data->get('account_id')) {
55
-            throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
56
-        }
54
+		if (!$data->exists('account_id') || !$data->get('account_id')) {
55
+			throw new UnexpectedApiResponseException('Provider API returned an unexpected response.');
56
+		}
57 57
 
58
-        $userProfile = new User\Profile();
58
+		$userProfile = new User\Profile();
59 59
 
60
-        $userProfile->identifier = $data->get('account_id');
61
-        $userProfile->displayName = $data->filter('name')->get('display_name');
62
-        $userProfile->firstName = $data->filter('name')->get('given_name');
63
-        $userProfile->lastName = $data->filter('name')->get('surname');
64
-        $userProfile->email = $data->get('email');
65
-        $userProfile->photoURL = $data->get('profile_photo_url');
66
-        $userProfile->language = $data->get('locale');
67
-        $userProfile->country = $data->get('country');
68
-        if ($data->get('email_verified')) {
69
-            $userProfile->emailVerified = $data->get('email');
70
-        }
60
+		$userProfile->identifier = $data->get('account_id');
61
+		$userProfile->displayName = $data->filter('name')->get('display_name');
62
+		$userProfile->firstName = $data->filter('name')->get('given_name');
63
+		$userProfile->lastName = $data->filter('name')->get('surname');
64
+		$userProfile->email = $data->get('email');
65
+		$userProfile->photoURL = $data->get('profile_photo_url');
66
+		$userProfile->language = $data->get('locale');
67
+		$userProfile->country = $data->get('country');
68
+		if ($data->get('email_verified')) {
69
+			$userProfile->emailVerified = $data->get('email');
70
+		}
71 71
 
72
-        return $userProfile;
73
-    }
72
+		return $userProfile;
73
+	}
74 74
 }
Please login to merge, or discard this patch.
src/Provider/WeChatChina.php 1 patch
Indentation   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -12,23 +12,23 @@
 block discarded – undo
12 12
  */
13 13
 class WeChatChina extends WeChat
14 14
 {
15
-    /**
16
-     * {@inheritdoc}
17
-     */
18
-    protected $apiBaseUrl = 'https://api.weixin.qq.com/sns/';
15
+	/**
16
+	 * {@inheritdoc}
17
+	 */
18
+	protected $apiBaseUrl = 'https://api.weixin.qq.com/sns/';
19 19
 
20
-    /**
21
-     * {@inheritdoc}
22
-     */
23
-    protected $accessTokenUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token';
20
+	/**
21
+	 * {@inheritdoc}
22
+	 */
23
+	protected $accessTokenUrl = 'https://api.weixin.qq.com/sns/oauth2/access_token';
24 24
 
25
-    /**
26
-     * {@inheritdoc}
27
-     */
28
-    protected $tokenRefreshUrl = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
25
+	/**
26
+	 * {@inheritdoc}
27
+	 */
28
+	protected $tokenRefreshUrl = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
29 29
 
30
-    /**
31
-     * {@ịnheritdoc}
32
-     */
33
-    protected $accessTokenInfoUrl = 'https://api.weixin.qq.com/sns/auth';
30
+	/**
31
+	 * {@ịnheritdoc}
32
+	 */
33
+	protected $accessTokenInfoUrl = 'https://api.weixin.qq.com/sns/auth';
34 34
 }
Please login to merge, or discard this patch.
src/Logger/LoggerInterface.php 1 patch
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -12,39 +12,39 @@
 block discarded – undo
12 12
  */
13 13
 interface LoggerInterface
14 14
 {
15
-    /**
16
-     * Interesting events.
17
-     *
18
-     * Example: User logs in, SQL logs.
19
-     *
20
-     * @param string $message
21
-     * @param array $context
22
-     */
23
-    public function info($message, array $context = array());
15
+	/**
16
+	 * Interesting events.
17
+	 *
18
+	 * Example: User logs in, SQL logs.
19
+	 *
20
+	 * @param string $message
21
+	 * @param array $context
22
+	 */
23
+	public function info($message, array $context = array());
24 24
 
25
-    /**
26
-     * Detailed debug information.
27
-     *
28
-     * @param string $message
29
-     * @param array $context
30
-     */
31
-    public function debug($message, array $context = array());
25
+	/**
26
+	 * Detailed debug information.
27
+	 *
28
+	 * @param string $message
29
+	 * @param array $context
30
+	 */
31
+	public function debug($message, array $context = array());
32 32
 
33
-    /**
34
-     * Runtime errors that do not require immediate action but should typically
35
-     * be logged and monitored.
36
-     *
37
-     * @param string $message
38
-     * @param array $context
39
-     */
40
-    public function error($message, array $context = array());
33
+	/**
34
+	 * Runtime errors that do not require immediate action but should typically
35
+	 * be logged and monitored.
36
+	 *
37
+	 * @param string $message
38
+	 * @param array $context
39
+	 */
40
+	public function error($message, array $context = array());
41 41
 
42
-    /**
43
-     * Logs with an arbitrary level.
44
-     *
45
-     * @param mixed $level
46
-     * @param string $message
47
-     * @param array $context
48
-     */
49
-    public function log($level, $message, array $context = array());
42
+	/**
43
+	 * Logs with an arbitrary level.
44
+	 *
45
+	 * @param mixed $level
46
+	 * @param string $message
47
+	 * @param array $context
48
+	 */
49
+	public function log($level, $message, array $context = array());
50 50
 }
Please login to merge, or discard this patch.
src/Logger/Logger.php 2 patches
Indentation   +111 added lines, -111 removed lines patch added patch discarded remove patch
@@ -15,115 +15,115 @@
 block discarded – undo
15 15
  */
16 16
 class Logger implements LoggerInterface
17 17
 {
18
-    const NONE = 'none';  // turn logging off
19
-    const DEBUG = 'debug'; // debug, info and error messages
20
-    const INFO = 'info';  // info and error messages
21
-    const ERROR = 'error'; // only error messages
22
-
23
-    /**
24
-     * Debug level.
25
-     *
26
-     * One of Logger::NONE, Logger::DEBUG, Logger::INFO, Logger::ERROR
27
-     *
28
-     * @var string
29
-     */
30
-    protected $level;
31
-
32
-    /**
33
-     * Path to file writeable by the web server. Required if $this->level !== Logger::NONE.
34
-     *
35
-     * @var string
36
-     */
37
-    protected $file;
38
-
39
-    /**
40
-     * @param bool|string $level One of Logger::NONE, Logger::DEBUG, Logger::INFO, Logger::ERROR
41
-     * @param string $file File where to write messages
42
-     *
43
-     * @throws InvalidArgumentException
44
-     * @throws RuntimeException
45
-     */
46
-    public function __construct($level, $file)
47
-    {
48
-        $this->level = self::NONE;
49
-
50
-        if ($level && $level !== self::NONE) {
51
-            $this->initialize($file);
52
-
53
-            $this->level = $level === true ? Logger::DEBUG : $level;
54
-            $this->file = $file;
55
-        }
56
-    }
57
-
58
-    /**
59
-     * @param string $file
60
-     *
61
-     * @throws InvalidArgumentException
62
-     * @throws RuntimeException
63
-     */
64
-    protected function initialize($file)
65
-    {
66
-        if (!$file) {
67
-            throw new InvalidArgumentException('Log file is not specified.');
68
-        }
69
-
70
-        if (!file_exists($file) && !touch($file)) {
71
-            throw new RuntimeException(sprintf('Log file %s can not be created.', $file));
72
-        }
73
-
74
-        if (!is_writable($file)) {
75
-            throw new RuntimeException(sprintf('Log file %s is not writeable.', $file));
76
-        }
77
-    }
78
-
79
-    /**
80
-     * @inheritdoc
81
-     */
82
-    public function info($message, array $context = [])
83
-    {
84
-        if (!in_array($this->level, [self::DEBUG, self::INFO])) {
85
-            return;
86
-        }
87
-
88
-        $this->log(self::INFO, $message, $context);
89
-    }
90
-
91
-    /**
92
-     * @inheritdoc
93
-     */
94
-    public function debug($message, array $context = [])
95
-    {
96
-        if (!in_array($this->level, [self::DEBUG])) {
97
-            return;
98
-        }
99
-
100
-        $this->log(self::DEBUG, $message, $context);
101
-    }
102
-
103
-    /**
104
-     * @inheritdoc
105
-     */
106
-    public function error($message, array $context = [])
107
-    {
108
-        if (!in_array($this->level, [self::DEBUG, self::INFO, self::ERROR])) {
109
-            return;
110
-        }
111
-
112
-        $this->log(self::ERROR, $message, $context);
113
-    }
114
-
115
-    /**
116
-     * @inheritdoc
117
-     */
118
-    public function log($level, $message, array $context = [])
119
-    {
120
-        $datetime = new \DateTime();
121
-        $datetime = $datetime->format(DATE_ATOM);
122
-
123
-        $content = sprintf('%s -- %s -- %s -- %s', $level, $_SERVER['REMOTE_ADDR'], $datetime, $message);
124
-        $content .= ($context ? "\n" . print_r($context, true) : '');
125
-        $content .= "\n";
126
-
127
-        file_put_contents($this->file, $content, FILE_APPEND);
128
-    }
18
+	const NONE = 'none';  // turn logging off
19
+	const DEBUG = 'debug'; // debug, info and error messages
20
+	const INFO = 'info';  // info and error messages
21
+	const ERROR = 'error'; // only error messages
22
+
23
+	/**
24
+	 * Debug level.
25
+	 *
26
+	 * One of Logger::NONE, Logger::DEBUG, Logger::INFO, Logger::ERROR
27
+	 *
28
+	 * @var string
29
+	 */
30
+	protected $level;
31
+
32
+	/**
33
+	 * Path to file writeable by the web server. Required if $this->level !== Logger::NONE.
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $file;
38
+
39
+	/**
40
+	 * @param bool|string $level One of Logger::NONE, Logger::DEBUG, Logger::INFO, Logger::ERROR
41
+	 * @param string $file File where to write messages
42
+	 *
43
+	 * @throws InvalidArgumentException
44
+	 * @throws RuntimeException
45
+	 */
46
+	public function __construct($level, $file)
47
+	{
48
+		$this->level = self::NONE;
49
+
50
+		if ($level && $level !== self::NONE) {
51
+			$this->initialize($file);
52
+
53
+			$this->level = $level === true ? Logger::DEBUG : $level;
54
+			$this->file = $file;
55
+		}
56
+	}
57
+
58
+	/**
59
+	 * @param string $file
60
+	 *
61
+	 * @throws InvalidArgumentException
62
+	 * @throws RuntimeException
63
+	 */
64
+	protected function initialize($file)
65
+	{
66
+		if (!$file) {
67
+			throw new InvalidArgumentException('Log file is not specified.');
68
+		}
69
+
70
+		if (!file_exists($file) && !touch($file)) {
71
+			throw new RuntimeException(sprintf('Log file %s can not be created.', $file));
72
+		}
73
+
74
+		if (!is_writable($file)) {
75
+			throw new RuntimeException(sprintf('Log file %s is not writeable.', $file));
76
+		}
77
+	}
78
+
79
+	/**
80
+	 * @inheritdoc
81
+	 */
82
+	public function info($message, array $context = [])
83
+	{
84
+		if (!in_array($this->level, [self::DEBUG, self::INFO])) {
85
+			return;
86
+		}
87
+
88
+		$this->log(self::INFO, $message, $context);
89
+	}
90
+
91
+	/**
92
+	 * @inheritdoc
93
+	 */
94
+	public function debug($message, array $context = [])
95
+	{
96
+		if (!in_array($this->level, [self::DEBUG])) {
97
+			return;
98
+		}
99
+
100
+		$this->log(self::DEBUG, $message, $context);
101
+	}
102
+
103
+	/**
104
+	 * @inheritdoc
105
+	 */
106
+	public function error($message, array $context = [])
107
+	{
108
+		if (!in_array($this->level, [self::DEBUG, self::INFO, self::ERROR])) {
109
+			return;
110
+		}
111
+
112
+		$this->log(self::ERROR, $message, $context);
113
+	}
114
+
115
+	/**
116
+	 * @inheritdoc
117
+	 */
118
+	public function log($level, $message, array $context = [])
119
+	{
120
+		$datetime = new \DateTime();
121
+		$datetime = $datetime->format(DATE_ATOM);
122
+
123
+		$content = sprintf('%s -- %s -- %s -- %s', $level, $_SERVER['REMOTE_ADDR'], $datetime, $message);
124
+		$content .= ($context ? "\n" . print_r($context, true) : '');
125
+		$content .= "\n";
126
+
127
+		file_put_contents($this->file, $content, FILE_APPEND);
128
+	}
129 129
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -15,9 +15,9 @@  discard block
 block discarded – undo
15 15
  */
16 16
 class Logger implements LoggerInterface
17 17
 {
18
-    const NONE = 'none';  // turn logging off
18
+    const NONE = 'none'; // turn logging off
19 19
     const DEBUG = 'debug'; // debug, info and error messages
20
-    const INFO = 'info';  // info and error messages
20
+    const INFO = 'info'; // info and error messages
21 21
     const ERROR = 'error'; // only error messages
22 22
 
23 23
     /**
@@ -63,15 +63,15 @@  discard block
 block discarded – undo
63 63
      */
64 64
     protected function initialize($file)
65 65
     {
66
-        if (!$file) {
66
+        if ( ! $file) {
67 67
             throw new InvalidArgumentException('Log file is not specified.');
68 68
         }
69 69
 
70
-        if (!file_exists($file) && !touch($file)) {
70
+        if ( ! file_exists($file) && ! touch($file)) {
71 71
             throw new RuntimeException(sprintf('Log file %s can not be created.', $file));
72 72
         }
73 73
 
74
-        if (!is_writable($file)) {
74
+        if ( ! is_writable($file)) {
75 75
             throw new RuntimeException(sprintf('Log file %s is not writeable.', $file));
76 76
         }
77 77
     }
@@ -81,7 +81,7 @@  discard block
 block discarded – undo
81 81
      */
82 82
     public function info($message, array $context = [])
83 83
     {
84
-        if (!in_array($this->level, [self::DEBUG, self::INFO])) {
84
+        if ( ! in_array($this->level, [self::DEBUG, self::INFO])) {
85 85
             return;
86 86
         }
87 87
 
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
      */
94 94
     public function debug($message, array $context = [])
95 95
     {
96
-        if (!in_array($this->level, [self::DEBUG])) {
96
+        if ( ! in_array($this->level, [self::DEBUG])) {
97 97
             return;
98 98
         }
99 99
 
@@ -105,7 +105,7 @@  discard block
 block discarded – undo
105 105
      */
106 106
     public function error($message, array $context = [])
107 107
     {
108
-        if (!in_array($this->level, [self::DEBUG, self::INFO, self::ERROR])) {
108
+        if ( ! in_array($this->level, [self::DEBUG, self::INFO, self::ERROR])) {
109 109
             return;
110 110
         }
111 111
 
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
         $datetime = $datetime->format(DATE_ATOM);
122 122
 
123 123
         $content = sprintf('%s -- %s -- %s -- %s', $level, $_SERVER['REMOTE_ADDR'], $datetime, $message);
124
-        $content .= ($context ? "\n" . print_r($context, true) : '');
124
+        $content .= ($context ? "\n".print_r($context, true) : '');
125 125
         $content .= "\n";
126 126
 
127 127
         file_put_contents($this->file, $content, FILE_APPEND);
Please login to merge, or discard this patch.
src/Adapter/AbstractAdapter.php 2 patches
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
      */
301 301
     protected function setCallback($callback)
302 302
     {
303
-        if (!filter_var($callback, FILTER_VALIDATE_URL)) {
303
+        if ( ! filter_var($callback, FILTER_VALIDATE_URL)) {
304 304
             throw new InvalidArgumentException('A valid callback url is required.');
305 305
         }
306 306
 
@@ -339,16 +339,16 @@  discard block
 block discarded – undo
339 339
      */
340 340
     protected function validateApiResponse($error = '')
341 341
     {
342
-        $error .= !empty($error) ? '. ' : '';
342
+        $error .= ! empty($error) ? '. ' : '';
343 343
 
344 344
         if ($this->httpClient->getResponseClientError()) {
345 345
             throw new HttpClientFailureException(
346
-                $error . 'HTTP client error: ' . $this->httpClient->getResponseClientError() . '.'
346
+                $error.'HTTP client error: '.$this->httpClient->getResponseClientError().'.'
347 347
             );
348 348
         }
349 349
 
350 350
         // if validateApiResponseHttpCode is set to false, we by pass verification of http status code
351
-        if (!$this->validateApiResponseHttpCode) {
351
+        if ( ! $this->validateApiResponseHttpCode) {
352 352
             return;
353 353
         }
354 354
 
@@ -356,8 +356,8 @@  discard block
 block discarded – undo
356 356
 
357 357
         if ($status < 200 || $status > 299) {
358 358
             throw new HttpRequestFailedException(
359
-                $error . 'HTTP error ' . $this->httpClient->getResponseHttpCode() .
360
-                '. Raw Provider API response: ' . $this->httpClient->getResponseBody() . '.'
359
+                $error.'HTTP error '.$this->httpClient->getResponseHttpCode().
360
+                '. Raw Provider API response: '.$this->httpClient->getResponseBody().'.'
361 361
             );
362 362
         }
363 363
     }
Please login to merge, or discard this patch.
Indentation   +345 added lines, -345 removed lines patch added patch discarded remove patch
@@ -24,349 +24,349 @@
 block discarded – undo
24 24
  */
25 25
 abstract class AbstractAdapter implements AdapterInterface
26 26
 {
27
-    use DataStoreTrait;
28
-
29
-    /**
30
-     * Provider ID (unique name).
31
-     *
32
-     * @var string
33
-     */
34
-    protected $providerId = '';
35
-
36
-    /**
37
-     * Specific Provider config.
38
-     *
39
-     * @var mixed
40
-     */
41
-    protected $config = [];
42
-
43
-    /**
44
-     * Extra Provider parameters.
45
-     *
46
-     * @var array
47
-     */
48
-    protected $params;
49
-
50
-    /**
51
-     * Callback url
52
-     *
53
-     * @var string
54
-     */
55
-    protected $callback = '';
56
-
57
-    /**
58
-     * Storage.
59
-     *
60
-     * @var StorageInterface
61
-     */
62
-    public $storage;
63
-
64
-    /**
65
-     * HttpClient.
66
-     *
67
-     * @var HttpClientInterface
68
-     */
69
-    public $httpClient;
70
-
71
-    /**
72
-     * Logger.
73
-     *
74
-     * @var LoggerInterface
75
-     */
76
-    public $logger;
77
-
78
-    /**
79
-     * Whether to validate API status codes of http responses
80
-     *
81
-     * @var bool
82
-     */
83
-    protected $validateApiResponseHttpCode = true;
84
-
85
-    /**
86
-     * Common adapters constructor.
87
-     *
88
-     * @param array $config
89
-     * @param HttpClientInterface $httpClient
90
-     * @param StorageInterface $storage
91
-     * @param LoggerInterface $logger
92
-     */
93
-    public function __construct(
94
-        $config = [],
95
-        HttpClientInterface $httpClient = null,
96
-        StorageInterface $storage = null,
97
-        LoggerInterface $logger = null
98
-    ) {
99
-        $this->providerId = (new \ReflectionClass($this))->getShortName();
100
-
101
-        $this->config = new Data\Collection($config);
102
-
103
-        $this->setHttpClient($httpClient);
104
-
105
-        $this->setStorage($storage);
106
-
107
-        $this->setLogger($logger);
108
-
109
-        $this->configure();
110
-
111
-        $this->logger->debug(sprintf('Initialize %s, config: ', get_class($this)), $config);
112
-
113
-        $this->initialize();
114
-    }
115
-
116
-    /**
117
-     * Load adapter's configuration
118
-     */
119
-    abstract protected function configure();
120
-
121
-    /**
122
-     * Adapter initializer
123
-     */
124
-    abstract protected function initialize();
125
-
126
-    /**
127
-     * {@inheritdoc}
128
-     */
129
-    abstract public function isConnected();
130
-
131
-    /**
132
-     * {@inheritdoc}
133
-     */
134
-    public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
135
-    {
136
-        throw new NotImplementedException('Provider does not support this feature.');
137
-    }
138
-
139
-    /**
140
-     * {@inheritdoc}
141
-     */
142
-    public function maintainToken()
143
-    {
144
-        // Nothing needed for most providers
145
-    }
146
-
147
-    /**
148
-     * {@inheritdoc}
149
-     */
150
-    public function getUserProfile()
151
-    {
152
-        throw new NotImplementedException('Provider does not support this feature.');
153
-    }
154
-
155
-    /**
156
-     * {@inheritdoc}
157
-     */
158
-    public function getUserContacts()
159
-    {
160
-        throw new NotImplementedException('Provider does not support this feature.');
161
-    }
162
-
163
-    /**
164
-     * {@inheritdoc}
165
-     */
166
-    public function getUserPages()
167
-    {
168
-        throw new NotImplementedException('Provider does not support this feature.');
169
-    }
170
-
171
-    /**
172
-     * {@inheritdoc}
173
-     */
174
-    public function getUserActivity($stream)
175
-    {
176
-        throw new NotImplementedException('Provider does not support this feature.');
177
-    }
178
-
179
-    /**
180
-     * {@inheritdoc}
181
-     */
182
-    public function setUserStatus($status)
183
-    {
184
-        throw new NotImplementedException('Provider does not support this feature.');
185
-    }
186
-
187
-    /**
188
-     * {@inheritdoc}
189
-     */
190
-    public function setPageStatus($status, $pageId)
191
-    {
192
-        throw new NotImplementedException('Provider does not support this feature.');
193
-    }
194
-
195
-    /**
196
-     * {@inheritdoc}
197
-     */
198
-    public function disconnect()
199
-    {
200
-        $this->clearStoredData();
201
-    }
202
-
203
-    /**
204
-     * {@inheritdoc}
205
-     */
206
-    public function getAccessToken()
207
-    {
208
-        $tokenNames = [
209
-            'access_token',
210
-            'access_token_secret',
211
-            'token_type',
212
-            'refresh_token',
213
-            'expires_in',
214
-            'expires_at',
215
-        ];
216
-
217
-        $tokens = [];
218
-
219
-        foreach ($tokenNames as $name) {
220
-            if ($this->getStoredData($name)) {
221
-                $tokens[$name] = $this->getStoredData($name);
222
-            }
223
-        }
224
-
225
-        return $tokens;
226
-    }
227
-
228
-    /**
229
-     * {@inheritdoc}
230
-     */
231
-    public function setAccessToken($tokens = [])
232
-    {
233
-        $this->clearStoredData();
234
-
235
-        foreach ($tokens as $token => $value) {
236
-            $this->storeData($token, $value);
237
-        }
238
-
239
-        // Re-initialize token parameters.
240
-        $this->initialize();
241
-    }
242
-
243
-    /**
244
-     * {@inheritdoc}
245
-     */
246
-    public function setHttpClient(HttpClientInterface $httpClient = null)
247
-    {
248
-        $this->httpClient = $httpClient ?: new HttpClient();
249
-
250
-        if ($this->config->exists('curl_options') && method_exists($this->httpClient, 'setCurlOptions')) {
251
-            $this->httpClient->setCurlOptions($this->config->get('curl_options'));
252
-        }
253
-    }
254
-
255
-    /**
256
-     * {@inheritdoc}
257
-     */
258
-    public function getHttpClient()
259
-    {
260
-        return $this->httpClient;
261
-    }
262
-
263
-    /**
264
-     * {@inheritdoc}
265
-     */
266
-    public function setStorage(StorageInterface $storage = null)
267
-    {
268
-        $this->storage = $storage ?: new Session();
269
-    }
270
-
271
-    /**
272
-     * {@inheritdoc}
273
-     */
274
-    public function getStorage()
275
-    {
276
-        return $this->storage;
277
-    }
278
-
279
-    /**
280
-     * {@inheritdoc}
281
-     */
282
-    public function setLogger(LoggerInterface $logger = null)
283
-    {
284
-        $this->logger = $logger ?: new Logger(
285
-            $this->config->get('debug_mode'),
286
-            $this->config->get('debug_file')
287
-        );
288
-
289
-        if (method_exists($this->httpClient, 'setLogger')) {
290
-            $this->httpClient->setLogger($this->logger);
291
-        }
292
-    }
293
-
294
-    /**
295
-     * {@inheritdoc}
296
-     */
297
-    public function getLogger()
298
-    {
299
-        return $this->logger;
300
-    }
301
-
302
-    /**
303
-     * Set Adapter's API callback url
304
-     *
305
-     * @param string $callback
306
-     *
307
-     * @throws InvalidArgumentException
308
-     */
309
-    protected function setCallback($callback)
310
-    {
311
-        if (!filter_var($callback, FILTER_VALIDATE_URL)) {
312
-            throw new InvalidArgumentException('A valid callback url is required.');
313
-        }
314
-
315
-        $this->callback = $callback;
316
-    }
317
-
318
-    /**
319
-     * Overwrite Adapter's API endpoints
320
-     *
321
-     * @param array|Data\Collection $endpoints
322
-     */
323
-    protected function setApiEndpoints($endpoints = null)
324
-    {
325
-        if (empty($endpoints)) {
326
-            return;
327
-        }
328
-
329
-        $collection = is_array($endpoints) ? new Data\Collection($endpoints) : $endpoints;
330
-
331
-        $this->apiBaseUrl = $collection->get('api_base_url') ?: $this->apiBaseUrl;
332
-        $this->authorizeUrl = $collection->get('authorize_url') ?: $this->authorizeUrl;
333
-        $this->accessTokenUrl = $collection->get('access_token_url') ?: $this->accessTokenUrl;
334
-    }
335
-
336
-
337
-    /**
338
-     * Validate signed API responses Http status code.
339
-     *
340
-     * Since the specifics of error responses is beyond the scope of RFC6749 and OAuth Core specifications,
341
-     * Hybridauth will consider any HTTP status code that is different than '200 OK' as an ERROR.
342
-     *
343
-     * @param string $error String to pre append to message thrown in exception
344
-     *
345
-     * @throws HttpClientFailureException
346
-     * @throws HttpRequestFailedException
347
-     */
348
-    protected function validateApiResponse($error = '')
349
-    {
350
-        $error .= !empty($error) ? '. ' : '';
351
-
352
-        if ($this->httpClient->getResponseClientError()) {
353
-            throw new HttpClientFailureException(
354
-                $error . 'HTTP client error: ' . $this->httpClient->getResponseClientError() . '.'
355
-            );
356
-        }
357
-
358
-        // if validateApiResponseHttpCode is set to false, we by pass verification of http status code
359
-        if (!$this->validateApiResponseHttpCode) {
360
-            return;
361
-        }
362
-
363
-        $status = $this->httpClient->getResponseHttpCode();
364
-
365
-        if ($status < 200 || $status > 299) {
366
-            throw new HttpRequestFailedException(
367
-                $error . 'HTTP error ' . $this->httpClient->getResponseHttpCode() .
368
-                '. Raw Provider API response: ' . $this->httpClient->getResponseBody() . '.'
369
-            );
370
-        }
371
-    }
27
+	use DataStoreTrait;
28
+
29
+	/**
30
+	 * Provider ID (unique name).
31
+	 *
32
+	 * @var string
33
+	 */
34
+	protected $providerId = '';
35
+
36
+	/**
37
+	 * Specific Provider config.
38
+	 *
39
+	 * @var mixed
40
+	 */
41
+	protected $config = [];
42
+
43
+	/**
44
+	 * Extra Provider parameters.
45
+	 *
46
+	 * @var array
47
+	 */
48
+	protected $params;
49
+
50
+	/**
51
+	 * Callback url
52
+	 *
53
+	 * @var string
54
+	 */
55
+	protected $callback = '';
56
+
57
+	/**
58
+	 * Storage.
59
+	 *
60
+	 * @var StorageInterface
61
+	 */
62
+	public $storage;
63
+
64
+	/**
65
+	 * HttpClient.
66
+	 *
67
+	 * @var HttpClientInterface
68
+	 */
69
+	public $httpClient;
70
+
71
+	/**
72
+	 * Logger.
73
+	 *
74
+	 * @var LoggerInterface
75
+	 */
76
+	public $logger;
77
+
78
+	/**
79
+	 * Whether to validate API status codes of http responses
80
+	 *
81
+	 * @var bool
82
+	 */
83
+	protected $validateApiResponseHttpCode = true;
84
+
85
+	/**
86
+	 * Common adapters constructor.
87
+	 *
88
+	 * @param array $config
89
+	 * @param HttpClientInterface $httpClient
90
+	 * @param StorageInterface $storage
91
+	 * @param LoggerInterface $logger
92
+	 */
93
+	public function __construct(
94
+		$config = [],
95
+		HttpClientInterface $httpClient = null,
96
+		StorageInterface $storage = null,
97
+		LoggerInterface $logger = null
98
+	) {
99
+		$this->providerId = (new \ReflectionClass($this))->getShortName();
100
+
101
+		$this->config = new Data\Collection($config);
102
+
103
+		$this->setHttpClient($httpClient);
104
+
105
+		$this->setStorage($storage);
106
+
107
+		$this->setLogger($logger);
108
+
109
+		$this->configure();
110
+
111
+		$this->logger->debug(sprintf('Initialize %s, config: ', get_class($this)), $config);
112
+
113
+		$this->initialize();
114
+	}
115
+
116
+	/**
117
+	 * Load adapter's configuration
118
+	 */
119
+	abstract protected function configure();
120
+
121
+	/**
122
+	 * Adapter initializer
123
+	 */
124
+	abstract protected function initialize();
125
+
126
+	/**
127
+	 * {@inheritdoc}
128
+	 */
129
+	abstract public function isConnected();
130
+
131
+	/**
132
+	 * {@inheritdoc}
133
+	 */
134
+	public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
135
+	{
136
+		throw new NotImplementedException('Provider does not support this feature.');
137
+	}
138
+
139
+	/**
140
+	 * {@inheritdoc}
141
+	 */
142
+	public function maintainToken()
143
+	{
144
+		// Nothing needed for most providers
145
+	}
146
+
147
+	/**
148
+	 * {@inheritdoc}
149
+	 */
150
+	public function getUserProfile()
151
+	{
152
+		throw new NotImplementedException('Provider does not support this feature.');
153
+	}
154
+
155
+	/**
156
+	 * {@inheritdoc}
157
+	 */
158
+	public function getUserContacts()
159
+	{
160
+		throw new NotImplementedException('Provider does not support this feature.');
161
+	}
162
+
163
+	/**
164
+	 * {@inheritdoc}
165
+	 */
166
+	public function getUserPages()
167
+	{
168
+		throw new NotImplementedException('Provider does not support this feature.');
169
+	}
170
+
171
+	/**
172
+	 * {@inheritdoc}
173
+	 */
174
+	public function getUserActivity($stream)
175
+	{
176
+		throw new NotImplementedException('Provider does not support this feature.');
177
+	}
178
+
179
+	/**
180
+	 * {@inheritdoc}
181
+	 */
182
+	public function setUserStatus($status)
183
+	{
184
+		throw new NotImplementedException('Provider does not support this feature.');
185
+	}
186
+
187
+	/**
188
+	 * {@inheritdoc}
189
+	 */
190
+	public function setPageStatus($status, $pageId)
191
+	{
192
+		throw new NotImplementedException('Provider does not support this feature.');
193
+	}
194
+
195
+	/**
196
+	 * {@inheritdoc}
197
+	 */
198
+	public function disconnect()
199
+	{
200
+		$this->clearStoredData();
201
+	}
202
+
203
+	/**
204
+	 * {@inheritdoc}
205
+	 */
206
+	public function getAccessToken()
207
+	{
208
+		$tokenNames = [
209
+			'access_token',
210
+			'access_token_secret',
211
+			'token_type',
212
+			'refresh_token',
213
+			'expires_in',
214
+			'expires_at',
215
+		];
216
+
217
+		$tokens = [];
218
+
219
+		foreach ($tokenNames as $name) {
220
+			if ($this->getStoredData($name)) {
221
+				$tokens[$name] = $this->getStoredData($name);
222
+			}
223
+		}
224
+
225
+		return $tokens;
226
+	}
227
+
228
+	/**
229
+	 * {@inheritdoc}
230
+	 */
231
+	public function setAccessToken($tokens = [])
232
+	{
233
+		$this->clearStoredData();
234
+
235
+		foreach ($tokens as $token => $value) {
236
+			$this->storeData($token, $value);
237
+		}
238
+
239
+		// Re-initialize token parameters.
240
+		$this->initialize();
241
+	}
242
+
243
+	/**
244
+	 * {@inheritdoc}
245
+	 */
246
+	public function setHttpClient(HttpClientInterface $httpClient = null)
247
+	{
248
+		$this->httpClient = $httpClient ?: new HttpClient();
249
+
250
+		if ($this->config->exists('curl_options') && method_exists($this->httpClient, 'setCurlOptions')) {
251
+			$this->httpClient->setCurlOptions($this->config->get('curl_options'));
252
+		}
253
+	}
254
+
255
+	/**
256
+	 * {@inheritdoc}
257
+	 */
258
+	public function getHttpClient()
259
+	{
260
+		return $this->httpClient;
261
+	}
262
+
263
+	/**
264
+	 * {@inheritdoc}
265
+	 */
266
+	public function setStorage(StorageInterface $storage = null)
267
+	{
268
+		$this->storage = $storage ?: new Session();
269
+	}
270
+
271
+	/**
272
+	 * {@inheritdoc}
273
+	 */
274
+	public function getStorage()
275
+	{
276
+		return $this->storage;
277
+	}
278
+
279
+	/**
280
+	 * {@inheritdoc}
281
+	 */
282
+	public function setLogger(LoggerInterface $logger = null)
283
+	{
284
+		$this->logger = $logger ?: new Logger(
285
+			$this->config->get('debug_mode'),
286
+			$this->config->get('debug_file')
287
+		);
288
+
289
+		if (method_exists($this->httpClient, 'setLogger')) {
290
+			$this->httpClient->setLogger($this->logger);
291
+		}
292
+	}
293
+
294
+	/**
295
+	 * {@inheritdoc}
296
+	 */
297
+	public function getLogger()
298
+	{
299
+		return $this->logger;
300
+	}
301
+
302
+	/**
303
+	 * Set Adapter's API callback url
304
+	 *
305
+	 * @param string $callback
306
+	 *
307
+	 * @throws InvalidArgumentException
308
+	 */
309
+	protected function setCallback($callback)
310
+	{
311
+		if (!filter_var($callback, FILTER_VALIDATE_URL)) {
312
+			throw new InvalidArgumentException('A valid callback url is required.');
313
+		}
314
+
315
+		$this->callback = $callback;
316
+	}
317
+
318
+	/**
319
+	 * Overwrite Adapter's API endpoints
320
+	 *
321
+	 * @param array|Data\Collection $endpoints
322
+	 */
323
+	protected function setApiEndpoints($endpoints = null)
324
+	{
325
+		if (empty($endpoints)) {
326
+			return;
327
+		}
328
+
329
+		$collection = is_array($endpoints) ? new Data\Collection($endpoints) : $endpoints;
330
+
331
+		$this->apiBaseUrl = $collection->get('api_base_url') ?: $this->apiBaseUrl;
332
+		$this->authorizeUrl = $collection->get('authorize_url') ?: $this->authorizeUrl;
333
+		$this->accessTokenUrl = $collection->get('access_token_url') ?: $this->accessTokenUrl;
334
+	}
335
+
336
+
337
+	/**
338
+	 * Validate signed API responses Http status code.
339
+	 *
340
+	 * Since the specifics of error responses is beyond the scope of RFC6749 and OAuth Core specifications,
341
+	 * Hybridauth will consider any HTTP status code that is different than '200 OK' as an ERROR.
342
+	 *
343
+	 * @param string $error String to pre append to message thrown in exception
344
+	 *
345
+	 * @throws HttpClientFailureException
346
+	 * @throws HttpRequestFailedException
347
+	 */
348
+	protected function validateApiResponse($error = '')
349
+	{
350
+		$error .= !empty($error) ? '. ' : '';
351
+
352
+		if ($this->httpClient->getResponseClientError()) {
353
+			throw new HttpClientFailureException(
354
+				$error . 'HTTP client error: ' . $this->httpClient->getResponseClientError() . '.'
355
+			);
356
+		}
357
+
358
+		// if validateApiResponseHttpCode is set to false, we by pass verification of http status code
359
+		if (!$this->validateApiResponseHttpCode) {
360
+			return;
361
+		}
362
+
363
+		$status = $this->httpClient->getResponseHttpCode();
364
+
365
+		if ($status < 200 || $status > 299) {
366
+			throw new HttpRequestFailedException(
367
+				$error . 'HTTP error ' . $this->httpClient->getResponseHttpCode() .
368
+				'. Raw Provider API response: ' . $this->httpClient->getResponseBody() . '.'
369
+			);
370
+		}
371
+	}
372 372
 }
Please login to merge, or discard this patch.
src/Adapter/OAuth2.php 2 patches
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -249,9 +249,9 @@  discard block
 block discarded – undo
249 249
         $this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
250 250
         $this->clientSecret = $this->config->filter('keys')->get('secret');
251 251
 
252
-        if (!$this->clientId || !$this->clientSecret) {
252
+        if ( ! $this->clientId || ! $this->clientSecret) {
253 253
             throw new InvalidApplicationCredentialsException(
254
-                'Your application id is required in order to connect to ' . $this->providerId
254
+                'Your application id is required in order to connect to '.$this->providerId
255 255
             );
256 256
         }
257 257
 
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
         ];
286 286
 
287 287
         $refreshToken = $this->getStoredData('refresh_token');
288
-        if (!empty($refreshToken)) {
288
+        if ( ! empty($refreshToken)) {
289 289
             $this->tokenRefreshParameters = [
290 290
                 'grant_type' => 'refresh_token',
291 291
                 'refresh_token' => $refreshToken,
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
         }
294 294
 
295 295
         $this->apiRequestHeaders = [
296
-            'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
296
+            'Authorization' => 'Bearer '.$this->getStoredData('access_token')
297 297
         ];
298 298
     }
299 299
 
@@ -332,8 +332,8 @@  discard block
 block discarded – undo
332 332
      */
333 333
     public function isConnected()
334 334
     {
335
-        if ((bool)$this->getStoredData('access_token')) {
336
-            return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
335
+        if ((bool) $this->getStoredData('access_token')) {
336
+            return ( ! $this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
337 337
         }
338 338
         return false;
339 339
     }
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
     {
365 365
         $error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
366 366
 
367
-        if (!empty($error)) {
367
+        if ( ! empty($error)) {
368 368
             $error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
369 369
             $error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
370 370
 
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
             && $this->getStoredData('authorization_state') != $state
425 425
         ) {
426 426
             throw new InvalidAuthorizationStateException(
427
-                'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
427
+                'The authorization state [state='.substr(htmlentities($state), 0, 100).'] '
428 428
                 . 'of this page is either invalid or has already been consumed.'
429 429
             );
430 430
         }
@@ -466,23 +466,23 @@  discard block
 block discarded – undo
466 466
      */
467 467
     protected function getAuthorizeUrl($parameters = [])
468 468
     {
469
-        $this->AuthorizeUrlParameters = !empty($parameters)
469
+        $this->AuthorizeUrlParameters = ! empty($parameters)
470 470
             ? $parameters
471 471
             : array_replace(
472
-                (array)$this->AuthorizeUrlParameters,
473
-                (array)$this->config->get('authorize_url_parameters')
472
+                (array) $this->AuthorizeUrlParameters,
473
+                (array) $this->config->get('authorize_url_parameters')
474 474
             );
475 475
 
476 476
         if ($this->supportRequestState) {
477
-            if (!isset($this->AuthorizeUrlParameters['state'])) {
478
-                $this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
477
+            if ( ! isset($this->AuthorizeUrlParameters['state'])) {
478
+                $this->AuthorizeUrlParameters['state'] = 'HA-'.str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
479 479
             }
480 480
 
481 481
             $this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
482 482
         }
483 483
 
484 484
         $queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
485
-        return $this->authorizeUrl . '?' . $queryParams;
485
+        return $this->authorizeUrl.'?'.$queryParams;
486 486
     }
487 487
 
488 488
     /**
@@ -562,9 +562,9 @@  discard block
 block discarded – undo
562 562
 
563 563
         $collection = new Data\Collection($data);
564 564
 
565
-        if (!$collection->exists('access_token')) {
565
+        if ( ! $collection->exists('access_token')) {
566 566
             throw new InvalidAccessTokenException(
567
-                'Provider returned no access_token: ' . htmlentities($response)
567
+                'Provider returned no access_token: '.htmlentities($response)
568 568
             );
569 569
         }
570 570
 
@@ -577,7 +577,7 @@  discard block
 block discarded – undo
577 577
 
578 578
         // calculate when the access token expire
579 579
         if ($collection->exists('expires_in')) {
580
-            $expires_at = time() + (int)$collection->get('expires_in');
580
+            $expires_at = time() + (int) $collection->get('expires_in');
581 581
 
582 582
             $this->storeData('expires_in', $collection->get('expires_in'));
583 583
             $this->storeData('expires_at', $expires_at);
@@ -615,11 +615,11 @@  discard block
 block discarded – undo
615 615
      */
616 616
     public function refreshAccessToken($parameters = [])
617 617
     {
618
-        $this->tokenRefreshParameters = !empty($parameters)
618
+        $this->tokenRefreshParameters = ! empty($parameters)
619 619
             ? $parameters
620 620
             : $this->tokenRefreshParameters;
621 621
 
622
-        if (!$this->isRefreshTokenAvailable()) {
622
+        if ( ! $this->isRefreshTokenAvailable()) {
623 623
             return null;
624 624
         }
625 625
 
@@ -650,7 +650,7 @@  discard block
 block discarded – undo
650 650
         }
651 651
 
652 652
         $expires_at = $this->getStoredData('expires_at');
653
-        if (!$expires_at) {
653
+        if ( ! $expires_at) {
654 654
             return null;
655 655
         }
656 656
 
@@ -715,21 +715,21 @@  discard block
 block discarded – undo
715 715
         }
716 716
 
717 717
         if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
718
-            $url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
718
+            $url = rtrim($this->apiBaseUrl, '/').'/'.ltrim($url, '/');
719 719
         }
720 720
 
721
-        $parameters = array_replace($this->apiRequestParameters, (array)$parameters);
722
-        $headers = array_replace($this->apiRequestHeaders, (array)$headers);
721
+        $parameters = array_replace($this->apiRequestParameters, (array) $parameters);
722
+        $headers = array_replace($this->apiRequestHeaders, (array) $headers);
723 723
 
724 724
         $response = $this->httpClient->request(
725 725
             $url,
726
-            $method,     // HTTP Request Method. Defaults to GET.
726
+            $method, // HTTP Request Method. Defaults to GET.
727 727
             $parameters, // Request Parameters
728
-            $headers,    // Request Headers
728
+            $headers, // Request Headers
729 729
             $multipart   // Is request multipart
730 730
         );
731 731
 
732
-        $this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
732
+        $this->validateApiResponse('Signed API request to '.$url.' has returned an error');
733 733
 
734 734
         $response = (new Data\Parser())->parse($response);
735 735
 
Please login to merge, or discard this patch.
Indentation   +715 added lines, -715 removed lines patch added patch discarded remove patch
@@ -24,720 +24,720 @@
 block discarded – undo
24 24
  */
25 25
 abstract class OAuth2 extends AbstractAdapter implements AdapterInterface
26 26
 {
27
-    /**
28
-     * Client Identifier
29
-     *
30
-     * RFC6749: client_id REQUIRED. The client identifier issued to the client during
31
-     * the registration process described by Section 2.2.
32
-     *
33
-     * http://tools.ietf.org/html/rfc6749#section-2.2
34
-     *
35
-     * @var string
36
-     */
37
-    protected $clientId = '';
38
-
39
-    /**
40
-     * Client Secret
41
-     *
42
-     * RFC6749: client_secret REQUIRED. The client secret. The client MAY omit the
43
-     * parameter if the client secret is an empty string.
44
-     *
45
-     * http://tools.ietf.org/html/rfc6749#section-2.2
46
-     *
47
-     * @var string
48
-     */
49
-    protected $clientSecret = '';
50
-
51
-    /**
52
-     * Access Token Scope
53
-     *
54
-     * RFC6749: The authorization and token endpoints allow the client to specify the
55
-     * scope of the access request using the "scope" request parameter.
56
-     *
57
-     * http://tools.ietf.org/html/rfc6749#section-3.3
58
-     *
59
-     * @var string
60
-     */
61
-    protected $scope = '';
62
-
63
-    /**
64
-     * Base URL to provider API
65
-     *
66
-     * This var will be used to build urls when sending signed requests
67
-     *
68
-     * @var string
69
-     */
70
-    protected $apiBaseUrl = '';
71
-
72
-    /**
73
-     * Authorization Endpoint
74
-     *
75
-     * RFC6749: The authorization endpoint is used to interact with the resource
76
-     * owner and obtain an authorization grant.
77
-     *
78
-     * http://tools.ietf.org/html/rfc6749#section-3.1
79
-     *
80
-     * @var string
81
-     */
82
-    protected $authorizeUrl = '';
83
-
84
-    /**
85
-     * Access Token Endpoint
86
-     *
87
-     * RFC6749: The token endpoint is used by the client to obtain an access token by
88
-     * presenting its authorization grant or refresh token.
89
-     *
90
-     * http://tools.ietf.org/html/rfc6749#section-3.2
91
-     *
92
-     * @var string
93
-     */
94
-    protected $accessTokenUrl = '';
95
-
96
-    /**
97
-     * TokenInfo endpoint
98
-     *
99
-     * Access token validation. OPTIONAL.
100
-     *
101
-     * @var string
102
-     */
103
-    protected $accessTokenInfoUrl = '';
104
-
105
-    /**
106
-     * IPD API Documentation
107
-     *
108
-     * OPTIONAL.
109
-     *
110
-     * @var string
111
-     */
112
-    protected $apiDocumentation = '';
113
-
114
-    /**
115
-     * Redirection Endpoint or Callback
116
-     *
117
-     * RFC6749: After completing its interaction with the resource owner, the
118
-     * authorization server directs the resource owner's user-agent back to
119
-     * the client.
120
-     *
121
-     * http://tools.ietf.org/html/rfc6749#section-3.1.2
122
-     *
123
-     * @var string
124
-     */
125
-    protected $callback = '';
126
-
127
-    /**
128
-     * Authorization Url Parameters
129
-     *
130
-     * @var array
131
-     */
132
-    protected $AuthorizeUrlParameters = [];
133
-
134
-
135
-    /**
136
-     * Authorization Url Parameter encoding type
137
-     * @see https://www.php.net/manual/de/function.http-build-query.php
138
-     *
139
-     * @var string
140
-     */
141
-    protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC1738;
142
-
143
-    /**
144
-     * Authorization Request State
145
-     *
146
-     * @var bool
147
-     */
148
-    protected $supportRequestState = true;
149
-
150
-    /**
151
-     * Access Token name
152
-     *
153
-     * While most providers will use 'access_token' as name for the Access Token attribute, other do not.
154
-     * On the latter case, this should be set by sub classes.
155
-     *
156
-     * @var string
157
-     */
158
-    protected $accessTokenName = 'access_token';
159
-
160
-    /**
161
-     * Authorization Request HTTP method.
162
-     *
163
-     * @see exchangeCodeForAccessToken()
164
-     *
165
-     * @var string
166
-     */
167
-    protected $tokenExchangeMethod = 'POST';
168
-
169
-    /**
170
-     * Authorization Request URL parameters.
171
-     *
172
-     * Sub classes may change add any additional parameter when necessary.
173
-     *
174
-     * @see exchangeCodeForAccessToken()
175
-     *
176
-     * @var array
177
-     */
178
-    protected $tokenExchangeParameters = [];
179
-
180
-    /**
181
-     * Authorization Request HTTP headers.
182
-     *
183
-     * Sub classes may add any additional header when necessary.
184
-     *
185
-     * @see exchangeCodeForAccessToken()
186
-     *
187
-     * @var array
188
-     */
189
-    protected $tokenExchangeHeaders = [];
190
-
191
-    /**
192
-     * Refresh Token Request HTTP method.
193
-     *
194
-     * @see refreshAccessToken()
195
-     *
196
-     * @var string
197
-     */
198
-    protected $tokenRefreshMethod = 'POST';
199
-
200
-    /**
201
-     * Refresh Token Request URL parameters.
202
-     *
203
-     * Sub classes may change add any additional parameter when necessary.
204
-     *
205
-     * @see refreshAccessToken()
206
-     *
207
-     * @var array|null
208
-     */
209
-    protected $tokenRefreshParameters = null;
210
-
211
-    /**
212
-     * Refresh Token Request HTTP headers.
213
-     *
214
-     * Sub classes may add any additional header when necessary.
215
-     *
216
-     * @see refreshAccessToken()
217
-     *
218
-     * @var array
219
-     */
220
-    protected $tokenRefreshHeaders = [];
221
-
222
-    /**
223
-     * Authorization Request URL parameters.
224
-     *
225
-     * Sub classes may change add any additional parameter when necessary.
226
-     *
227
-     * @see apiRequest()
228
-     *
229
-     * @var array
230
-     */
231
-    protected $apiRequestParameters = [];
232
-
233
-    /**
234
-     * Authorization Request HTTP headers.
235
-     *
236
-     * Sub classes may add any additional header when necessary.
237
-     *
238
-     * @see apiRequest()
239
-     *
240
-     * @var array
241
-     */
242
-    protected $apiRequestHeaders = [];
243
-
244
-    /**
245
-     * {@inheritdoc}
246
-     */
247
-    protected function configure()
248
-    {
249
-        $this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
250
-        $this->clientSecret = $this->config->filter('keys')->get('secret');
251
-
252
-        if (!$this->clientId || !$this->clientSecret) {
253
-            throw new InvalidApplicationCredentialsException(
254
-                'Your application id is required in order to connect to ' . $this->providerId
255
-            );
256
-        }
257
-
258
-        $this->scope = $this->config->exists('scope') ? $this->config->get('scope') : $this->scope;
259
-
260
-        if ($this->config->exists('tokens')) {
261
-            $this->setAccessToken($this->config->get('tokens'));
262
-        }
27
+	/**
28
+	 * Client Identifier
29
+	 *
30
+	 * RFC6749: client_id REQUIRED. The client identifier issued to the client during
31
+	 * the registration process described by Section 2.2.
32
+	 *
33
+	 * http://tools.ietf.org/html/rfc6749#section-2.2
34
+	 *
35
+	 * @var string
36
+	 */
37
+	protected $clientId = '';
38
+
39
+	/**
40
+	 * Client Secret
41
+	 *
42
+	 * RFC6749: client_secret REQUIRED. The client secret. The client MAY omit the
43
+	 * parameter if the client secret is an empty string.
44
+	 *
45
+	 * http://tools.ietf.org/html/rfc6749#section-2.2
46
+	 *
47
+	 * @var string
48
+	 */
49
+	protected $clientSecret = '';
50
+
51
+	/**
52
+	 * Access Token Scope
53
+	 *
54
+	 * RFC6749: The authorization and token endpoints allow the client to specify the
55
+	 * scope of the access request using the "scope" request parameter.
56
+	 *
57
+	 * http://tools.ietf.org/html/rfc6749#section-3.3
58
+	 *
59
+	 * @var string
60
+	 */
61
+	protected $scope = '';
62
+
63
+	/**
64
+	 * Base URL to provider API
65
+	 *
66
+	 * This var will be used to build urls when sending signed requests
67
+	 *
68
+	 * @var string
69
+	 */
70
+	protected $apiBaseUrl = '';
71
+
72
+	/**
73
+	 * Authorization Endpoint
74
+	 *
75
+	 * RFC6749: The authorization endpoint is used to interact with the resource
76
+	 * owner and obtain an authorization grant.
77
+	 *
78
+	 * http://tools.ietf.org/html/rfc6749#section-3.1
79
+	 *
80
+	 * @var string
81
+	 */
82
+	protected $authorizeUrl = '';
83
+
84
+	/**
85
+	 * Access Token Endpoint
86
+	 *
87
+	 * RFC6749: The token endpoint is used by the client to obtain an access token by
88
+	 * presenting its authorization grant or refresh token.
89
+	 *
90
+	 * http://tools.ietf.org/html/rfc6749#section-3.2
91
+	 *
92
+	 * @var string
93
+	 */
94
+	protected $accessTokenUrl = '';
95
+
96
+	/**
97
+	 * TokenInfo endpoint
98
+	 *
99
+	 * Access token validation. OPTIONAL.
100
+	 *
101
+	 * @var string
102
+	 */
103
+	protected $accessTokenInfoUrl = '';
104
+
105
+	/**
106
+	 * IPD API Documentation
107
+	 *
108
+	 * OPTIONAL.
109
+	 *
110
+	 * @var string
111
+	 */
112
+	protected $apiDocumentation = '';
113
+
114
+	/**
115
+	 * Redirection Endpoint or Callback
116
+	 *
117
+	 * RFC6749: After completing its interaction with the resource owner, the
118
+	 * authorization server directs the resource owner's user-agent back to
119
+	 * the client.
120
+	 *
121
+	 * http://tools.ietf.org/html/rfc6749#section-3.1.2
122
+	 *
123
+	 * @var string
124
+	 */
125
+	protected $callback = '';
126
+
127
+	/**
128
+	 * Authorization Url Parameters
129
+	 *
130
+	 * @var array
131
+	 */
132
+	protected $AuthorizeUrlParameters = [];
133
+
134
+
135
+	/**
136
+	 * Authorization Url Parameter encoding type
137
+	 * @see https://www.php.net/manual/de/function.http-build-query.php
138
+	 *
139
+	 * @var string
140
+	 */
141
+	protected $AuthorizeUrlParametersEncType = PHP_QUERY_RFC1738;
142
+
143
+	/**
144
+	 * Authorization Request State
145
+	 *
146
+	 * @var bool
147
+	 */
148
+	protected $supportRequestState = true;
149
+
150
+	/**
151
+	 * Access Token name
152
+	 *
153
+	 * While most providers will use 'access_token' as name for the Access Token attribute, other do not.
154
+	 * On the latter case, this should be set by sub classes.
155
+	 *
156
+	 * @var string
157
+	 */
158
+	protected $accessTokenName = 'access_token';
159
+
160
+	/**
161
+	 * Authorization Request HTTP method.
162
+	 *
163
+	 * @see exchangeCodeForAccessToken()
164
+	 *
165
+	 * @var string
166
+	 */
167
+	protected $tokenExchangeMethod = 'POST';
168
+
169
+	/**
170
+	 * Authorization Request URL parameters.
171
+	 *
172
+	 * Sub classes may change add any additional parameter when necessary.
173
+	 *
174
+	 * @see exchangeCodeForAccessToken()
175
+	 *
176
+	 * @var array
177
+	 */
178
+	protected $tokenExchangeParameters = [];
179
+
180
+	/**
181
+	 * Authorization Request HTTP headers.
182
+	 *
183
+	 * Sub classes may add any additional header when necessary.
184
+	 *
185
+	 * @see exchangeCodeForAccessToken()
186
+	 *
187
+	 * @var array
188
+	 */
189
+	protected $tokenExchangeHeaders = [];
190
+
191
+	/**
192
+	 * Refresh Token Request HTTP method.
193
+	 *
194
+	 * @see refreshAccessToken()
195
+	 *
196
+	 * @var string
197
+	 */
198
+	protected $tokenRefreshMethod = 'POST';
199
+
200
+	/**
201
+	 * Refresh Token Request URL parameters.
202
+	 *
203
+	 * Sub classes may change add any additional parameter when necessary.
204
+	 *
205
+	 * @see refreshAccessToken()
206
+	 *
207
+	 * @var array|null
208
+	 */
209
+	protected $tokenRefreshParameters = null;
210
+
211
+	/**
212
+	 * Refresh Token Request HTTP headers.
213
+	 *
214
+	 * Sub classes may add any additional header when necessary.
215
+	 *
216
+	 * @see refreshAccessToken()
217
+	 *
218
+	 * @var array
219
+	 */
220
+	protected $tokenRefreshHeaders = [];
221
+
222
+	/**
223
+	 * Authorization Request URL parameters.
224
+	 *
225
+	 * Sub classes may change add any additional parameter when necessary.
226
+	 *
227
+	 * @see apiRequest()
228
+	 *
229
+	 * @var array
230
+	 */
231
+	protected $apiRequestParameters = [];
232
+
233
+	/**
234
+	 * Authorization Request HTTP headers.
235
+	 *
236
+	 * Sub classes may add any additional header when necessary.
237
+	 *
238
+	 * @see apiRequest()
239
+	 *
240
+	 * @var array
241
+	 */
242
+	protected $apiRequestHeaders = [];
243
+
244
+	/**
245
+	 * {@inheritdoc}
246
+	 */
247
+	protected function configure()
248
+	{
249
+		$this->clientId = $this->config->filter('keys')->get('id') ?: $this->config->filter('keys')->get('key');
250
+		$this->clientSecret = $this->config->filter('keys')->get('secret');
251
+
252
+		if (!$this->clientId || !$this->clientSecret) {
253
+			throw new InvalidApplicationCredentialsException(
254
+				'Your application id is required in order to connect to ' . $this->providerId
255
+			);
256
+		}
257
+
258
+		$this->scope = $this->config->exists('scope') ? $this->config->get('scope') : $this->scope;
259
+
260
+		if ($this->config->exists('tokens')) {
261
+			$this->setAccessToken($this->config->get('tokens'));
262
+		}
263 263
         
264
-        if ($this->config->exists('supportRequestState')) {
265
-            $this->supportRequestState = $this->config->get('supportRequestState');
266
-        }
267
-
268
-        $this->setCallback($this->config->get('callback'));
269
-        $this->setApiEndpoints($this->config->get('endpoints'));
270
-    }
271
-
272
-    /**
273
-     * {@inheritdoc}
274
-     */
275
-    protected function initialize()
276
-    {
277
-        $this->AuthorizeUrlParameters = [
278
-            'response_type' => 'code',
279
-            'client_id' => $this->clientId,
280
-            'redirect_uri' => $this->callback,
281
-            'scope' => $this->scope,
282
-        ];
283
-
284
-        $this->tokenExchangeParameters = [
285
-            'client_id' => $this->clientId,
286
-            'client_secret' => $this->clientSecret,
287
-            'grant_type' => 'authorization_code',
288
-            'redirect_uri' => $this->callback
289
-        ];
290
-
291
-        $refreshToken = $this->getStoredData('refresh_token');
292
-        if (!empty($refreshToken)) {
293
-            $this->tokenRefreshParameters = [
294
-                'grant_type' => 'refresh_token',
295
-                'refresh_token' => $refreshToken,
296
-            ];
297
-        }
298
-
299
-        $this->apiRequestHeaders = [
300
-            'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
301
-        ];
302
-    }
303
-
304
-    /**
305
-     * {@inheritdoc}
306
-     */
307
-    public function authenticate()
308
-    {
309
-        $this->logger->info(sprintf('%s::authenticate()', get_class($this)));
310
-
311
-        if ($this->isConnected()) {
312
-            return true;
313
-        }
314
-
315
-        try {
316
-            $this->authenticateCheckError();
317
-
318
-            $code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
319
-
320
-            if (empty($code)) {
321
-                $this->authenticateBegin();
322
-            } else {
323
-                $this->authenticateFinish();
324
-            }
325
-        } catch (Exception $e) {
326
-            $this->clearStoredData();
327
-
328
-            throw $e;
329
-        }
330
-
331
-        return null;
332
-    }
333
-
334
-    /**
335
-     * {@inheritdoc}
336
-     */
337
-    public function isConnected()
338
-    {
339
-        if ((bool)$this->getStoredData('access_token')) {
340
-            return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
341
-        }
342
-        return false;
343
-    }
344
-
345
-    /**
346
-     * If we can use a refresh token, then an expired token does not stop us being connected.
347
-     *
348
-     * @return bool
349
-     */
350
-    public function isRefreshTokenAvailable()
351
-    {
352
-        return is_array($this->tokenRefreshParameters);
353
-    }
354
-
355
-    /**
356
-     * Authorization Request Error Response
357
-     *
358
-     * RFC6749: If the request fails due to a missing, invalid, or mismatching
359
-     * redirection URI, or if the client identifier is missing or invalid,
360
-     * the authorization server SHOULD inform the resource owner of the error.
361
-     *
362
-     * http://tools.ietf.org/html/rfc6749#section-4.1.2.1
363
-     *
364
-     * @throws \Hybridauth\Exception\InvalidAuthorizationCodeException
365
-     * @throws \Hybridauth\Exception\AuthorizationDeniedException
366
-     */
367
-    protected function authenticateCheckError()
368
-    {
369
-        $error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
370
-
371
-        if (!empty($error)) {
372
-            $error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
373
-            $error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
374
-
375
-            $collated_error = sprintf('Provider returned an error: %s %s %s', $error, $error_description, $error_uri);
376
-
377
-            if ($error == 'access_denied') {
378
-                throw new AuthorizationDeniedException($collated_error);
379
-            }
380
-
381
-            throw new InvalidAuthorizationCodeException($collated_error);
382
-        }
383
-    }
384
-
385
-    /**
386
-     * Initiate the authorization protocol
387
-     *
388
-     * Build Authorization URL for Authorization Request and redirect the user-agent to the
389
-     * Authorization Server.
390
-     */
391
-    protected function authenticateBegin()
392
-    {
393
-        $authUrl = $this->getAuthorizeUrl();
394
-
395
-        $this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
396
-
397
-        HttpClient\Util::redirect($authUrl);
398
-    }
399
-
400
-    /**
401
-     * Finalize the authorization process
402
-     *
403
-     * @throws \Hybridauth\Exception\HttpClientFailureException
404
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
405
-     * @throws InvalidAccessTokenException
406
-     * @throws InvalidAuthorizationStateException
407
-     */
408
-    protected function authenticateFinish()
409
-    {
410
-        $this->logger->debug(
411
-            sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
412
-            [HttpClient\Util::getCurrentUrl(true)]
413
-        );
414
-
415
-        $state = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'state');
416
-        $code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
417
-
418
-        /**
419
-         * Authorization Request State
420
-         *
421
-         * RFC6749: state : RECOMMENDED. An opaque value used by the client to maintain
422
-         * state between the request and callback. The authorization server includes
423
-         * this value when redirecting the user-agent back to the client.
424
-         *
425
-         * http://tools.ietf.org/html/rfc6749#section-4.1.1
426
-         */
427
-        if ($this->supportRequestState
428
-            && $this->getStoredData('authorization_state') != $state
429
-        ) {
430
-            throw new InvalidAuthorizationStateException(
431
-                'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
432
-                . 'of this page is either invalid or has already been consumed.'
433
-            );
434
-        }
435
-
436
-        /**
437
-         * Authorization Request Code
438
-         *
439
-         * RFC6749: If the resource owner grants the access request, the authorization
440
-         * server issues an authorization code and delivers it to the client:
441
-         *
442
-         * http://tools.ietf.org/html/rfc6749#section-4.1.2
443
-         */
444
-        $response = $this->exchangeCodeForAccessToken($code);
445
-
446
-        $this->validateAccessTokenExchange($response);
447
-
448
-        $this->initialize();
449
-    }
450
-
451
-    /**
452
-     * Build Authorization URL for Authorization Request
453
-     *
454
-     * RFC6749: The client constructs the request URI by adding the following
455
-     * $parameters to the query component of the authorization endpoint URI:
456
-     *
457
-     *    - response_type  REQUIRED. Value MUST be set to "code".
458
-     *    - client_id      REQUIRED.
459
-     *    - redirect_uri   OPTIONAL.
460
-     *    - scope          OPTIONAL.
461
-     *    - state          RECOMMENDED.
462
-     *
463
-     * http://tools.ietf.org/html/rfc6749#section-4.1.1
464
-     *
465
-     * Sub classes may redefine this method when necessary.
466
-     *
467
-     * @param array $parameters
468
-     *
469
-     * @return string Authorization URL
470
-     */
471
-    protected function getAuthorizeUrl($parameters = [])
472
-    {
473
-        $this->AuthorizeUrlParameters = !empty($parameters)
474
-            ? $parameters
475
-            : array_replace(
476
-                (array)$this->AuthorizeUrlParameters,
477
-                (array)$this->config->get('authorize_url_parameters')
478
-            );
479
-
480
-        if ($this->supportRequestState) {
481
-            if (!isset($this->AuthorizeUrlParameters['state'])) {
482
-                $this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
483
-            }
484
-
485
-            $this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
486
-        }
487
-
488
-        $queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
489
-        return $this->authorizeUrl . '?' . $queryParams;
490
-    }
491
-
492
-    /**
493
-     * Access Token Request
494
-     *
495
-     * This method will exchange the received $code in loginFinish() with an Access Token.
496
-     *
497
-     * RFC6749: The client makes a request to the token endpoint by sending the
498
-     * following parameters using the "application/x-www-form-urlencoded"
499
-     * with a character encoding of UTF-8 in the HTTP request entity-body:
500
-     *
501
-     *    - grant_type    REQUIRED. Value MUST be set to "authorization_code".
502
-     *    - code          REQUIRED. The authorization code received from the authorization server.
503
-     *    - redirect_uri  REQUIRED.
504
-     *    - client_id     REQUIRED.
505
-     *
506
-     * http://tools.ietf.org/html/rfc6749#section-4.1.3
507
-     *
508
-     * @param string $code
509
-     *
510
-     * @return string Raw Provider API response
511
-     * @throws \Hybridauth\Exception\HttpClientFailureException
512
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
513
-     */
514
-    protected function exchangeCodeForAccessToken($code)
515
-    {
516
-        $this->tokenExchangeParameters['code'] = $code;
517
-
518
-        $response = $this->httpClient->request(
519
-            $this->accessTokenUrl,
520
-            $this->tokenExchangeMethod,
521
-            $this->tokenExchangeParameters,
522
-            $this->tokenExchangeHeaders
523
-        );
524
-
525
-        $this->validateApiResponse('Unable to exchange code for API access token');
526
-
527
-        return $response;
528
-    }
529
-
530
-    /**
531
-     * Validate Access Token Response
532
-     *
533
-     * RFC6749: If the access token request is valid and authorized, the
534
-     * authorization server issues an access token and optional refresh token.
535
-     * If the request client authentication failed or is invalid, the authorization
536
-     * server returns an error response as described in Section 5.2.
537
-     *
538
-     * Example of a successful response:
539
-     *
540
-     *  HTTP/1.1 200 OK
541
-     *  Content-Type: application/json;charset=UTF-8
542
-     *  Cache-Control: no-store
543
-     *  Pragma: no-cache
544
-     *
545
-     *  {
546
-     *      "access_token":"2YotnFZFEjr1zCsicMWpAA",
547
-     *      "token_type":"example",
548
-     *      "expires_in":3600,
549
-     *      "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
550
-     *      "example_parameter":"example_value"
551
-     *  }
552
-     *
553
-     * http://tools.ietf.org/html/rfc6749#section-4.1.4
554
-     *
555
-     * This method uses Data_Parser to attempt to decodes the raw $response (usually JSON)
556
-     * into a data collection.
557
-     *
558
-     * @param string $response
559
-     *
560
-     * @return \Hybridauth\Data\Collection
561
-     * @throws InvalidAccessTokenException
562
-     */
563
-    protected function validateAccessTokenExchange($response)
564
-    {
565
-        $data = (new Data\Parser())->parse($response);
566
-
567
-        $collection = new Data\Collection($data);
568
-
569
-        if (!$collection->exists('access_token')) {
570
-            throw new InvalidAccessTokenException(
571
-                'Provider returned no access_token: ' . htmlentities($response)
572
-            );
573
-        }
574
-
575
-        $this->storeData('access_token', $collection->get('access_token'));
576
-        $this->storeData('token_type', $collection->get('token_type'));
577
-
578
-        if ($collection->get('refresh_token')) {
579
-            $this->storeData('refresh_token', $collection->get('refresh_token'));
580
-        }
581
-
582
-        // calculate when the access token expire
583
-        if ($collection->exists('expires_in')) {
584
-            $expires_at = time() + (int)$collection->get('expires_in');
585
-
586
-            $this->storeData('expires_in', $collection->get('expires_in'));
587
-            $this->storeData('expires_at', $expires_at);
588
-        }
589
-
590
-        $this->deleteStoredData('authorization_state');
591
-
592
-        $this->initialize();
593
-
594
-        return $collection;
595
-    }
596
-
597
-    /**
598
-     * Refreshing an Access Token
599
-     *
600
-     * RFC6749: If the authorization server issued a refresh token to the
601
-     * client, the client makes a refresh request to the token endpoint by
602
-     * adding the following parameters ... in the HTTP request entity-body:
603
-     *
604
-     *    - grant_type     REQUIRED. Value MUST be set to "refresh_token".
605
-     *    - refresh_token  REQUIRED. The refresh token issued to the client.
606
-     *    - scope          OPTIONAL.
607
-     *
608
-     * http://tools.ietf.org/html/rfc6749#section-6
609
-     *
610
-     * This method is similar to exchangeCodeForAccessToken(). The only
611
-     * difference is here we exchange refresh_token for a new access_token.
612
-     *
613
-     * @param array $parameters
614
-     *
615
-     * @return string|null Raw Provider API response, or null if we cannot refresh
616
-     * @throws \Hybridauth\Exception\HttpClientFailureException
617
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
618
-     * @throws InvalidAccessTokenException
619
-     */
620
-    public function refreshAccessToken($parameters = [])
621
-    {
622
-        $this->tokenRefreshParameters = !empty($parameters)
623
-            ? $parameters
624
-            : $this->tokenRefreshParameters;
625
-
626
-        if (!$this->isRefreshTokenAvailable()) {
627
-            return null;
628
-        }
629
-
630
-        $response = $this->httpClient->request(
631
-            $this->accessTokenUrl,
632
-            $this->tokenRefreshMethod,
633
-            $this->tokenRefreshParameters,
634
-            $this->tokenRefreshHeaders
635
-        );
636
-
637
-        $this->validateApiResponse('Unable to refresh the access token');
638
-
639
-        $this->validateRefreshAccessToken($response);
640
-
641
-        return $response;
642
-    }
643
-
644
-    /**
645
-     * Check whether access token has expired
646
-     *
647
-     * @param int|null $time
648
-     * @return bool|null
649
-     */
650
-    public function hasAccessTokenExpired($time = null)
651
-    {
652
-        if ($time === null) {
653
-            $time = time();
654
-        }
655
-
656
-        $expires_at = $this->getStoredData('expires_at');
657
-        if (!$expires_at) {
658
-            return null;
659
-        }
660
-
661
-        return $expires_at <= $time;
662
-    }
663
-
664
-    /**
665
-     * Validate Refresh Access Token Request
666
-     *
667
-     * RFC6749: If valid and authorized, the authorization server issues an
668
-     * access token as described in Section 5.1.  If the request failed
669
-     * verification or is invalid, the authorization server returns an error
670
-     * response as described in Section 5.2.
671
-     *
672
-     * http://tools.ietf.org/html/rfc6749#section-6
673
-     * http://tools.ietf.org/html/rfc6749#section-5.1
674
-     * http://tools.ietf.org/html/rfc6749#section-5.2
675
-     *
676
-     * This method simply use validateAccessTokenExchange(), however sub
677
-     * classes may redefine it when necessary.
678
-     *
679
-     * @param $response
680
-     *
681
-     * @return \Hybridauth\Data\Collection
682
-     * @throws InvalidAccessTokenException
683
-     */
684
-    protected function validateRefreshAccessToken($response)
685
-    {
686
-        return $this->validateAccessTokenExchange($response);
687
-    }
688
-
689
-    /**
690
-     * Send a signed request to provider API
691
-     *
692
-     * RFC6749: Accessing Protected Resources: The client accesses protected
693
-     * resources by presenting the access token to the resource server. The
694
-     * resource server MUST validate the access token and ensure that it has
695
-     * not expired and that its scope covers the requested resource.
696
-     *
697
-     * Note: Since the specifics of error responses is beyond the scope of
698
-     * RFC6749 and OAuth specifications, Hybridauth will consider any HTTP
699
-     * status code that is different than '200 OK' as an ERROR.
700
-     *
701
-     * http://tools.ietf.org/html/rfc6749#section-7
702
-     *
703
-     * @param string $url
704
-     * @param string $method
705
-     * @param array $parameters
706
-     * @param array $headers
707
-     * @param bool $multipart
708
-     *
709
-     * @return mixed
710
-     * @throws \Hybridauth\Exception\HttpClientFailureException
711
-     * @throws \Hybridauth\Exception\HttpRequestFailedException
712
-     * @throws InvalidAccessTokenException
713
-     */
714
-    public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
715
-    {
716
-        // refresh tokens if needed
717
-        $this->maintainToken();
718
-        if ($this->hasAccessTokenExpired() === true) {
719
-            $this->refreshAccessToken();
720
-        }
721
-
722
-        if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
723
-            $url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
724
-        }
725
-
726
-        $parameters = array_replace($this->apiRequestParameters, (array)$parameters);
727
-        $headers = array_replace($this->apiRequestHeaders, (array)$headers);
728
-
729
-        $response = $this->httpClient->request(
730
-            $url,
731
-            $method,     // HTTP Request Method. Defaults to GET.
732
-            $parameters, // Request Parameters
733
-            $headers,    // Request Headers
734
-            $multipart   // Is request multipart
735
-        );
736
-
737
-        $this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
738
-
739
-        $response = (new Data\Parser())->parse($response);
740
-
741
-        return $response;
742
-    }
264
+		if ($this->config->exists('supportRequestState')) {
265
+			$this->supportRequestState = $this->config->get('supportRequestState');
266
+		}
267
+
268
+		$this->setCallback($this->config->get('callback'));
269
+		$this->setApiEndpoints($this->config->get('endpoints'));
270
+	}
271
+
272
+	/**
273
+	 * {@inheritdoc}
274
+	 */
275
+	protected function initialize()
276
+	{
277
+		$this->AuthorizeUrlParameters = [
278
+			'response_type' => 'code',
279
+			'client_id' => $this->clientId,
280
+			'redirect_uri' => $this->callback,
281
+			'scope' => $this->scope,
282
+		];
283
+
284
+		$this->tokenExchangeParameters = [
285
+			'client_id' => $this->clientId,
286
+			'client_secret' => $this->clientSecret,
287
+			'grant_type' => 'authorization_code',
288
+			'redirect_uri' => $this->callback
289
+		];
290
+
291
+		$refreshToken = $this->getStoredData('refresh_token');
292
+		if (!empty($refreshToken)) {
293
+			$this->tokenRefreshParameters = [
294
+				'grant_type' => 'refresh_token',
295
+				'refresh_token' => $refreshToken,
296
+			];
297
+		}
298
+
299
+		$this->apiRequestHeaders = [
300
+			'Authorization' => 'Bearer ' . $this->getStoredData('access_token')
301
+		];
302
+	}
303
+
304
+	/**
305
+	 * {@inheritdoc}
306
+	 */
307
+	public function authenticate()
308
+	{
309
+		$this->logger->info(sprintf('%s::authenticate()', get_class($this)));
310
+
311
+		if ($this->isConnected()) {
312
+			return true;
313
+		}
314
+
315
+		try {
316
+			$this->authenticateCheckError();
317
+
318
+			$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
319
+
320
+			if (empty($code)) {
321
+				$this->authenticateBegin();
322
+			} else {
323
+				$this->authenticateFinish();
324
+			}
325
+		} catch (Exception $e) {
326
+			$this->clearStoredData();
327
+
328
+			throw $e;
329
+		}
330
+
331
+		return null;
332
+	}
333
+
334
+	/**
335
+	 * {@inheritdoc}
336
+	 */
337
+	public function isConnected()
338
+	{
339
+		if ((bool)$this->getStoredData('access_token')) {
340
+			return (!$this->hasAccessTokenExpired() || $this->isRefreshTokenAvailable());
341
+		}
342
+		return false;
343
+	}
344
+
345
+	/**
346
+	 * If we can use a refresh token, then an expired token does not stop us being connected.
347
+	 *
348
+	 * @return bool
349
+	 */
350
+	public function isRefreshTokenAvailable()
351
+	{
352
+		return is_array($this->tokenRefreshParameters);
353
+	}
354
+
355
+	/**
356
+	 * Authorization Request Error Response
357
+	 *
358
+	 * RFC6749: If the request fails due to a missing, invalid, or mismatching
359
+	 * redirection URI, or if the client identifier is missing or invalid,
360
+	 * the authorization server SHOULD inform the resource owner of the error.
361
+	 *
362
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.2.1
363
+	 *
364
+	 * @throws \Hybridauth\Exception\InvalidAuthorizationCodeException
365
+	 * @throws \Hybridauth\Exception\AuthorizationDeniedException
366
+	 */
367
+	protected function authenticateCheckError()
368
+	{
369
+		$error = filter_input(INPUT_GET, 'error', FILTER_SANITIZE_SPECIAL_CHARS);
370
+
371
+		if (!empty($error)) {
372
+			$error_description = filter_input(INPUT_GET, 'error_description', FILTER_SANITIZE_SPECIAL_CHARS);
373
+			$error_uri = filter_input(INPUT_GET, 'error_uri', FILTER_SANITIZE_SPECIAL_CHARS);
374
+
375
+			$collated_error = sprintf('Provider returned an error: %s %s %s', $error, $error_description, $error_uri);
376
+
377
+			if ($error == 'access_denied') {
378
+				throw new AuthorizationDeniedException($collated_error);
379
+			}
380
+
381
+			throw new InvalidAuthorizationCodeException($collated_error);
382
+		}
383
+	}
384
+
385
+	/**
386
+	 * Initiate the authorization protocol
387
+	 *
388
+	 * Build Authorization URL for Authorization Request and redirect the user-agent to the
389
+	 * Authorization Server.
390
+	 */
391
+	protected function authenticateBegin()
392
+	{
393
+		$authUrl = $this->getAuthorizeUrl();
394
+
395
+		$this->logger->debug(sprintf('%s::authenticateBegin(), redirecting user to:', get_class($this)), [$authUrl]);
396
+
397
+		HttpClient\Util::redirect($authUrl);
398
+	}
399
+
400
+	/**
401
+	 * Finalize the authorization process
402
+	 *
403
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
404
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
405
+	 * @throws InvalidAccessTokenException
406
+	 * @throws InvalidAuthorizationStateException
407
+	 */
408
+	protected function authenticateFinish()
409
+	{
410
+		$this->logger->debug(
411
+			sprintf('%s::authenticateFinish(), callback url:', get_class($this)),
412
+			[HttpClient\Util::getCurrentUrl(true)]
413
+		);
414
+
415
+		$state = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'state');
416
+		$code = filter_input($_SERVER['REQUEST_METHOD'] === 'POST' ? INPUT_POST : INPUT_GET, 'code');
417
+
418
+		/**
419
+		 * Authorization Request State
420
+		 *
421
+		 * RFC6749: state : RECOMMENDED. An opaque value used by the client to maintain
422
+		 * state between the request and callback. The authorization server includes
423
+		 * this value when redirecting the user-agent back to the client.
424
+		 *
425
+		 * http://tools.ietf.org/html/rfc6749#section-4.1.1
426
+		 */
427
+		if ($this->supportRequestState
428
+			&& $this->getStoredData('authorization_state') != $state
429
+		) {
430
+			throw new InvalidAuthorizationStateException(
431
+				'The authorization state [state=' . substr(htmlentities($state), 0, 100) . '] '
432
+				. 'of this page is either invalid or has already been consumed.'
433
+			);
434
+		}
435
+
436
+		/**
437
+		 * Authorization Request Code
438
+		 *
439
+		 * RFC6749: If the resource owner grants the access request, the authorization
440
+		 * server issues an authorization code and delivers it to the client:
441
+		 *
442
+		 * http://tools.ietf.org/html/rfc6749#section-4.1.2
443
+		 */
444
+		$response = $this->exchangeCodeForAccessToken($code);
445
+
446
+		$this->validateAccessTokenExchange($response);
447
+
448
+		$this->initialize();
449
+	}
450
+
451
+	/**
452
+	 * Build Authorization URL for Authorization Request
453
+	 *
454
+	 * RFC6749: The client constructs the request URI by adding the following
455
+	 * $parameters to the query component of the authorization endpoint URI:
456
+	 *
457
+	 *    - response_type  REQUIRED. Value MUST be set to "code".
458
+	 *    - client_id      REQUIRED.
459
+	 *    - redirect_uri   OPTIONAL.
460
+	 *    - scope          OPTIONAL.
461
+	 *    - state          RECOMMENDED.
462
+	 *
463
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.1
464
+	 *
465
+	 * Sub classes may redefine this method when necessary.
466
+	 *
467
+	 * @param array $parameters
468
+	 *
469
+	 * @return string Authorization URL
470
+	 */
471
+	protected function getAuthorizeUrl($parameters = [])
472
+	{
473
+		$this->AuthorizeUrlParameters = !empty($parameters)
474
+			? $parameters
475
+			: array_replace(
476
+				(array)$this->AuthorizeUrlParameters,
477
+				(array)$this->config->get('authorize_url_parameters')
478
+			);
479
+
480
+		if ($this->supportRequestState) {
481
+			if (!isset($this->AuthorizeUrlParameters['state'])) {
482
+				$this->AuthorizeUrlParameters['state'] = 'HA-' . str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890');
483
+			}
484
+
485
+			$this->storeData('authorization_state', $this->AuthorizeUrlParameters['state']);
486
+		}
487
+
488
+		$queryParams = http_build_query($this->AuthorizeUrlParameters, '', '&', $this->AuthorizeUrlParametersEncType);
489
+		return $this->authorizeUrl . '?' . $queryParams;
490
+	}
491
+
492
+	/**
493
+	 * Access Token Request
494
+	 *
495
+	 * This method will exchange the received $code in loginFinish() with an Access Token.
496
+	 *
497
+	 * RFC6749: The client makes a request to the token endpoint by sending the
498
+	 * following parameters using the "application/x-www-form-urlencoded"
499
+	 * with a character encoding of UTF-8 in the HTTP request entity-body:
500
+	 *
501
+	 *    - grant_type    REQUIRED. Value MUST be set to "authorization_code".
502
+	 *    - code          REQUIRED. The authorization code received from the authorization server.
503
+	 *    - redirect_uri  REQUIRED.
504
+	 *    - client_id     REQUIRED.
505
+	 *
506
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.3
507
+	 *
508
+	 * @param string $code
509
+	 *
510
+	 * @return string Raw Provider API response
511
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
512
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
513
+	 */
514
+	protected function exchangeCodeForAccessToken($code)
515
+	{
516
+		$this->tokenExchangeParameters['code'] = $code;
517
+
518
+		$response = $this->httpClient->request(
519
+			$this->accessTokenUrl,
520
+			$this->tokenExchangeMethod,
521
+			$this->tokenExchangeParameters,
522
+			$this->tokenExchangeHeaders
523
+		);
524
+
525
+		$this->validateApiResponse('Unable to exchange code for API access token');
526
+
527
+		return $response;
528
+	}
529
+
530
+	/**
531
+	 * Validate Access Token Response
532
+	 *
533
+	 * RFC6749: If the access token request is valid and authorized, the
534
+	 * authorization server issues an access token and optional refresh token.
535
+	 * If the request client authentication failed or is invalid, the authorization
536
+	 * server returns an error response as described in Section 5.2.
537
+	 *
538
+	 * Example of a successful response:
539
+	 *
540
+	 *  HTTP/1.1 200 OK
541
+	 *  Content-Type: application/json;charset=UTF-8
542
+	 *  Cache-Control: no-store
543
+	 *  Pragma: no-cache
544
+	 *
545
+	 *  {
546
+	 *      "access_token":"2YotnFZFEjr1zCsicMWpAA",
547
+	 *      "token_type":"example",
548
+	 *      "expires_in":3600,
549
+	 *      "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
550
+	 *      "example_parameter":"example_value"
551
+	 *  }
552
+	 *
553
+	 * http://tools.ietf.org/html/rfc6749#section-4.1.4
554
+	 *
555
+	 * This method uses Data_Parser to attempt to decodes the raw $response (usually JSON)
556
+	 * into a data collection.
557
+	 *
558
+	 * @param string $response
559
+	 *
560
+	 * @return \Hybridauth\Data\Collection
561
+	 * @throws InvalidAccessTokenException
562
+	 */
563
+	protected function validateAccessTokenExchange($response)
564
+	{
565
+		$data = (new Data\Parser())->parse($response);
566
+
567
+		$collection = new Data\Collection($data);
568
+
569
+		if (!$collection->exists('access_token')) {
570
+			throw new InvalidAccessTokenException(
571
+				'Provider returned no access_token: ' . htmlentities($response)
572
+			);
573
+		}
574
+
575
+		$this->storeData('access_token', $collection->get('access_token'));
576
+		$this->storeData('token_type', $collection->get('token_type'));
577
+
578
+		if ($collection->get('refresh_token')) {
579
+			$this->storeData('refresh_token', $collection->get('refresh_token'));
580
+		}
581
+
582
+		// calculate when the access token expire
583
+		if ($collection->exists('expires_in')) {
584
+			$expires_at = time() + (int)$collection->get('expires_in');
585
+
586
+			$this->storeData('expires_in', $collection->get('expires_in'));
587
+			$this->storeData('expires_at', $expires_at);
588
+		}
589
+
590
+		$this->deleteStoredData('authorization_state');
591
+
592
+		$this->initialize();
593
+
594
+		return $collection;
595
+	}
596
+
597
+	/**
598
+	 * Refreshing an Access Token
599
+	 *
600
+	 * RFC6749: If the authorization server issued a refresh token to the
601
+	 * client, the client makes a refresh request to the token endpoint by
602
+	 * adding the following parameters ... in the HTTP request entity-body:
603
+	 *
604
+	 *    - grant_type     REQUIRED. Value MUST be set to "refresh_token".
605
+	 *    - refresh_token  REQUIRED. The refresh token issued to the client.
606
+	 *    - scope          OPTIONAL.
607
+	 *
608
+	 * http://tools.ietf.org/html/rfc6749#section-6
609
+	 *
610
+	 * This method is similar to exchangeCodeForAccessToken(). The only
611
+	 * difference is here we exchange refresh_token for a new access_token.
612
+	 *
613
+	 * @param array $parameters
614
+	 *
615
+	 * @return string|null Raw Provider API response, or null if we cannot refresh
616
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
617
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
618
+	 * @throws InvalidAccessTokenException
619
+	 */
620
+	public function refreshAccessToken($parameters = [])
621
+	{
622
+		$this->tokenRefreshParameters = !empty($parameters)
623
+			? $parameters
624
+			: $this->tokenRefreshParameters;
625
+
626
+		if (!$this->isRefreshTokenAvailable()) {
627
+			return null;
628
+		}
629
+
630
+		$response = $this->httpClient->request(
631
+			$this->accessTokenUrl,
632
+			$this->tokenRefreshMethod,
633
+			$this->tokenRefreshParameters,
634
+			$this->tokenRefreshHeaders
635
+		);
636
+
637
+		$this->validateApiResponse('Unable to refresh the access token');
638
+
639
+		$this->validateRefreshAccessToken($response);
640
+
641
+		return $response;
642
+	}
643
+
644
+	/**
645
+	 * Check whether access token has expired
646
+	 *
647
+	 * @param int|null $time
648
+	 * @return bool|null
649
+	 */
650
+	public function hasAccessTokenExpired($time = null)
651
+	{
652
+		if ($time === null) {
653
+			$time = time();
654
+		}
655
+
656
+		$expires_at = $this->getStoredData('expires_at');
657
+		if (!$expires_at) {
658
+			return null;
659
+		}
660
+
661
+		return $expires_at <= $time;
662
+	}
663
+
664
+	/**
665
+	 * Validate Refresh Access Token Request
666
+	 *
667
+	 * RFC6749: If valid and authorized, the authorization server issues an
668
+	 * access token as described in Section 5.1.  If the request failed
669
+	 * verification or is invalid, the authorization server returns an error
670
+	 * response as described in Section 5.2.
671
+	 *
672
+	 * http://tools.ietf.org/html/rfc6749#section-6
673
+	 * http://tools.ietf.org/html/rfc6749#section-5.1
674
+	 * http://tools.ietf.org/html/rfc6749#section-5.2
675
+	 *
676
+	 * This method simply use validateAccessTokenExchange(), however sub
677
+	 * classes may redefine it when necessary.
678
+	 *
679
+	 * @param $response
680
+	 *
681
+	 * @return \Hybridauth\Data\Collection
682
+	 * @throws InvalidAccessTokenException
683
+	 */
684
+	protected function validateRefreshAccessToken($response)
685
+	{
686
+		return $this->validateAccessTokenExchange($response);
687
+	}
688
+
689
+	/**
690
+	 * Send a signed request to provider API
691
+	 *
692
+	 * RFC6749: Accessing Protected Resources: The client accesses protected
693
+	 * resources by presenting the access token to the resource server. The
694
+	 * resource server MUST validate the access token and ensure that it has
695
+	 * not expired and that its scope covers the requested resource.
696
+	 *
697
+	 * Note: Since the specifics of error responses is beyond the scope of
698
+	 * RFC6749 and OAuth specifications, Hybridauth will consider any HTTP
699
+	 * status code that is different than '200 OK' as an ERROR.
700
+	 *
701
+	 * http://tools.ietf.org/html/rfc6749#section-7
702
+	 *
703
+	 * @param string $url
704
+	 * @param string $method
705
+	 * @param array $parameters
706
+	 * @param array $headers
707
+	 * @param bool $multipart
708
+	 *
709
+	 * @return mixed
710
+	 * @throws \Hybridauth\Exception\HttpClientFailureException
711
+	 * @throws \Hybridauth\Exception\HttpRequestFailedException
712
+	 * @throws InvalidAccessTokenException
713
+	 */
714
+	public function apiRequest($url, $method = 'GET', $parameters = [], $headers = [], $multipart = false)
715
+	{
716
+		// refresh tokens if needed
717
+		$this->maintainToken();
718
+		if ($this->hasAccessTokenExpired() === true) {
719
+			$this->refreshAccessToken();
720
+		}
721
+
722
+		if (strrpos($url, 'http://') !== 0 && strrpos($url, 'https://') !== 0) {
723
+			$url = rtrim($this->apiBaseUrl, '/') . '/' . ltrim($url, '/');
724
+		}
725
+
726
+		$parameters = array_replace($this->apiRequestParameters, (array)$parameters);
727
+		$headers = array_replace($this->apiRequestHeaders, (array)$headers);
728
+
729
+		$response = $this->httpClient->request(
730
+			$url,
731
+			$method,     // HTTP Request Method. Defaults to GET.
732
+			$parameters, // Request Parameters
733
+			$headers,    // Request Headers
734
+			$multipart   // Is request multipart
735
+		);
736
+
737
+		$this->validateApiResponse('Signed API request to ' . $url . ' has returned an error');
738
+
739
+		$response = (new Data\Parser())->parse($response);
740
+
741
+		return $response;
742
+	}
743 743
 }
Please login to merge, or discard this patch.
src/Adapter/DataStoreTrait.php 2 patches
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -12,63 +12,63 @@
 block discarded – undo
12 12
  */
13 13
 trait DataStoreTrait
14 14
 {
15
-    /**
16
-     * Returns storage instance
17
-     *
18
-     * @return \Hybridauth\Storage\StorageInterface
19
-     */
20
-    abstract public function getStorage();
15
+	/**
16
+	 * Returns storage instance
17
+	 *
18
+	 * @return \Hybridauth\Storage\StorageInterface
19
+	 */
20
+	abstract public function getStorage();
21 21
 
22
-    /**
23
-     * Store a piece of data in storage.
24
-     *
25
-     * This method is mainly used for OAuth tokens (access, secret, refresh, and whatnot), but it
26
-     * can be also used by providers to store any other useful data (i.g., user_id, auth_nonce, etc.)
27
-     *
28
-     * @param string $name
29
-     * @param mixed $value
30
-     */
31
-    protected function storeData($name, $value = null)
32
-    {
33
-        // if empty, we simply delete the thing as we'd want to only store necessary data
34
-        if (empty($value)) {
35
-            $this->deleteStoredData($name);
36
-        }
22
+	/**
23
+	 * Store a piece of data in storage.
24
+	 *
25
+	 * This method is mainly used for OAuth tokens (access, secret, refresh, and whatnot), but it
26
+	 * can be also used by providers to store any other useful data (i.g., user_id, auth_nonce, etc.)
27
+	 *
28
+	 * @param string $name
29
+	 * @param mixed $value
30
+	 */
31
+	protected function storeData($name, $value = null)
32
+	{
33
+		// if empty, we simply delete the thing as we'd want to only store necessary data
34
+		if (empty($value)) {
35
+			$this->deleteStoredData($name);
36
+		}
37 37
 
38
-        $this->getStorage()->set($this->providerId . '.' . $name, $value);
39
-    }
38
+		$this->getStorage()->set($this->providerId . '.' . $name, $value);
39
+	}
40 40
 
41
-    /**
42
-     * Retrieve a piece of data from storage.
43
-     *
44
-     * This method is mainly used for OAuth tokens (access, secret, refresh, and whatnot), but it
45
-     * can be also used by providers to retrieve from store any other useful data (i.g., user_id,
46
-     * auth_nonce, etc.)
47
-     *
48
-     * @param string $name
49
-     *
50
-     * @return mixed
51
-     */
52
-    protected function getStoredData($name)
53
-    {
54
-        return $this->getStorage()->get($this->providerId . '.' . $name);
55
-    }
41
+	/**
42
+	 * Retrieve a piece of data from storage.
43
+	 *
44
+	 * This method is mainly used for OAuth tokens (access, secret, refresh, and whatnot), but it
45
+	 * can be also used by providers to retrieve from store any other useful data (i.g., user_id,
46
+	 * auth_nonce, etc.)
47
+	 *
48
+	 * @param string $name
49
+	 *
50
+	 * @return mixed
51
+	 */
52
+	protected function getStoredData($name)
53
+	{
54
+		return $this->getStorage()->get($this->providerId . '.' . $name);
55
+	}
56 56
 
57
-    /**
58
-     * Delete a stored piece of data.
59
-     *
60
-     * @param string $name
61
-     */
62
-    protected function deleteStoredData($name)
63
-    {
64
-        $this->getStorage()->delete($this->providerId . '.' . $name);
65
-    }
57
+	/**
58
+	 * Delete a stored piece of data.
59
+	 *
60
+	 * @param string $name
61
+	 */
62
+	protected function deleteStoredData($name)
63
+	{
64
+		$this->getStorage()->delete($this->providerId . '.' . $name);
65
+	}
66 66
 
67
-    /**
68
-     * Delete all stored data of the instantiated adapter
69
-     */
70
-    protected function clearStoredData()
71
-    {
72
-        $this->getStorage()->deleteMatch($this->providerId . '.');
73
-    }
67
+	/**
68
+	 * Delete all stored data of the instantiated adapter
69
+	 */
70
+	protected function clearStoredData()
71
+	{
72
+		$this->getStorage()->deleteMatch($this->providerId . '.');
73
+	}
74 74
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -35,7 +35,7 @@  discard block
 block discarded – undo
35 35
             $this->deleteStoredData($name);
36 36
         }
37 37
 
38
-        $this->getStorage()->set($this->providerId . '.' . $name, $value);
38
+        $this->getStorage()->set($this->providerId.'.'.$name, $value);
39 39
     }
40 40
 
41 41
     /**
@@ -51,7 +51,7 @@  discard block
 block discarded – undo
51 51
      */
52 52
     protected function getStoredData($name)
53 53
     {
54
-        return $this->getStorage()->get($this->providerId . '.' . $name);
54
+        return $this->getStorage()->get($this->providerId.'.'.$name);
55 55
     }
56 56
 
57 57
     /**
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
      */
62 62
     protected function deleteStoredData($name)
63 63
     {
64
-        $this->getStorage()->delete($this->providerId . '.' . $name);
64
+        $this->getStorage()->delete($this->providerId.'.'.$name);
65 65
     }
66 66
 
67 67
     /**
@@ -69,6 +69,6 @@  discard block
 block discarded – undo
69 69
      */
70 70
     protected function clearStoredData()
71 71
     {
72
-        $this->getStorage()->deleteMatch($this->providerId . '.');
72
+        $this->getStorage()->deleteMatch($this->providerId.'.');
73 73
     }
74 74
 }
Please login to merge, or discard this patch.