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

ringcentral / ringcentral-php / 4889308062

pending completion
4889308062

push

github

GitHub
Merge pull request #120 from embbnux/chore/github-actions

471 of 523 relevant lines covered (90.06%)

9.7 hits per line

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

92.42
/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', '/video',
25
       '/webinar',
26
       '/team-messaging',
27
       '/analytics',
28
       '/ai',
29
       '/scim'
30
    );
31

32
    /** @var string */
33
    protected $_server;
34

35
    /** @var string */
36
    protected $_clientId;
37

38
    /** @var string */
39
    protected $_clientSecret;
40

41
    /** @var string */
42
    protected $_appName;
43

44
    /** @var string */
45
    protected $_appVersion;
46

47
    /** @var string */
48
    protected $_userAgent;
49

50
    /** @var Auth */
51
    protected $_auth;
52

53
    /** @var Client */
54
    protected $_client;
55

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

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

73
        $this->_server = $server;
23✔
74

75
        $this->_auth = new Auth();
23✔
76
        $this->_client = $client;
23✔
77

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

83
    }
84

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

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

101
        $builtUrl = '';
22✔
102
        $hasHttp = stristr($path, 'http://') || stristr($path, 'https://');
22✔
103

104
        if (!empty($options['addServer']) && $options['addServer'] == TRUE && !$hasHttp) {
22✔
105
            $builtUrl .= $this->_server;
22✔
106
        }
107
        
108
        if (!array_reduce(self::KNOWN_PREFIXES,
22✔
109
                          function ($result, $key) use($path) {
22✔
110
                            if ($result) { return $result; } else { return str_starts_with( $path, $key ); }
22✔
111
                          },
22✔
112
                          FALSE) && !$hasHttp) {
22✔
113
            $builtUrl .= self::URL_PREFIX . '/' . self::API_VERSION;
5✔
114
        }
115

116
        $builtUrl .= $path;
22✔
117

118
        if (!empty($options['addMethod']) || !empty($options['addToken'])) {
22✔
119
            $builtUrl .= (stristr($path, '?') ? '&' : '?');
1✔
120
        }
121

122
        if (!empty($options['addMethod'])) {
22✔
123
            $builtUrl .= '_method=' . $options['addMethod'];
1✔
124
        }
125
        if (!empty($options['addToken'])) {
22✔
126
            $builtUrl .= ($options['addMethod'] ? '&' : '') . 'access_token=' . $this->_auth->accessToken();
1✔
127
        }
128

129
        return $builtUrl;
22✔
130

131
    }
132

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

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

182
    /**
183
     * @param string $url
184
     * @return array
185
     */
186
    public function parseAuthRedirectUrl($url)
187
    {
188

189
        parse_str($url, $qsArray);
×
190
        return [
×
191
            'code' => $qsArray['code']
×
192
        ];
×
193
    }
194

195
    /**
196
     * @param string $username
197
     * @param string $extension
198
     * @param string $password
199
     * @return ApiResponse
200
     * @throws Exception    If it fails to retrieve/parse JSON data from he response.
201
     * @throws ApiException If there is an issue with the token request.
202
     */
203
    public function login($options)
204
    {
205
        if (is_string($options)) {
20✔
206
            $options = [
20✔
207
                'username'  => func_get_arg(0),
20✔
208
                'extension' => func_get_arg(1) ? func_get_arg(1) : null,
20✔
209
                'password'  => func_get_arg(2)
20✔
210
            ];
20✔
211
        }
212

213
        $response = !empty($options['code']) ? $this->requestToken(self::TOKEN_ENDPOINT, [
20✔
214

215
            'grant_type'        => 'authorization_code',
20✔
216
            'code'              => $options['code'],
20✔
217
            'redirect_uri'      => $options['redirectUri'],
20✔
218
            'access_token_ttl'  => self::ACCESS_TOKEN_TTL,
20✔
219
            'refresh_token_ttl' => self::REFRESH_TOKEN_TTL
20✔
220

221
            ] + (!empty($options['codeVerifier']) ? [ 'code_verifier' => $options['codeVerifier'] ] : [])
20✔
222
        
223
        ) : (!empty($options['jwt']) ? $this->requestToken(self::TOKEN_ENDPOINT, [
20✔
224

225
            'grant_type'        => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
20✔
226
            'assertion'         => $options['jwt'],
20✔
227
            'access_token_ttl'  => self::ACCESS_TOKEN_TTL,
20✔
228
            'refresh_token_ttl' => self::REFRESH_TOKEN_TTL
20✔
229

230
        ]) : $this->requestToken(self::TOKEN_ENDPOINT, [
20✔
231

232
            'grant_type'        => 'password',
20✔
233
            'username'          => $options['username'],
20✔
234
            'extension'         => $options['extension'] ? $options['extension'] : null,
20✔
235
            'password'          => $options["password"],
20✔
236
            'access_token_ttl'  => self::ACCESS_TOKEN_TTL,
20✔
237
            'refresh_token_ttl' => self::REFRESH_TOKEN_TTL
20✔
238

239
        ]));
20✔
240

241
        $this->_auth->setData($response->jsonArray());
20✔
242

243
        return $response;
20✔
244

245
    }
246

247
    /**
248
     * Attempt to request new access and refresh tokens using the existing refresh token.
249
     * @return ApiResponse
250
     * @throws Exception    If it fails to retrieve/parse JSON data from he response.
251
     * @throws ApiException If the existing refresh token is invalid or there is an issue with the request.
252
     */
253
    public function refresh()
254
    {
255

256
        if (!$this->_auth->refreshTokenValid()) {
2✔
257
            throw new ApiException(null, new Exception('Refresh token has expired'));
1✔
258
        }
259

260
        // Synchronous
261
        $response = $this->requestToken(self::TOKEN_ENDPOINT, [
1✔
262
            "grant_type"        => "refresh_token",
1✔
263
            "refresh_token"     => $this->_auth->refreshToken(),
1✔
264
            "access_token_ttl"  => self::ACCESS_TOKEN_TTL,
1✔
265
            "refresh_token_ttl" => self::REFRESH_TOKEN_TTL
1✔
266
        ]);
1✔
267

268
        $this->_auth->setData($response->jsonArray());
1✔
269

270
        return $response;
1✔
271

272
    }
273

274
    /**
275
     * @return ApiResponse
276
     * @throws Exception    If an error occurs parsing the response from the request.
277
     * @throws ApiException If an error occurs making the request.
278
     */
279
    public function logout()
280
    {
281

282
        $response = $this->requestToken(self::REVOKE_ENDPOINT, [
1✔
283
            'token' => $this->_auth->accessToken()
1✔
284
        ]);
1✔
285

286
        $this->_auth->reset();
1✔
287

288
        return $response;
1✔
289

290
    }
291

292
    /**
293
     * Convenience helper used for processing requests (even externally created).
294
     * Performs access token refresh if needed.
295
     * Then adds Authorization header and API server to URI
296
     * @param RequestInterface $request
297
     * @param array            $options
298
     * @return RequestInterface
299
     * @throws Exception    If an error occurs parsing the response from the refresh request.
300
     * @throws ApiException If an error occurs making the refresh request.
301
     */
302
    public function inflateRequest(RequestInterface $request, $options = [])
303
    {
304

305
        if (empty($options['skipAuthCheck'])) {
22✔
306

307
            $this->ensureAuthentication();
13✔
308

309
            /** @var RequestInterface $request */
310
            $request = $request->withHeader('Authorization', $this->authHeader());
13✔
311

312
        }
313

314
        /** @var RequestInterface $request */
315
        $request = $request->withAddedHeader('User-Agent', $this->_userAgent)
22✔
316
                           ->withAddedHeader('RC-User-Agent', $this->_userAgent);
22✔
317

318
        $uri = new Uri($this->createUrl((string)$request->getUri(), ['addServer' => true]));
22✔
319

320
        return $request->withUri($uri);
22✔
321

322
    }
323

324
    /**
325
     * Method sends the request (even externally created) to API server using client
326
     * @param RequestInterface $request
327
     * @param array            $options
328
     * @return ApiResponse
329
     * @throws Exception    If an error occurs parsing the response from the refresh request as part of inflateRequest()
330
     * @throws ApiException If an error occurs making the refresh request as part of inflateRequest()
331
     */
332
    public function sendRequest(RequestInterface $request, $options = [])
333
    {
334

335
        return $this->_client->send($this->inflateRequest($request, $options));
22✔
336

337
    }
338

339
    /**
340
     * @param string $url
341
     * @param array  $queryParameters
342
     * @param array  $headers
343
     * @param array  $options
344
     * @return ApiResponse
345
     * @throws Exception    If an error occurs parsing the response from the request.
346
     * @throws ApiException If an error occurs making the request.
347
     */
348
    public function get($url = '', $queryParameters = [], array $headers = [], $options = [])
349
    {
350
        return $this->sendRequest(
3✔
351
            $this->_client->createRequest('GET', $url, $queryParameters, null, $headers),
3✔
352
            $options
3✔
353
        );
3✔
354
    }
355

356
    /**
357
     * @param string $url
358
     * @param array  $body
359
     * @param array  $queryParameters
360
     * @param array  $headers
361
     * @param array  $options
362
     * @return ApiResponse
363
     * @throws Exception    If an error occurs parsing the response from the request.
364
     * @throws ApiException If an error occurs making the request.
365
     */
366
    public function post(
367
        $url = '',
368
        $body = null,
369
        $queryParameters = [],
370
        array $headers = [],
371
        $options = []
372
    ) {
373
        return $this->sendRequest(
11✔
374
            $this->_client->createRequest('POST', $url, $queryParameters, $body, $headers),
11✔
375
            $options
11✔
376
        );
11✔
377
    }
378

379
    /**
380
     * @param string $url
381
     * @param array  $body
382
     * @param array  $queryParameters
383
     * @param array  $headers
384
     * @param array  $options
385
     * @return ApiResponse
386
     * @throws Exception    If an error occurs parsing the response from the request.
387
     * @throws ApiException If an error occurs making the request.
388
     */
389
    public function patch(
390
        $url = '',
391
        $body = null,
392
        $queryParameters = [],
393
        array $headers = [],
394
        $options = []
395
    ) {
396
        return $this->sendRequest(
×
397
            $this->_client->createRequest('PATCH', $url, $queryParameters, $body, $headers),
×
398
            $options
×
399
        );
×
400
    }
401

402
    /**
403
     * @param string $url
404
     * @param array  $body
405
     * @param array  $queryParameters
406
     * @param array  $headers
407
     * @param array  $options
408
     * @return ApiResponse
409
     * @throws Exception    If an error occurs parsing the response from the request.
410
     * @throws ApiException If an error occurs making the request.
411
     */
412
    public function put(
413
        $url = '',
414
        $body = null,
415
        $queryParameters = [],
416
        array $headers = [],
417
        $options = []
418
    ) {
419
        return $this->sendRequest(
3✔
420
            $this->_client->createRequest('PUT', $url, $queryParameters, $body, $headers),
3✔
421
            $options
3✔
422
        );
3✔
423
    }
424

425
    /**
426
     * @param string $url
427
     * @param array  $queryParameters
428
     * @param array  $headers
429
     * @param array  $options
430
     * @return ApiResponse
431
     * @throws Exception    If an error occurs parsing the response from the request.
432
     * @throws ApiException If an error occurs making the request.
433
     */
434
    public function delete($url = '', $queryParameters = [], array $headers = [], $options = [])
435
    {
436
        return $this->sendRequest(
2✔
437
            $this->_client->createRequest('DELETE', $url, $queryParameters, null, $headers),
2✔
438
            $options
2✔
439
        );
2✔
440
    }
441

442
    /**
443
     * @param string $path
444
     * @param array  $body
445
     * @return ApiResponse
446
     * @throws Exception    If an error occurs parsing the response from the request.
447
     * @throws ApiException If an error occurs making the request.
448
     */
449
    protected function requestToken($path = '', $body = [])
450
    {
451

452
        $headers = [
20✔
453
            'Authorization' => 'Basic ' . $this->apiKey(),
20✔
454
            'Content-Type'  => 'application/x-www-form-urlencoded'
20✔
455
        ];
20✔
456

457
        $request = $this->_client->createRequest('POST', $path, null, $body, $headers);
20✔
458

459
        return $this->sendRequest($request, ['skipAuthCheck' => true]);
20✔
460

461
    }
462

463
    /**
464
     * @return string
465
     */
466
    protected function apiKey()
467
    {
468
        return base64_encode($this->_clientId . ':' . $this->_clientSecret);
20✔
469
    }
470

471
    /**
472
     * @return string
473
     */
474
    protected function authHeader()
475
    {
476
        return $this->_auth->tokenType() . ' ' . $this->_auth->accessToken();
13✔
477
    }
478

479
    /**
480
     * @return void
481
     * @throws Exception    If an error occurs parsing the response from the refresh request.
482
     * @throws ApiException If an error occurs making the refresh request.
483
     */
484
    protected function ensureAuthentication()
485
    {
486
        if (!$this->_auth->accessTokenValid()) {
13✔
487
            $this->refresh();
1✔
488
        }
489
    }
490

491
}
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

© 2026 Coveralls, Inc