• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ringcentral / ringcentral-php / 10243692747

05 Aug 2024 06:22AM UTC coverage: 77.389% (-13.4%) from 90.761%
10243692747

push

github

web-flow
Merge pull request #137 from ringcentral/vendorPatch

Remove PubNub SubscriptionTest

575 of 743 relevant lines covered (77.39%)

7.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.28
/src/Platform/Platform.php
1
<?php
2

3
namespace RingCentral\SDK\Platform;
4

5
use Exception;
6
use GuzzleHttp\Psr7\Uri;
7
use Psr\Http\Message\RequestInterface;
8
use RingCentral\SDK\Http\ApiException;
9
use RingCentral\SDK\Http\ApiResponse;
10
use RingCentral\SDK\Http\Client;
11
use RingCentral\SDK\SDK;
12

13
class Platform
14
{
15
    const ACCESS_TOKEN_TTL = 3600; // 60 minutes
16
    const REFRESH_TOKEN_TTL = 604800; // 1 week
17
    const TOKEN_ENDPOINT = '/restapi/oauth/token';
18
    const REVOKE_ENDPOINT = '/restapi/oauth/revoke';
19
    const AUTHORIZE_ENDPOINT = '/restapi/oauth/authorize';
20
    const API_VERSION = 'v1.0';
21
    const URL_PREFIX = '/restapi';
22
    const KNOWN_PREFIXES = array(
23
        self::URL_PREFIX,
24
        '/rcvideo',
25
        '/video',
26
        '/webinar',
27
        '/team-messaging',
28
        '/analytics',
29
        '/ai',
30
        '/scim',
31
        '/cx'
32
    );
33

34
    /** @var string */
35
    protected $_server;
36

37
    /** @var string */
38
    protected $_clientId;
39

40
    /** @var string */
41
    protected $_clientSecret;
42

43
    /** @var string */
44
    protected $_appName;
45

46
    /** @var string */
47
    protected $_appVersion;
48

49
    /** @var string */
50
    protected $_userAgent;
51

52
    /** @var Auth */
53
    protected $_auth;
54

55
    /** @var Client */
56
    protected $_client;
57

58
    /**
59
     * Platform constructor.
60
     * @param Client $client
61
     * @param string $clientId
62
     * @param string $clientSecret
63
     * @param string $server
64
     * @param string $appName
65
     * @param string $appVersion
66
     */
67
    public function __construct(Client $client, $clientId, $clientSecret, $server, $appName = '', $appVersion = '')
68
    {
69

70
        $this->_clientId = $clientId;
25✔
71
        $this->_clientSecret = $clientSecret;
25✔
72
        $this->_appName = empty($appName) ? 'Unnamed' : $appName;
25✔
73
        $this->_appVersion = empty($appVersion) ? '0.0.0' : $appVersion;
25✔
74

75
        $this->_server = $server;
25✔
76

77
        $this->_auth = new Auth();
25✔
78
        $this->_client = $client;
25✔
79

80
        $this->_userAgent = (!empty($this->_appName) ? ($this->_appName . (!empty($this->_appVersion) ? '/' . $this->_appVersion : '') . ' ') : '') .
25✔
81
            php_uname('s') . '/' . php_uname('r') . ' ' .
25✔
82
            'PHP/' . phpversion() . ' ' .
25✔
83
            'RCPHPSDK/' . SDK::VERSION;
25✔
84

85
    }
86

87
    /**
88
     * @return Auth
89
     */
90
    public function auth()
91
    {
92
        return $this->_auth;
5✔
93
    }
94

95
    /**
96
     * @param string $path
97
     * @param array  $options
98
     * @return string
99
     */
100
    public function createUrl($path = '', $options = [])
101
    {
102

103
        $builtUrl = '';
24✔
104
        $hasHttp = stristr($path, 'http://') || stristr($path, 'https://');
24✔
105

106
        if (!empty($options['addServer']) && $options['addServer'] == TRUE && !$hasHttp) {
24✔
107
            $builtUrl .= $this->_server;
24✔
108
        }
109

110
        if (
111
            !array_reduce(
24✔
112
                self::KNOWN_PREFIXES,
24✔
113
                function ($result, $key) use ($path) {
24✔
114
                    if ($result) {
24✔
115
                        return $result;
23✔
116
                    } else {
117
                        return str_starts_with($path, $key);
24✔
118
                    }
119
                },
24✔
120
                FALSE
24✔
121
            ) && !$hasHttp
24✔
122
        ) {
123
            $builtUrl .= self::URL_PREFIX . '/' . self::API_VERSION;
4✔
124
        }
125

126
        $builtUrl .= $path;
24✔
127

128
        if (!empty($options['addMethod']) || !empty($options['addToken'])) {
24✔
129
            $builtUrl .= (stristr($path, '?') ? '&' : '?');
1✔
130
        }
131

132
        if (!empty($options['addMethod'])) {
24✔
133
            $builtUrl .= '_method=' . $options['addMethod'];
1✔
134
        }
135
        if (!empty($options['addToken'])) {
24✔
136
            $builtUrl .= ($options['addMethod'] ? '&' : '') . 'access_token=' . $this->_auth->accessToken();
1✔
137
        }
138

139
        return $builtUrl;
24✔
140

141
    }
142

143
    /**
144
     * This function has mixed purposes. On the face of it, it can used to return a boolean value which represents
145
     * whether or not the platform has been configured with valid authentication tokens.
146
     * However, it also does much more than that. If the access token is expired BUT the refresh token is valid, then
147
     * this function takes it upon itself to use that refresh token to automatically request brand new tokens, which it
148
     * then sets and uses.
149
     * @return bool True if the access token is value OR it is able to request new tokens successfully, otherwise false
150
     */
151
    public function loggedIn()
152
    {
153
        try {
154
            return $this->_auth->accessTokenValid() || $this->refresh();
1✔
155
        } catch (Exception $e) {
×
156
            return false;
×
157
        }
158
    }
159

160
    /**
161
     * Create and return a URL that can be used for authenticating/logging in to RingCentral.
162
     * @param array $options     An array containing information that will be added to the generated URL.
163
     *                           $options = [
164
     *                           'redirectUri' => (string) The callback URI to use once authentication is complete.
165
     *                           'state'       => (string)
166
     *                           'brandId'     => (string)
167
     *                           'display'     => (string)
168
     *                           'prompt'      => (string)
169
     *                           'code_challenge'         => (string) Used to facilitate PKCE auth flows
170
     *                           'code_challenge_method'  => (string) Used to facilitate PKCE auth flows
171
     *                           ]
172
     * @return string
173
     */
174
    public function authUrl($options)
175
    {
176
        return $this->createUrl(self::AUTHORIZE_ENDPOINT . '?' . http_build_query(
1✔
177
            [
1✔
178
                'response_type' => 'code',
1✔
179
                'redirect_uri' => $options['redirectUri'] ? $options['redirectUri'] : null,
1✔
180
                'client_id' => $this->_clientId,
1✔
181
                'state' => array_key_exists('state', $options) ? $options['state'] : null,
1✔
182
                'brand_id' => array_key_exists('brandId', $options) ? $options['brandId'] : null,
1✔
183
                'display' => array_key_exists('display', $options) ? $options['display'] : null,
1✔
184
                'prompt' => array_key_exists('prompt', $options) ? $options['prompt'] : null,
1✔
185
                'code_challenge' => array_key_exists('code_challenge', $options) ? $options['code_challenge'] : null,
1✔
186
                'code_challenge_method' => array_key_exists('code_challenge_method', $options) ? $options['code_challenge_method'] : null
1✔
187
            ]
1✔
188
        ), [
1✔
189
            'addServer' => 'true'
1✔
190
        ]);
1✔
191
    }
192

193
    /**
194
     * @param string $url
195
     * @return array
196
     */
197
    public function parseAuthRedirectUrl($url)
198
    {
199

200
        parse_str($url, $qsArray);
×
201
        return [
×
202
            'code' => $qsArray['code']
×
203
        ];
×
204
    }
205

206
    /**
207
     * @param string $username
208
     * @param string $extension
209
     * @param string $password
210
     * @return ApiResponse
211
     * @throws Exception    If it fails to retrieve/parse JSON data from he response.
212
     * @throws ApiException If there is an issue with the token request.
213
     */
214
    public function login($options)
215
    {
216
        if (is_string($options)) {
23✔
217
            $options = [
1✔
218
                'username' => func_get_arg(0),
1✔
219
                'extension' => func_get_arg(1) ? func_get_arg(1) : null,
1✔
220
                'password' => func_get_arg(2)
1✔
221
            ];
1✔
222
        }
223

224
        $response = !empty($options['code']) ? $this->requestToken(
23✔
225
            self::TOKEN_ENDPOINT,
23✔
226
            [
23✔
227

228
                'grant_type' => 'authorization_code',
23✔
229
                'code' => $options['code'],
23✔
230
                'redirect_uri' => $options['redirectUri'],
23✔
231
                'access_token_ttl' => self::ACCESS_TOKEN_TTL,
23✔
232
                'refresh_token_ttl' => self::REFRESH_TOKEN_TTL
23✔
233

234
            ] + (!empty($options['codeVerifier']) ? ['code_verifier' => $options['codeVerifier']] : [])
23✔
235

236
        ) : (!empty($options['jwt']) ? $this->requestToken(self::TOKEN_ENDPOINT, [
23✔
237

238
                'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
23✔
239
                'assertion' => $options['jwt'],
23✔
240
                'access_token_ttl' => self::ACCESS_TOKEN_TTL,
23✔
241
                'refresh_token_ttl' => self::REFRESH_TOKEN_TTL
23✔
242

243
            ]) : $this->requestToken(self::TOKEN_ENDPOINT, [
23✔
244

245
                        'grant_type' => 'password',
23✔
246
                        'username' => $options['username'],
23✔
247
                        'extension' => $options['extension'] ? $options['extension'] : null,
23✔
248
                        'password' => $options["password"],
23✔
249
                        'access_token_ttl' => self::ACCESS_TOKEN_TTL,
23✔
250
                        'refresh_token_ttl' => self::REFRESH_TOKEN_TTL
23✔
251

252
                    ]));
23✔
253

254
        $this->_auth->setData($response->jsonArray());
23✔
255

256
        return $response;
23✔
257

258
    }
259

260
    /**
261
     * Attempt to request new access and refresh tokens using the existing refresh token.
262
     * @return ApiResponse
263
     * @throws Exception    If it fails to retrieve/parse JSON data from he response.
264
     * @throws ApiException If the existing refresh token is invalid or there is an issue with the request.
265
     */
266
    public function refresh()
267
    {
268

269
        if (!$this->_auth->refreshTokenValid()) {
2✔
270
            throw new ApiException(null, new Exception('Refresh token has expired'));
1✔
271
        }
272

273
        // Synchronous
274
        $response = $this->requestToken(self::TOKEN_ENDPOINT, [
1✔
275
            "grant_type" => "refresh_token",
1✔
276
            "refresh_token" => $this->_auth->refreshToken(),
1✔
277
            "access_token_ttl" => self::ACCESS_TOKEN_TTL,
1✔
278
            "refresh_token_ttl" => self::REFRESH_TOKEN_TTL
1✔
279
        ]);
1✔
280

281
        $this->_auth->setData($response->jsonArray());
1✔
282

283
        return $response;
1✔
284

285
    }
286

287
    /**
288
     * @return ApiResponse
289
     * @throws Exception    If an error occurs parsing the response from the request.
290
     * @throws ApiException If an error occurs making the request.
291
     */
292
    public function logout()
293
    {
294

295
        $response = $this->requestToken(self::REVOKE_ENDPOINT, [
1✔
296
            'token' => $this->_auth->accessToken()
1✔
297
        ]);
1✔
298

299
        $this->_auth->reset();
1✔
300

301
        return $response;
1✔
302

303
    }
304

305
    /**
306
     * Convenience helper used for processing requests (even externally created).
307
     * Performs access token refresh if needed.
308
     * Then adds Authorization header and API server to URI
309
     * @param RequestInterface $request
310
     * @param array            $options
311
     * @return RequestInterface
312
     * @throws Exception    If an error occurs parsing the response from the refresh request.
313
     * @throws ApiException If an error occurs making the refresh request.
314
     */
315
    public function inflateRequest(RequestInterface $request, $options = [])
316
    {
317

318
        if (empty($options['skipAuthCheck'])) {
24✔
319

320
            $this->ensureAuthentication();
12✔
321

322
            /** @var RequestInterface $request */
323
            $request = $request->withHeader('Authorization', $this->authHeader());
12✔
324

325
        }
326

327
        /** @var RequestInterface $request */
328
        $request = $request->withAddedHeader('User-Agent', $this->_userAgent)
24✔
329
            ->withAddedHeader('RC-User-Agent', $this->_userAgent);
24✔
330

331
        $uri = new Uri($this->createUrl((string) $request->getUri(), ['addServer' => true]));
24✔
332

333
        return $request->withUri($uri);
24✔
334

335
    }
336

337
    /**
338
     * Method sends the request (even externally created) to API server using client
339
     * @param RequestInterface $request
340
     * @param array            $options
341
     * @return ApiResponse
342
     * @throws Exception    If an error occurs parsing the response from the refresh request as part of inflateRequest()
343
     * @throws ApiException If an error occurs making the refresh request as part of inflateRequest()
344
     */
345
    public function sendRequest(RequestInterface $request, $options = [])
346
    {
347

348
        return $this->_client->send($this->inflateRequest($request, $options));
24✔
349

350
    }
351

352
    /**
353
     * @param string $url
354
     * @param array  $queryParameters
355
     * @param array  $headers
356
     * @param array  $options
357
     * @return ApiResponse
358
     * @throws Exception    If an error occurs parsing the response from the request.
359
     * @throws ApiException If an error occurs making the request.
360
     */
361
    public function get($url = '', $queryParameters = [], array $headers = [], $options = [])
362
    {
363
        return $this->sendRequest(
2✔
364
            $this->_client->createRequest('GET', $url, $queryParameters, null, $headers),
2✔
365
            $options
2✔
366
        );
2✔
367
    }
368

369
    /**
370
     * @param string $url
371
     * @param array  $body
372
     * @param array  $queryParameters
373
     * @param array  $headers
374
     * @param array  $options
375
     * @return ApiResponse
376
     * @throws Exception    If an error occurs parsing the response from the request.
377
     * @throws ApiException If an error occurs making the request.
378
     */
379
    public function post(
380
        $url = '',
381
        $body = null,
382
        $queryParameters = [],
383
        array $headers = [],
384
        $options = []
385
    ) {
386
        return $this->sendRequest(
6✔
387
            $this->_client->createRequest('POST', $url, $queryParameters, $body, $headers),
6✔
388
            $options
6✔
389
        );
6✔
390
    }
391

392
    /**
393
     * @param string $url
394
     * @param array  $body
395
     * @param array  $queryParameters
396
     * @param array  $headers
397
     * @param array  $options
398
     * @return ApiResponse
399
     * @throws Exception    If an error occurs parsing the response from the request.
400
     * @throws ApiException If an error occurs making the request.
401
     */
402
    public function patch(
403
        $url = '',
404
        $body = null,
405
        $queryParameters = [],
406
        array $headers = [],
407
        $options = []
408
    ) {
409
        return $this->sendRequest(
×
410
            $this->_client->createRequest('PATCH', $url, $queryParameters, $body, $headers),
×
411
            $options
×
412
        );
×
413
    }
414

415
    /**
416
     * @param string $url
417
     * @param array  $body
418
     * @param array  $queryParameters
419
     * @param array  $headers
420
     * @param array  $options
421
     * @return ApiResponse
422
     * @throws Exception    If an error occurs parsing the response from the request.
423
     * @throws ApiException If an error occurs making the request.
424
     */
425
    public function put(
426
        $url = '',
427
        $body = null,
428
        $queryParameters = [],
429
        array $headers = [],
430
        $options = []
431
    ) {
432
        return $this->sendRequest(
×
433
            $this->_client->createRequest('PUT', $url, $queryParameters, $body, $headers),
×
434
            $options
×
435
        );
×
436
    }
437

438
    /**
439
     * @param string $url
440
     * @param array  $queryParameters
441
     * @param array  $headers
442
     * @param array  $options
443
     * @return ApiResponse
444
     * @throws Exception    If an error occurs parsing the response from the request.
445
     * @throws ApiException If an error occurs making the request.
446
     */
447
    public function delete($url = '', $body = null, $queryParameters = [], array $headers = [], $options = [])
448
    {
449
        return $this->sendRequest(
4✔
450
            $this->_client->createRequest('DELETE', $url, $queryParameters, $body, $headers),
4✔
451
            $options
4✔
452
        );
4✔
453
    }
454

455
    /**
456
     * @param string $path
457
     * @param array  $body
458
     * @return ApiResponse
459
     * @throws Exception    If an error occurs parsing the response from the request.
460
     * @throws ApiException If an error occurs making the request.
461
     */
462
    protected function requestToken($path = '', $body = [])
463
    {
464
        if (!empty($body['grant_type']) && $body['grant_type'] == 'password') {
23✔
465
            trigger_error(
1✔
466
                'Username/password authentication is deprecated. Please migrate to the JWT grant type.',
1✔
467
                E_USER_DEPRECATED
1✔
468
            );
1✔
469
        }
470
        $headers = [
23✔
471
            'Authorization' => 'Basic ' . $this->apiKey(),
23✔
472
            'Content-Type' => 'application/x-www-form-urlencoded'
23✔
473
        ];
23✔
474

475
        $request = $this->_client->createRequest('POST', $path, null, $body, $headers);
23✔
476

477
        return $this->sendRequest($request, ['skipAuthCheck' => true]);
23✔
478

479
    }
480

481
    /**
482
     * @return string
483
     */
484
    protected function apiKey()
485
    {
486
        return base64_encode($this->_clientId . ':' . $this->_clientSecret);
23✔
487
    }
488

489
    /**
490
     * @return string
491
     */
492
    protected function authHeader()
493
    {
494
        return $this->_auth->tokenType() . ' ' . $this->_auth->accessToken();
12✔
495
    }
496

497
    /**
498
     * @return void
499
     * @throws Exception    If an error occurs parsing the response from the refresh request.
500
     * @throws ApiException If an error occurs making the refresh request.
501
     */
502
    protected function ensureAuthentication()
503
    {
504
        if (!$this->_auth->accessTokenValid()) {
12✔
505
            $this->refresh();
1✔
506
        }
507
    }
508

509
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc