Completed
Pull Request — master (#50)
by
unknown
04:31
created

WeChatProvider::setComponentToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
/*
4
 * This file is part of the overtrue/socialite.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Overtrue\Socialite\Providers;
13
14
use Overtrue\Socialite\AccessToken;
15
use Overtrue\Socialite\AccessTokenInterface;
16
use Overtrue\Socialite\InvalidArgumentException;
17
use Overtrue\Socialite\ProviderInterface;
18
use Overtrue\Socialite\User;
19
20
/**
21
 * Class WeChatProvider.
22
 *
23
 * @link http://mp.weixin.qq.com/wiki/9/01f711493b5a02f24b04365ac5d8fd95.html [WeChat - 公众平台OAuth文档]
24
 * @link https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316505&token=&lang=zh_CN [网站应用微信登录开发指南]
25
 */
26
class WeChatProvider extends AbstractProvider implements ProviderInterface
27
{
28
    /**
29
     * The base url of WeChat API.
30
     *
31
     * @var string
32
     */
33
    protected $baseUrl = 'https://api.weixin.qq.com/sns';
34
35
    /**
36
     * {@inheritdoc}.
37
     */
38
    protected $openId;
39
40
    /**
41
     * {@inheritdoc}.
42
     */
43
    protected $scopes = ['snsapi_login'];
44
45
    /**
46
     * Indicates if the session state should be utilized.
47
     *
48
     * @var bool
49
     */
50
    protected $stateless = true;
51
52
    /**
53
     * Return country code instead of country name.
54
     *
55
     * @var bool
56
     */
57
    protected $withCountryCode = false;
58
59
    /**
60
     * Return country code instead of country name.
61
     *
62
     * @return $this
63
     */
64
    public function withCountryCode()
65
    {
66
        $this->withCountryCode = true;
67
68
        return $this;
69
    }
70
71
    /**
72
     * {@inheritdoc}.
73
     */
74
    public function getAccessToken($code)
75
    {
76
        $response = $this->getHttpClient()->get($this->getTokenUrl(), [
77
            'headers' => ['Accept' => 'application/json'],
78
            'query' => $this->getTokenFields($code),
79
        ]);
80
81
        return $this->parseAccessToken($response->getBody());
82
    }
83
84
    /**
85
     * {@inheritdoc}.
86
     */
87
    protected function getAuthUrl($state)
88
    {
89
        $path = 'oauth2/authorize';
90
91
        if (in_array('snsapi_login', $this->scopes)) {
92
            $path = 'qrconnect';
93
        }
94
95
        return $this->buildAuthUrlFromBase("https://open.weixin.qq.com/connect/{$path}", $state);
96
    }
97
98
    /**
99
     * {@inheritdoc}.
100
     */
101
    protected function buildAuthUrlFromBase($url, $state)
102
    {
103
        $query = http_build_query($this->getCodeFields($state), '', '&', $this->encodingType);
104
105
        return $url.'?'.$query.'#wechat_redirect';
106
    }
107
108
    /**
109
     * {@inheritdoc}.
110
     */
111
    protected function getCodeFields($state = null)
112
    {
113
        if ($this->isOpenPlatform()) {
0 ignored issues
show
Bug introduced by
The method isOpenPlatform() does not seem to exist on object<Overtrue\Socialit...oviders\WeChatProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
114
            $this->with(['component_appid' => $this->config->get('wechat.open_platform.app_id')]);
0 ignored issues
show
Bug introduced by
The property config does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
115
        }
116
        return array_merge([
117
            'appid' => $this->clientId,
118
            'redirect_uri' => $this->redirectUrl,
119
            'response_type' => 'code',
120
            'scope' => $this->formatScopes($this->scopes, $this->scopeSeparator),
121
            'state' => $state ?: md5(time()),
122
        ], $this->parameters);
123
    }
124
125
    /**
126
     * {@inheritdoc}.
127
     */
128
    protected function getTokenUrl()
129
    {
130
        return $this->baseUrl.'/oauth2/access_token';
131
    }
132
133
    /**
134
     * {@inheritdoc}.
135
     */
136
    protected function getUserByToken(AccessTokenInterface $token)
137
    {
138
        $scopes = explode(',', $token->getAttribute('scope', ''));
139
140
        if (in_array('snsapi_base', $scopes)) {
141
            return $token->toArray();
142
        }
143
144
        if (empty($token['openid'])) {
145
            throw new InvalidArgumentException('openid of AccessToken is required.');
146
        }
147
148
        $language = $this->withCountryCode ? null : (isset($this->parameters['lang']) ? $this->parameters['lang'] : 'zh_CN');
149
150
        $response = $this->getHttpClient()->get($this->baseUrl.'/userinfo', [
151
            'query' => array_filter([
152
                'access_token' => $token->getToken(),
153
                'openid' => $token['openid'],
154
                'lang' => $language,
155
            ]),
156
        ]);
157
158
        return json_decode($response->getBody(), true);
159
    }
160
161
    /**
162
     * {@inheritdoc}.
163
     */
164
    protected function mapUserToObject(array $user)
165
    {
166
        return new User([
167
            'id' => $this->arrayItem($user, 'openid'),
168
            'name' => $this->arrayItem($user, 'nickname'),
169
            'nickname' => $this->arrayItem($user, 'nickname'),
170
            'avatar' => $this->arrayItem($user, 'headimgurl'),
171
            'email' => null,
172
        ]);
173
    }
174
175
    /**
176
     * {@inheritdoc}.
177
     */
178
    protected function getTokenFields($code)
179
    {
180
        return [
181
            'appid' => $this->clientId,
182
            'secret' => $this->clientSecret,
183
            'code' => $code,
184
            'grant_type' => 'authorization_code',
185
        ];
186
    }
187
188
    /**
189
     * Remove the fucking callback parentheses.
190
     *
191
     * @param mixed $response
192
     *
193
     * @return string
194
     */
195 View Code Duplication
    protected function removeCallback($response)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
    {
197
        if (strpos($response, 'callback') !== false) {
198
            $lpos = strpos($response, '(');
199
            $rpos = strrpos($response, ')');
200
            $response = substr($response, $lpos + 1, $rpos - $lpos - 1);
201
        }
202
203
        return $response;
204
    }
205
    
206
    /**
207
     * Set app id
208
     * @param $authorizer_app_id
209
     * @return $this
210
     */
211
    public function setAuthorizerAppId($authorizer_app_id)
212
    {
213
        $this->clientId = $authorizer_app_id;
214
        return $this;
215
    }
216
217
    /**
218
     * set platform component access token
219
     * @param $token
220
     * @return $this
221
     */
222
    public function setComponentToken($token)
223
    {
224
        $wechat= $this->config->get('wechat');
225
        $wechat['open_platform']['access_token'] = $token;
226
        $this->config->set('wechat', $wechat);
227
        return $this;
228
    }
229
}
230