Passed
Pull Request — master (#226)
by
unknown
01:54
created

BigBlueButton   F

Complexity

Total Complexity 65

Size/Duplication

Total Lines 528
Duplicated Lines 0 %

Importance

Changes 24
Bugs 3 Features 2
Metric Value
wmc 65
eloc 122
c 24
b 3
f 2
dl 0
loc 528
rs 3.2

44 Methods

Rating   Name   Duplication   Size   Complexity  
A hooksDestroy() 0 5 1
A getHooksDestroyUrl() 0 3 1
A getUpdateRecordingsUrl() 0 3 1
A getPutRecordingTextTrackUrl() 0 3 1
A endMeeting() 0 5 1
A deleteRecordings() 0 5 1
A getJoinMeetingURL() 0 3 1
A publishRecordings() 0 5 1
A getIsMeetingRunningUrl() 0 3 1
A getPublishRecordingsUrl() 0 3 1
A setHashingAlgorithm() 0 4 1
A getDeleteRecordingsUrl() 0 3 1
A buildUrl() 0 3 1
A getMeetingInfo() 0 5 1
A createMeeting() 0 5 1
A setCurlOpts() 0 3 1
A getMeetings() 0 5 1
A insertDocument() 0 5 1
A getHooksCreateUrl() 0 3 1
A getApiVersion() 0 5 1
A getRecordingTextTracks() 0 5 1
A setJSessionId() 0 3 1
A getInsertDocumentUrl() 0 3 1
A hooksList() 0 5 1
A getMeetingsUrl() 0 3 1
A getRecordingTextTracksUrl() 0 3 1
A getRecordingsUrl() 0 3 1
A getEndMeetingURL() 0 3 1
A getMeetingInfoUrl() 0 3 1
A getRecordings() 0 5 1
A hooksCreate() 0 5 1
A putRecordingTextTrack() 0 5 1
A setTimeOut() 0 5 1
A isMeetingRunning() 0 5 1
A getJSessionId() 0 3 1
A updateRecordings() 0 5 1
A joinMeeting() 0 5 1
A getHooksListUrl() 0 3 1
B __construct() 0 24 11
A getCreateMeetingUrl() 0 3 1
A getUrlBuilder() 0 3 1
A processJsonResponse() 0 3 1
A processXmlResponse() 0 3 1
C sendRequest() 0 75 12

How to fix   Complexity   

Complex Class

Complex classes like BigBlueButton often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use BigBlueButton, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * BigBlueButton open source conferencing system - https://www.bigbluebutton.org/.
5
 *
6
 * Copyright (c) 2016-2024 BigBlueButton Inc. and by respective authors (see below).
7
 *
8
 * This program is free software; you can redistribute it and/or modify it under the
9
 * terms of the GNU Lesser General Public License as published by the Free Software
10
 * Foundation; either version 3.0 of the License, or (at your option) any later
11
 * version.
12
 *
13
 * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
14
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
15
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License along
18
 * with BigBlueButton; if not, see <https://www.gnu.org/licenses/>.
19
 */
20
21
namespace BigBlueButton;
22
23
use BigBlueButton\Enum\HashingAlgorithm;
24
use BigBlueButton\Exceptions\BadResponseException;
25
use BigBlueButton\Parameters\CreateMeetingParameters;
26
use BigBlueButton\Parameters\DeleteRecordingsParameters;
27
use BigBlueButton\Parameters\EndMeetingParameters;
28
use BigBlueButton\Parameters\GetMeetingInfoParameters;
29
use BigBlueButton\Parameters\GetRecordingsParameters;
30
use BigBlueButton\Parameters\GetRecordingTextTracksParameters;
31
use BigBlueButton\Parameters\HooksCreateParameters;
32
use BigBlueButton\Parameters\HooksDestroyParameters;
33
use BigBlueButton\Parameters\InsertDocumentParameters;
34
use BigBlueButton\Parameters\IsMeetingRunningParameters;
35
use BigBlueButton\Parameters\JoinMeetingParameters;
36
use BigBlueButton\Parameters\PublishRecordingsParameters;
37
use BigBlueButton\Parameters\PutRecordingTextTrackParameters;
38
use BigBlueButton\Parameters\UpdateRecordingsParameters;
39
use BigBlueButton\Responses\ApiVersionResponse;
40
use BigBlueButton\Responses\CreateMeetingResponse;
41
use BigBlueButton\Responses\DeleteRecordingsResponse;
42
use BigBlueButton\Responses\EndMeetingResponse;
43
use BigBlueButton\Responses\GetMeetingInfoResponse;
44
use BigBlueButton\Responses\GetMeetingsResponse;
45
use BigBlueButton\Responses\GetRecordingsResponse;
46
use BigBlueButton\Responses\GetRecordingTextTracksResponse;
47
use BigBlueButton\Responses\HooksCreateResponse;
48
use BigBlueButton\Responses\HooksDestroyResponse;
49
use BigBlueButton\Responses\HooksListResponse;
50
use BigBlueButton\Responses\IsMeetingRunningResponse;
51
use BigBlueButton\Responses\JoinMeetingResponse;
52
use BigBlueButton\Responses\PublishRecordingsResponse;
53
use BigBlueButton\Responses\PutRecordingTextTrackResponse;
54
use BigBlueButton\Responses\UpdateRecordingsResponse;
55
use BigBlueButton\Util\UrlBuilder;
56
57
/**
58
 * Class BigBlueButton.
59
 */
60
class BigBlueButton
61
{
62
    protected string $bbbSecret;
63
    protected string $bbbBaseUrl;
64
    protected string $jSessionId;
65
    protected string $hashingAlgorithm;
66
67
    /**
68
     * @var array<int, mixed>
69
     */
70
    protected array $curlOpts = [];
71
    protected int $timeOut    = 10;
72
73
    private UrlBuilder $urlBuilder;
74
75
    /**
76
     * @param null|array<string, mixed> $opts
77
     */
78
    public function __construct(?string $baseUrl = null, ?string $secret = null, ?array $opts = [])
79
    {
80
        // Provide an early error message if configuration is wrong
81
        if (is_null($baseUrl) && false === getenv('BBB_SERVER_BASE_URL')) {
82
            throw new \RuntimeException('No BBB-Server-Url found! Please provide it either in constructor ' .
83
                "(1st argument) or by environment variable 'BBB_SERVER_BASE_URL'!");
84
        }
85
86
        if (is_null($secret) && false === getenv('BBB_SECRET') && false === getenv('BBB_SECURITY_SALT')) {
87
            throw new \RuntimeException('No BBB-Secret (or BBB-Salt) found! Please provide it either in constructor ' .
88
                "(2nd argument) or by environment variable 'BBB_SECRET' (or 'BBB_SECURITY_SALT')!");
89
        }
90
91
        // Keeping backward compatibility with older deployed versions
92
        // BBB_SECRET is the new variable name and have higher priority against the old named BBB_SECURITY_SALT
93
        // Reminder: getenv() will return FALSE if not set. But bool is not accepted by $this->bbbSecret
94
        //           nor $this->bbbBaseUrl (only strings), thus FALSE will be converted automatically to an empty
95
        //           string (''). Having a bool should be not possible due to the checks above and the automated
96
        //           conversion, but PHPStan is still unhappy, so it's covered explicit by adding `?: ''`.
97
        $this->bbbBaseUrl       = $baseUrl ?: getenv('BBB_SERVER_BASE_URL') ?: '';
98
        $this->bbbSecret        = $secret ?: getenv('BBB_SECRET') ?: getenv('BBB_SECURITY_SALT') ?: '';
99
        $this->hashingAlgorithm = HashingAlgorithm::SHA_256;
100
        $this->urlBuilder       = new UrlBuilder($this->bbbSecret, $this->bbbBaseUrl, $this->hashingAlgorithm);
101
        $this->curlOpts         = $opts['curl'] ?? [];
102
    }
103
104
    /**
105
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
106
     */
107
    public function setHashingAlgorithm(string $hashingAlgorithm): void
108
    {
109
        $this->hashingAlgorithm = $hashingAlgorithm;
110
        $this->urlBuilder->setHashingAlgorithm($hashingAlgorithm);
111
    }
112
113
    /**
114
     * @throws BadResponseException|\RuntimeException
115
     */
116
    public function getApiVersion(): ApiVersionResponse
117
    {
118
        $xml = $this->processXmlResponse($this->urlBuilder->buildUrl());
119
120
        return new ApiVersionResponse($xml);
121
    }
122
123
    // __________________ BBB ADMINISTRATION METHODS _________________
124
    /* The methods in the following section support the following categories of the BBB API:
125
    -- create
126
    -- join
127
    -- end
128
    -- insertDocument
129
    */
130
131
    /**
132
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
133
     */
134
    public function getCreateMeetingUrl(CreateMeetingParameters $createMeetingParams): string
135
    {
136
        return $this->urlBuilder->getCreateMeetingUrl($createMeetingParams);
137
    }
138
139
    /**
140
     * @throws BadResponseException|\RuntimeException
141
     */
142
    public function createMeeting(CreateMeetingParameters $createMeetingParams): CreateMeetingResponse
143
    {
144
        $xml = $this->processXmlResponse($this->urlBuilder->getCreateMeetingUrl($createMeetingParams), $createMeetingParams->getPresentationsAsXML());
145
146
        return new CreateMeetingResponse($xml);
147
    }
148
149
    /**
150
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
151
     */
152
    public function getJoinMeetingURL(JoinMeetingParameters $joinMeetingParams): string
153
    {
154
        return $this->urlBuilder->getJoinMeetingURL($joinMeetingParams);
155
    }
156
157
    /**
158
     * @throws BadResponseException|\RuntimeException
159
     */
160
    public function joinMeeting(JoinMeetingParameters $joinMeetingParams): JoinMeetingResponse
161
    {
162
        $xml = $this->processXmlResponse($this->urlBuilder->getJoinMeetingURL($joinMeetingParams));
163
164
        return new JoinMeetingResponse($xml);
165
    }
166
167
    /**
168
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
169
     */
170
    public function getEndMeetingURL(EndMeetingParameters $endParams): string
171
    {
172
        return $this->urlBuilder->getEndMeetingURL($endParams);
173
    }
174
175
    /**
176
     * @throws BadResponseException|\RuntimeException
177
     */
178
    public function endMeeting(EndMeetingParameters $endParams): EndMeetingResponse
179
    {
180
        $xml = $this->processXmlResponse($this->urlBuilder->getEndMeetingURL($endParams));
181
182
        return new EndMeetingResponse($xml);
183
    }
184
185
    /**
186
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
187
     */
188
    public function getInsertDocumentUrl(InsertDocumentParameters $insertDocumentParameters): string
189
    {
190
        return $this->urlBuilder->getInsertDocumentUrl($insertDocumentParameters);
191
    }
192
193
    /**
194
     * @throws BadResponseException|\RuntimeException
195
     */
196
    public function insertDocument(InsertDocumentParameters $insertDocumentParams): CreateMeetingResponse
197
    {
198
        $xml = $this->processXmlResponse($this->urlBuilder->getInsertDocumentUrl($insertDocumentParams), $insertDocumentParams->getPresentationsAsXML());
199
200
        return new CreateMeetingResponse($xml);
201
    }
202
203
    // __________________ BBB MONITORING METHODS _________________
204
    /* The methods in the following section support the following categories of the BBB API:
205
    -- isMeetingRunning
206
    -- getMeetings
207
    -- getMeetingInfo
208
    */
209
210
    /**
211
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
212
     */
213
    public function getIsMeetingRunningUrl(IsMeetingRunningParameters $meetingParams): string
214
    {
215
        return $this->urlBuilder->getIsMeetingRunningUrl($meetingParams);
216
    }
217
218
    /**
219
     * @throws BadResponseException|\RuntimeException
220
     */
221
    public function isMeetingRunning(IsMeetingRunningParameters $meetingParams): IsMeetingRunningResponse
222
    {
223
        $xml = $this->processXmlResponse($this->urlBuilder->getIsMeetingRunningUrl($meetingParams));
224
225
        return new IsMeetingRunningResponse($xml);
226
    }
227
228
    /**
229
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
230
     */
231
    public function getMeetingsUrl(): string
232
    {
233
        return $this->urlBuilder->getMeetingsUrl();
234
    }
235
236
    /**
237
     * @throws BadResponseException|\RuntimeException
238
     */
239
    public function getMeetings(): GetMeetingsResponse
240
    {
241
        $xml = $this->processXmlResponse($this->urlBuilder->getMeetingsUrl());
242
243
        return new GetMeetingsResponse($xml);
244
    }
245
246
    /**
247
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
248
     */
249
    public function getMeetingInfoUrl(GetMeetingInfoParameters $meetingParams): string
250
    {
251
        return $this->urlBuilder->getMeetingInfoUrl($meetingParams);
252
    }
253
254
    /**
255
     * @throws BadResponseException|\RuntimeException
256
     */
257
    public function getMeetingInfo(GetMeetingInfoParameters $meetingParams): GetMeetingInfoResponse
258
    {
259
        $xml = $this->processXmlResponse($this->urlBuilder->getMeetingInfoUrl($meetingParams));
260
261
        return new GetMeetingInfoResponse($xml);
262
    }
263
264
    // __________________ BBB RECORDING METHODS _________________
265
    /* The methods in the following section support the following categories of the BBB API:
266
    -- getRecordings
267
    -- publishRecordings
268
    -- deleteRecordings
269
    */
270
271
    /**
272
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
273
     */
274
    public function getRecordingsUrl(GetRecordingsParameters $recordingsParams): string
275
    {
276
        return $this->urlBuilder->getRecordingsUrl($recordingsParams);
277
    }
278
279
    /**
280
     * @param mixed $recordingParams
281
     *
282
     * @throws BadResponseException|\RuntimeException
283
     */
284
    public function getRecordings($recordingParams): GetRecordingsResponse
285
    {
286
        $xml = $this->processXmlResponse($this->urlBuilder->getRecordingsUrl($recordingParams));
287
288
        return new GetRecordingsResponse($xml);
289
    }
290
291
    /**
292
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
293
     */
294
    public function getPublishRecordingsUrl(PublishRecordingsParameters $recordingParams): string
295
    {
296
        return $this->urlBuilder->getPublishRecordingsUrl($recordingParams);
297
    }
298
299
    /**
300
     * @throws BadResponseException
301
     */
302
    public function publishRecordings(PublishRecordingsParameters $recordingParams): PublishRecordingsResponse
303
    {
304
        $xml = $this->processXmlResponse($this->urlBuilder->getPublishRecordingsUrl($recordingParams));
305
306
        return new PublishRecordingsResponse($xml);
307
    }
308
309
    /**
310
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
311
     */
312
    public function getDeleteRecordingsUrl(DeleteRecordingsParameters $recordingParams): string
313
    {
314
        return $this->urlBuilder->getDeleteRecordingsUrl($recordingParams);
315
    }
316
317
    /**
318
     * @throws BadResponseException|\RuntimeException
319
     */
320
    public function deleteRecordings(DeleteRecordingsParameters $recordingParams): DeleteRecordingsResponse
321
    {
322
        $xml = $this->processXmlResponse($this->urlBuilder->getDeleteRecordingsUrl($recordingParams));
323
324
        return new DeleteRecordingsResponse($xml);
325
    }
326
327
    /**
328
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
329
     */
330
    public function getUpdateRecordingsUrl(UpdateRecordingsParameters $recordingParams): string
331
    {
332
        return $this->urlBuilder->getUpdateRecordingsUrl($recordingParams);
333
    }
334
335
    /**
336
     * @throws BadResponseException|\RuntimeException
337
     */
338
    public function updateRecordings(UpdateRecordingsParameters $recordingParams): UpdateRecordingsResponse
339
    {
340
        $xml = $this->processXmlResponse($this->urlBuilder->getUpdateRecordingsUrl($recordingParams));
341
342
        return new UpdateRecordingsResponse($xml);
343
    }
344
345
    /**
346
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
347
     */
348
    public function getRecordingTextTracksUrl(GetRecordingTextTracksParameters $getRecordingTextTracksParameters): string
349
    {
350
        return $this->urlBuilder->getRecordingTextTracksUrl($getRecordingTextTracksParameters);
351
    }
352
353
    /**
354
     * @throws BadResponseException
355
     */
356
    public function getRecordingTextTracks(GetRecordingTextTracksParameters $getRecordingTextTracksParams): GetRecordingTextTracksResponse
357
    {
358
        $json = $this->processJsonResponse($this->urlBuilder->getRecordingTextTracksUrl($getRecordingTextTracksParams));
359
360
        return new GetRecordingTextTracksResponse($json);
361
    }
362
363
    /**
364
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
365
     */
366
    public function getPutRecordingTextTrackUrl(PutRecordingTextTrackParameters $putRecordingTextTrackParams): string
367
    {
368
        return $this->urlBuilder->getPutRecordingTextTrackUrl($putRecordingTextTrackParams);
369
    }
370
371
    /**
372
     * @throws BadResponseException
373
     */
374
    public function putRecordingTextTrack(PutRecordingTextTrackParameters $putRecordingTextTrackParams): PutRecordingTextTrackResponse
375
    {
376
        $json = $this->processJsonResponse($this->urlBuilder->getPutRecordingTextTrackUrl($putRecordingTextTrackParams));
377
378
        return new PutRecordingTextTrackResponse($json);
379
    }
380
381
    // ____________________ WEB HOOKS METHODS ___________________
382
383
    /**
384
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
385
     */
386
    public function getHooksCreateUrl(HooksCreateParameters $hookCreateParams): string
387
    {
388
        return $this->urlBuilder->getHooksCreateUrl($hookCreateParams);
389
    }
390
391
    /**
392
     * @param mixed $hookCreateParams
393
     *
394
     * @throws BadResponseException
395
     */
396
    public function hooksCreate($hookCreateParams): HooksCreateResponse
397
    {
398
        $xml = $this->processXmlResponse($this->urlBuilder->getHooksCreateUrl($hookCreateParams));
399
400
        return new HooksCreateResponse($xml);
401
    }
402
403
    /**
404
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
405
     */
406
    public function getHooksListUrl(): string
407
    {
408
        return $this->urlBuilder->getHooksListUrl();
409
    }
410
411
    /**
412
     * @throws BadResponseException
413
     */
414
    public function hooksList(): HooksListResponse
415
    {
416
        $xml = $this->processXmlResponse($this->urlBuilder->getHooksListUrl());
417
418
        return new HooksListResponse($xml);
419
    }
420
421
    /**
422
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
423
     */
424
    public function getHooksDestroyUrl(HooksDestroyParameters $hooksDestroyParams): string
425
    {
426
        return $this->urlBuilder->getHooksDestroyUrl($hooksDestroyParams);
427
    }
428
429
    /**
430
     * @param mixed $hooksDestroyParams
431
     *
432
     * @throws BadResponseException
433
     */
434
    public function hooksDestroy($hooksDestroyParams): HooksDestroyResponse
435
    {
436
        $xml = $this->processXmlResponse($this->urlBuilder->getHooksDestroyUrl($hooksDestroyParams));
437
438
        return new HooksDestroyResponse($xml);
439
    }
440
441
    // ____________________ SPECIAL METHODS ___________________
442
443
    public function getJSessionId(): string
444
    {
445
        return $this->jSessionId;
446
    }
447
448
    public function setJSessionId(string $jSessionId): void
449
    {
450
        $this->jSessionId = $jSessionId;
451
    }
452
453
    /**
454
     * @param array<int, mixed> $curlOpts
455
     */
456
    public function setCurlOpts(array $curlOpts): void
457
    {
458
        $this->curlOpts = $curlOpts;
459
    }
460
461
    /**
462
     * Set Curl Timeout (Optional), Default 10 Seconds.
463
     */
464
    public function setTimeOut(int $TimeOutInSeconds): self
465
    {
466
        $this->timeOut = $TimeOutInSeconds;
467
468
        return $this;
469
    }
470
471
    /**
472
     * @deprecated replaced by same function-name provided by UrlBuilder-BigBlueButton
473
     *
474
     * Public accessor for buildUrl
475
     */
476
    public function buildUrl(string $method = '', string $params = '', bool $append = true): string
477
    {
478
        return $this->getUrlBuilder()->buildUrl($method, $params, $append);
479
    }
480
481
    public function getUrlBuilder(): UrlBuilder
482
    {
483
        return $this->urlBuilder;
484
    }
485
486
    // ____________________ INTERNAL CLASS METHODS ___________________
487
488
    /**
489
     * A private utility method used by other public methods to request HTTP responses.
490
     *
491
     * @throws BadResponseException|\RuntimeException
492
     */
493
    private function sendRequest(string $url, string $payload = '', string $contentType = 'application/xml'): string
494
    {
495
        if (!extension_loaded('curl')) {
496
            throw new \RuntimeException('Post XML data set but curl PHP module is not installed or not enabled.');
497
        }
498
499
        $ch         = curl_init();
500
        $cookieFile = tmpfile();
501
502
        if (!$ch) {  // @phpstan-ignore-line
503
            throw new \RuntimeException('Unhandled curl error: ' . curl_error($ch));
504
        }
505
506
        // JSESSIONID
507
        if ($cookieFile) {
0 ignored issues
show
introduced by
$cookieFile is of type resource, thus it always evaluated to false.
Loading history...
508
            $cookieFilePath = stream_get_meta_data($cookieFile)['uri'];
509
            $cookies        = file_get_contents($cookieFilePath);
510
511
            curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFilePath);
512
            curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFilePath);
513
514
            if ($cookies) {
515
                if (false !== mb_strpos($cookies, 'JSESSIONID')) {
516
                    preg_match('/(?:JSESSIONID\s*)(?<JSESSIONID>.*)/', $cookies, $output_array);
517
                    $this->setJSessionId($output_array['JSESSIONID']);
518
                }
519
            }
520
        }
521
522
        // PAYLOAD
523
        if (!empty($payload)) {
524
            curl_setopt($ch, CURLOPT_HEADER, 0);
525
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
526
            curl_setopt($ch, CURLOPT_POST, 1);
527
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
528
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
529
                'Content-type: ' . $contentType,
530
                'Content-length: ' . mb_strlen($payload),
531
            ]);
532
        }
533
534
        // OTHERS
535
        foreach ($this->curlOpts as $opt => $value) {
536
            curl_setopt($ch, $opt, $value);
537
        }
538
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
539
        curl_setopt($ch, CURLOPT_ENCODING, 'UTF-8');
540
        curl_setopt($ch, CURLOPT_URL, $url);
541
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
542
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
543
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeOut);
544
545
        // EXECUTE and RESULT
546
        $data     = curl_exec($ch);
547
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
548
549
        // ANALYSE
550
        if (false === $data) {
551
            throw new \RuntimeException('Unhandled curl error: ' . curl_error($ch));
552
        }
553
554
        if (is_bool($data)) {
555
            throw new \RuntimeException('Curl error: BOOL received, but STRING expected.');
556
        }
557
558
        if ($httpCode < 200 || $httpCode >= 300) {
559
            throw new BadResponseException('Bad response, HTTP code: ' . $httpCode);
560
        }
561
562
        // CLOSE AND UNSET
563
        curl_close($ch);
564
        unset($ch);
565
566
        // RETURN
567
        return $data;
568
    }
569
570
    /**
571
     * A private utility method used by other public methods to process XML responses.
572
     *
573
     * @throws BadResponseException|\Exception
574
     */
575
    private function processXmlResponse(string $url, string $payload = ''): \SimpleXMLElement
576
    {
577
        return new \SimpleXMLElement($this->sendRequest($url, $payload, 'application/xml'));
578
    }
579
580
    /**
581
     * A private utility method used by other public methods to process json responses.
582
     *
583
     * @throws BadResponseException
584
     */
585
    private function processJsonResponse(string $url, string $payload = ''): string
586
    {
587
        return $this->sendRequest($url, $payload, 'application/json');
588
    }
589
}
590