Completed
Push — master ( 3888fe...7b95f2 )
by Carlos
02:54
created

src/Providers/Alipay.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Overtrue\Socialite\Providers;
4
5
use Overtrue\Socialite\Exceptions\InvalidArgumentException;
6
use Overtrue\Socialite\User;
7
8
/**
9
 * @see https://opendocs.alipay.com/open/289/105656
10
 */
11
class Alipay extends Base
12
{
13
    public const NAME = 'alipay';
14
    protected string $baseUrl = 'https://openapi.alipay.com/gateway.do';
0 ignored issues
show
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected T_STRING, expecting T_FUNCTION or T_CONST
Loading history...
15
    protected array $scopes = ['auth_user'];
16
    protected string $apiVersion = '1.0';
17
    protected string $signType = 'RSA2';
18
    protected string $postCharset = 'UTF-8';
19
    protected string $format = 'json';
20
21
    protected function getAuthUrl(): string
22
    {
23
        return $this->buildAuthUrlFromBase('https://openauth.alipay.com/oauth2/publicAppAuthorize.htm');
24
    }
25
26
    protected function getTokenUrl(): string
27
    {
28
        return $this->baseUrl;
29
    }
30
31
    /**
32
     * @param string $token
33
     *
34
     * @return array
35
     * @throws \Overtrue\Socialite\Exceptions\InvalidArgumentException
36
     */
37
    protected function getUserByToken(string $token): array
38
    {
39
        $params = $this->getPublicFields('alipay.user.info.share');
40
        $params += ['auth_token' => $token];
41
        $params['sign'] = $this->generateSign($params);
42
43
        $response = $this->getHttpClient()->post(
44
            $this->baseUrl,
45
            [
46
                'form_params' => $params,
47
                'headers' => [
48
                    "content-type" => "application/x-www-form-urlencoded;charset=utf-8",
49
                ],
50
            ]
51
        );
52
53
        $response = json_decode($response->getBody()->getContents(), true);
54
55
        if (!empty($response['error_response']) || empty($response['alipay_user_info_share_response'])) {
56
            throw new \InvalidArgumentException('You have error! ' . \json_encode($response, JSON_UNESCAPED_UNICODE));
57
        }
58
59
        return $response['alipay_user_info_share_response'];
60
    }
61
62
    /**
63
     * @param array $user
64
     *
65
     * @return \Overtrue\Socialite\User
66
     */
67
    protected function mapUserToObject(array $user): User
68
    {
69
        return new User(
70
            [
71
                'id' => $user['user_id'] ?? null,
72
                'name' => $user['nick_name'] ?? null,
73
                'avatar' => $user['avatar'] ?? null,
74
                'email' => $user['email'] ?? null,
75
            ]
76
        );
77
    }
78
79
    /**
80
     * @param string $code
81
     *
82
     * @return array
83
     * @throws \Overtrue\Socialite\Exceptions\AuthorizeFailedException
84
     */
85
    public function tokenFromCode(string $code): array
86
    {
87
        $response = $this->getHttpClient()->post(
88
            $this->getTokenUrl(),
89
            [
90
                'form_params' => $this->getTokenFields($code),
91
                'headers' => [
92
                    "content-type" => "application/x-www-form-urlencoded;charset=utf-8",
93
                ],
94
            ]
95
        );
96
        $response = json_decode($response->getBody()->getContents(), true);
97
98
        if (!empty($response['error_response'])) {
99
            throw new \InvalidArgumentException('You have error! ' . json_encode($response, JSON_UNESCAPED_UNICODE));
100
        }
101
102
        return $this->normalizeAccessTokenResponse($response['alipay_system_oauth_token_response']);
103
    }
104
105
    protected function getCodeFields(): array
106
    {
107
        if (empty($this->redirectUrl)) {
108
            throw new InvalidArgumentException('Please set same redirect URL like your Alipay Official Admin');
109
        }
110
111
        $fields = array_merge(
112
            [
113
                'app_id' => $this->getConfig()->get('client_id') ?? $this->getConfig()->get('app_id'),
114
                'scope' => implode(',', $this->scopes),
115
                'redirect_uri' => $this->redirectUrl,
116
            ],
117
            $this->parameters
118
        );
119
120
        return $fields;
121
    }
122
123
    /**
124
     * @param string $code
125
     *
126
     * @return array|string[]
127
     * @throws \Overtrue\Socialite\Exceptions\InvalidArgumentException
128
     */
129
    protected function getTokenFields(string $code): array
130
    {
131
        $params = $this->getPublicFields('alipay.system.oauth.token');
132
        $params += [
133
            'code' => $code,
134
            'grant_type' => 'authorization_code',
135
        ];
136
        $params['sign'] = $this->generateSign($params);
137
138
        return $params;
139
    }
140
141
    /**
142
     * @param string $method
143
     *
144
     * @return array
145
     */
146
    public function getPublicFields(string $method): array
147
    {
148
        return [
149
            'app_id' => $this->getConfig()->get('client_id') ?? $this->getConfig()->get('app_id'),
150
            'format' => $this->format,
151
            'charset' => $this->postCharset,
152
            'sign_type' => $this->signType,
153
            'method' => $method,
154
            'timestamp' => date('Y-m-d H:m:s'),
155
            'version' => $this->apiVersion,
156
        ];
157
    }
158
159
    /**
160
     * @param $params
161
     *
162
     * @return string
163
     * @throws InvalidArgumentException
164
     *
165
     * @see https://opendocs.alipay.com/open/289/105656
166
     */
167
    protected function generateSign($params)
168
    {
169
        ksort($params);
170
171
        $signContent = $this->buildParams($params);
172
        $key = $this->getConfig()->get('rsa_private_key');
173
        $signValue = $this->signWithSHA256RSA($signContent, $key);
174
175
        return $signValue;
176
    }
177
178
    /**
179
     * @param string $signContent
180
     * @param string $key
181
     *
182
     * @return string
183
     * @throws \Overtrue\Socialite\Exceptions\InvalidArgumentException
184
     */
185
    protected function signWithSHA256RSA(string $signContent, string $key)
186
    {
187
        if (empty($key)) {
188
            throw new InvalidArgumentException('no RSA private key set.');
189
        }
190
191
        $key = "-----BEGIN RSA PRIVATE KEY-----\n" .
192
            chunk_split($key, 64, "\n") .
193
            "-----END RSA PRIVATE KEY-----";
194
195
        openssl_sign($signContent, $signValue, $key, OPENSSL_ALGO_SHA256);
196
197
        return base64_encode($signValue);
198
    }
199
200
    /**
201
     * @param array          $params
202
     * @param bool           $urlencode
203
     * @param array|string[] $except
204
     *
205
     * @return string
206
     */
207
    public static function buildParams(array $params, bool $urlencode = false, array $except = ['sign'])
208
    {
209
        $param_str = '';
210
        foreach ($params as $k => $v) {
211
            if (in_array($k, $except)) {
212
                continue;
213
            }
214
            $param_str .= $k . '=';
215
            $param_str .= $urlencode ? rawurlencode($v) : $v;
216
            $param_str .= '&';
217
        }
218
219
        return rtrim($param_str, '&');
220
    }
221
}
222