Completed
Push — master ( aaa777...736635 )
by Ghazi
26s queued 20s
created

BigBlueButton::getUpdateRecordingsUrl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
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\Core\ApiMethod;
24
use BigBlueButton\Enum\HashingAlgorithm;
25
use BigBlueButton\Exceptions\BadResponseException;
26
use BigBlueButton\Parameters\CreateMeetingParameters;
27
use BigBlueButton\Parameters\DeleteRecordingsParameters;
28
use BigBlueButton\Parameters\EndMeetingParameters;
29
use BigBlueButton\Parameters\GetMeetingInfoParameters;
30
use BigBlueButton\Parameters\GetRecordingsParameters;
31
use BigBlueButton\Parameters\GetRecordingTextTracksParameters;
32
use BigBlueButton\Parameters\HooksCreateParameters;
33
use BigBlueButton\Parameters\HooksDestroyParameters;
34
use BigBlueButton\Parameters\InsertDocumentParameters;
35
use BigBlueButton\Parameters\IsMeetingRunningParameters;
36
use BigBlueButton\Parameters\JoinMeetingParameters;
37
use BigBlueButton\Parameters\PublishRecordingsParameters;
38
use BigBlueButton\Parameters\PutRecordingTextTrackParameters;
39
use BigBlueButton\Parameters\UpdateRecordingsParameters;
40
use BigBlueButton\Responses\ApiVersionResponse;
41
use BigBlueButton\Responses\CreateMeetingResponse;
42
use BigBlueButton\Responses\DeleteRecordingsResponse;
43
use BigBlueButton\Responses\EndMeetingResponse;
44
use BigBlueButton\Responses\GetMeetingInfoResponse;
45
use BigBlueButton\Responses\GetMeetingsResponse;
46
use BigBlueButton\Responses\GetRecordingsResponse;
47
use BigBlueButton\Responses\GetRecordingTextTracksResponse;
48
use BigBlueButton\Responses\HooksCreateResponse;
49
use BigBlueButton\Responses\HooksDestroyResponse;
50
use BigBlueButton\Responses\HooksListResponse;
51
use BigBlueButton\Responses\IsMeetingRunningResponse;
52
use BigBlueButton\Responses\JoinMeetingResponse;
53
use BigBlueButton\Responses\PublishRecordingsResponse;
54
use BigBlueButton\Responses\PutRecordingTextTrackResponse;
55
use BigBlueButton\Responses\UpdateRecordingsResponse;
56
use BigBlueButton\Util\UrlBuilder;
57
58
/**
59
 * Class BigBlueButton.
60
 */
61
class BigBlueButton
62
{
63
    protected string $securitySecret;
64
    protected string $bbbServerBaseUrl;
65
    protected UrlBuilder $urlBuilder;
66
    protected string $jSessionId;
67
68
    protected string $hashingAlgorithm;
69
70
    /**
71
     * @var array<int, mixed>
72
     */
73
    protected array $curlOpts = [];
74
    protected int $timeOut    = 10;
75
76
    /**
77
     * @param null|array<string, mixed> $opts
78
     */
79
    public function __construct(?string $baseUrl = null, ?string $secret = null, ?array $opts = [])
80
    {
81
        // Keeping backward compatibility with older deployed versions
82
        // BBB_SECRET is the new variable name and have higher priority against the old named BBB_SECURITY_SALT
83
        $this->securitySecret   = $secret ?: getenv('BBB_SECRET') ?: getenv('BBB_SECURITY_SALT') ?: '';
84
        $this->bbbServerBaseUrl = $baseUrl ?: getenv('BBB_SERVER_BASE_URL') ?: '';
85
        $this->hashingAlgorithm = HashingAlgorithm::SHA_256;
86
        $this->urlBuilder       = new UrlBuilder($this->securitySecret, $this->bbbServerBaseUrl, $this->hashingAlgorithm);
87
        $this->curlOpts         = $opts['curl'] ?? [];
88
    }
89
90
    public function setHashingAlgorithm(string $hashingAlgorithm): void
91
    {
92
        $this->hashingAlgorithm = $hashingAlgorithm;
93
        $this->urlBuilder->setHashingAlgorithm($hashingAlgorithm);
94
    }
95
96
    /**
97
     * @throws BadResponseException|\RuntimeException
98
     */
99
    public function getApiVersion(): ApiVersionResponse
100
    {
101
        $xml = $this->processXmlResponse($this->urlBuilder->buildUrl());
102
103
        return new ApiVersionResponse($xml);
104
    }
105
106
    // __________________ BBB ADMINISTRATION METHODS _________________
107
    /* The methods in the following section support the following categories of the BBB API:
108
    -- create
109
    -- join
110
    -- end
111
    -- insertDocument
112
    */
113
114
    public function getCreateMeetingUrl(CreateMeetingParameters $createMeetingParams): string
115
    {
116
        return $this->urlBuilder->buildUrl(ApiMethod::CREATE, $createMeetingParams->getHTTPQuery());
117
    }
118
119
    /**
120
     * @throws BadResponseException|\RuntimeException
121
     */
122
    public function createMeeting(CreateMeetingParameters $createMeetingParams): CreateMeetingResponse
123
    {
124
        $xml = $this->processXmlResponse($this->getCreateMeetingUrl($createMeetingParams), $createMeetingParams->getPresentationsAsXML());
125
126
        return new CreateMeetingResponse($xml);
127
    }
128
129
    public function getJoinMeetingURL(JoinMeetingParameters $joinMeetingParams): string
130
    {
131
        return $this->urlBuilder->buildUrl(ApiMethod::JOIN, $joinMeetingParams->getHTTPQuery());
132
    }
133
134
    /**
135
     * @throws BadResponseException|\RuntimeException
136
     */
137
    public function joinMeeting(JoinMeetingParameters $joinMeetingParams): JoinMeetingResponse
138
    {
139
        $xml = $this->processXmlResponse($this->getJoinMeetingURL($joinMeetingParams));
140
141
        return new JoinMeetingResponse($xml);
142
    }
143
144
    public function getEndMeetingURL(EndMeetingParameters $endParams): string
145
    {
146
        return $this->urlBuilder->buildUrl(ApiMethod::END, $endParams->getHTTPQuery());
147
    }
148
149
    /**
150
     * @throws BadResponseException|\RuntimeException
151
     */
152
    public function endMeeting(EndMeetingParameters $endParams): EndMeetingResponse
153
    {
154
        $xml = $this->processXmlResponse($this->getEndMeetingURL($endParams));
155
156
        return new EndMeetingResponse($xml);
157
    }
158
159
    public function getInsertDocumentUrl(InsertDocumentParameters $insertDocumentParameters): string
160
    {
161
        return $this->urlBuilder->buildUrl(ApiMethod::INSERT_DOCUMENT, $insertDocumentParameters->getHTTPQuery());
162
    }
163
164
    /**
165
     * @throws BadResponseException|\RuntimeException
166
     */
167
    public function insertDocument(InsertDocumentParameters $insertDocumentParams): CreateMeetingResponse
168
    {
169
        $xml = $this->processXmlResponse($this->getInsertDocumentUrl($insertDocumentParams), $insertDocumentParams->getPresentationsAsXML());
170
171
        return new CreateMeetingResponse($xml);
172
    }
173
174
    // __________________ BBB MONITORING METHODS _________________
175
    /* The methods in the following section support the following categories of the BBB API:
176
    -- isMeetingRunning
177
    -- getMeetings
178
    -- getMeetingInfo
179
    */
180
181
    public function getIsMeetingRunningUrl(IsMeetingRunningParameters $meetingParams): string
182
    {
183
        return $this->urlBuilder->buildUrl(ApiMethod::IS_MEETING_RUNNING, $meetingParams->getHTTPQuery());
184
    }
185
186
    /**
187
     * @throws BadResponseException|\RuntimeException
188
     */
189
    public function isMeetingRunning(IsMeetingRunningParameters $meetingParams): IsMeetingRunningResponse
190
    {
191
        $xml = $this->processXmlResponse($this->getIsMeetingRunningUrl($meetingParams));
192
193
        return new IsMeetingRunningResponse($xml);
194
    }
195
196
    public function getMeetingsUrl(): string
197
    {
198
        return $this->urlBuilder->buildUrl(ApiMethod::GET_MEETINGS);
199
    }
200
201
    /**
202
     * @throws BadResponseException|\RuntimeException
203
     */
204
    public function getMeetings(): GetMeetingsResponse
205
    {
206
        $xml = $this->processXmlResponse($this->getMeetingsUrl());
207
208
        return new GetMeetingsResponse($xml);
209
    }
210
211
    public function getMeetingInfoUrl(GetMeetingInfoParameters $meetingParams): string
212
    {
213
        return $this->urlBuilder->buildUrl(ApiMethod::GET_MEETING_INFO, $meetingParams->getHTTPQuery());
214
    }
215
216
    /**
217
     * @throws BadResponseException|\RuntimeException
218
     */
219
    public function getMeetingInfo(GetMeetingInfoParameters $meetingParams): GetMeetingInfoResponse
220
    {
221
        $xml = $this->processXmlResponse($this->getMeetingInfoUrl($meetingParams));
222
223
        return new GetMeetingInfoResponse($xml);
224
    }
225
226
    // __________________ BBB RECORDING METHODS _________________
227
    /* The methods in the following section support the following categories of the BBB API:
228
    -- getRecordings
229
    -- publishRecordings
230
    -- deleteRecordings
231
    */
232
233
    public function getRecordingsUrl(GetRecordingsParameters $recordingsParams): string
234
    {
235
        return $this->urlBuilder->buildUrl(ApiMethod::GET_RECORDINGS, $recordingsParams->getHTTPQuery());
236
    }
237
238
    /**
239
     * @param mixed $recordingParams
240
     *
241
     * @throws BadResponseException|\RuntimeException
242
     */
243
    public function getRecordings($recordingParams): GetRecordingsResponse
244
    {
245
        $xml = $this->processXmlResponse($this->getRecordingsUrl($recordingParams));
246
247
        return new GetRecordingsResponse($xml);
248
    }
249
250
    public function getPublishRecordingsUrl(PublishRecordingsParameters $recordingParams): string
251
    {
252
        return $this->urlBuilder->buildUrl(ApiMethod::PUBLISH_RECORDINGS, $recordingParams->getHTTPQuery());
253
    }
254
255
    public function publishRecordings(PublishRecordingsParameters $recordingParams): PublishRecordingsResponse
256
    {
257
        $xml = $this->processXmlResponse($this->getPublishRecordingsUrl($recordingParams));
258
259
        return new PublishRecordingsResponse($xml);
260
    }
261
262
    public function getDeleteRecordingsUrl(DeleteRecordingsParameters $recordingParams): string
263
    {
264
        return $this->urlBuilder->buildUrl(ApiMethod::DELETE_RECORDINGS, $recordingParams->getHTTPQuery());
265
    }
266
267
    /**
268
     * @throws BadResponseException|\RuntimeException
269
     */
270
    public function deleteRecordings(DeleteRecordingsParameters $recordingParams): DeleteRecordingsResponse
271
    {
272
        $xml = $this->processXmlResponse($this->getDeleteRecordingsUrl($recordingParams));
273
274
        return new DeleteRecordingsResponse($xml);
275
    }
276
277
    public function getUpdateRecordingsUrl(UpdateRecordingsParameters $recordingParams): string
278
    {
279
        return $this->urlBuilder->buildUrl(ApiMethod::UPDATE_RECORDINGS, $recordingParams->getHTTPQuery());
280
    }
281
282
    /**
283
     * @throws BadResponseException|\RuntimeException
284
     */
285
    public function updateRecordings(UpdateRecordingsParameters $recordingParams): UpdateRecordingsResponse
286
    {
287
        $xml = $this->processXmlResponse($this->getUpdateRecordingsUrl($recordingParams));
288
289
        return new UpdateRecordingsResponse($xml);
290
    }
291
292
    public function getRecordingTextTracksUrl(GetRecordingTextTracksParameters $getRecordingTextTracksParameters): string
293
    {
294
        return $this->urlBuilder->buildUrl(ApiMethod::GET_RECORDING_TEXT_TRACKS, $getRecordingTextTracksParameters->getHTTPQuery());
295
    }
296
297
    public function getRecordingTextTracks(GetRecordingTextTracksParameters $getRecordingTextTracksParams): GetRecordingTextTracksResponse
298
    {
299
        $json = $this->processJsonResponse($this->getRecordingTextTracksUrl($getRecordingTextTracksParams));
300
301
        return new GetRecordingTextTracksResponse($json);
302
    }
303
304
    public function getPutRecordingTextTrackUrl(PutRecordingTextTrackParameters $putRecordingTextTrackParams): string
305
    {
306
        return $this->urlBuilder->buildUrl(ApiMethod::PUT_RECORDING_TEXT_TRACK, $putRecordingTextTrackParams->getHTTPQuery());
307
    }
308
309
    public function putRecordingTextTrack(PutRecordingTextTrackParameters $putRecordingTextTrackParams): PutRecordingTextTrackResponse
310
    {
311
        $json = $this->processJsonResponse($this->getPutRecordingTextTrackUrl($putRecordingTextTrackParams));
312
313
        return new PutRecordingTextTrackResponse($json);
314
    }
315
316
    // ____________________ WEB HOOKS METHODS ___________________
317
318
    public function getHooksCreateUrl(HooksCreateParameters $hookCreateParams): string
319
    {
320
        return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_CREATE, $hookCreateParams->getHTTPQuery());
321
    }
322
323
    /**
324
     * @param mixed $hookCreateParams
325
     *
326
     * @throws BadResponseException
327
     */
328
    public function hooksCreate($hookCreateParams): HooksCreateResponse
329
    {
330
        $xml = $this->processXmlResponse($this->getHooksCreateUrl($hookCreateParams));
331
332
        return new HooksCreateResponse($xml);
333
    }
334
335
    public function getHooksListUrl(): string
336
    {
337
        return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_LIST);
338
    }
339
340
    public function hooksList(): HooksListResponse
341
    {
342
        $xml = $this->processXmlResponse($this->getHooksListUrl());
343
344
        return new HooksListResponse($xml);
345
    }
346
347
    public function getHooksDestroyUrl(HooksDestroyParameters $hooksDestroyParams): string
348
    {
349
        return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_DESTROY, $hooksDestroyParams->getHTTPQuery());
350
    }
351
352
    /**
353
     * @param mixed $hooksDestroyParams
354
     *
355
     * @throws BadResponseException
356
     */
357
    public function hooksDestroy($hooksDestroyParams): HooksDestroyResponse
358
    {
359
        $xml = $this->processXmlResponse($this->getHooksDestroyUrl($hooksDestroyParams));
360
361
        return new HooksDestroyResponse($xml);
362
    }
363
364
    // ____________________ SPECIAL METHODS ___________________
365
366
    public function getJSessionId(): string
367
    {
368
        return $this->jSessionId;
369
    }
370
371
    public function setJSessionId(string $jSessionId): void
372
    {
373
        $this->jSessionId = $jSessionId;
374
    }
375
376
    /**
377
     * @param array<int, mixed> $curlOpts
378
     */
379
    public function setCurlOpts(array $curlOpts): void
380
    {
381
        $this->curlOpts = $curlOpts;
382
    }
383
384
    /**
385
     * Set Curl Timeout (Optional), Default 10 Seconds.
386
     */
387
    public function setTimeOut(int $TimeOutInSeconds): self
388
    {
389
        $this->timeOut = $TimeOutInSeconds;
390
391
        return $this;
392
    }
393
394
    /**
395
     * Public accessor for buildUrl.
396
     */
397
    public function buildUrl(string $method = '', string $params = '', bool $append = true): string
398
    {
399
        return $this->urlBuilder->buildUrl($method, $params, $append);
400
    }
401
402
    // ____________________ INTERNAL CLASS METHODS ___________________
403
404
    /**
405
     * A private utility method used by other public methods to request HTTP responses.
406
     *
407
     * @throws BadResponseException|\RuntimeException
408
     */
409
    private function sendRequest(string $url, string $payload = '', string $contentType = 'application/xml'): string
410
    {
411
        if (!extension_loaded('curl')) {
412
            throw new \RuntimeException('Post XML data set but curl PHP module is not installed or not enabled.');
413
        }
414
415
        $ch         = curl_init();
416
        $cookieFile = tmpfile();
417
418
        if (!$ch) {  // @phpstan-ignore-line
419
            throw new \RuntimeException('Unhandled curl error: ' . curl_error($ch));
420
        }
421
422
        // JSESSIONID
423
        if ($cookieFile) {
0 ignored issues
show
introduced by
$cookieFile is of type resource, thus it always evaluated to false.
Loading history...
424
            $cookieFilePath = stream_get_meta_data($cookieFile)['uri'];
425
            $cookies        = file_get_contents($cookieFilePath);
426
427
            curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFilePath);
428
            curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFilePath);
429
430
            if ($cookies) {
431
                if (false !== mb_strpos($cookies, 'JSESSIONID')) {
432
                    preg_match('/(?:JSESSIONID\s*)(?<JSESSIONID>.*)/', $cookies, $output_array);
433
                    $this->setJSessionId($output_array['JSESSIONID']);
434
                }
435
            }
436
        }
437
438
        // PAYLOAD
439
        if (!empty($payload)) {
440
            curl_setopt($ch, CURLOPT_HEADER, 0);
441
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
442
            curl_setopt($ch, CURLOPT_POST, 1);
443
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
444
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
445
                'Content-type: ' . $contentType,
446
                'Content-length: ' . mb_strlen($payload),
447
            ]);
448
        }
449
450
        // OTHERS
451
        foreach ($this->curlOpts as $opt => $value) {
452
            curl_setopt($ch, $opt, $value);
453
        }
454
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
455
        curl_setopt($ch, CURLOPT_ENCODING, 'UTF-8');
456
        curl_setopt($ch, CURLOPT_URL, $url);
457
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
458
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
459
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeOut);
460
461
        // EXECUTE and RESULT
462
        $data     = curl_exec($ch);
463
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
464
465
        // ANALYSE
466
        if (false === $data) {
467
            throw new \RuntimeException('Unhandled curl error: ' . curl_error($ch));
468
        }
469
470
        if (is_bool($data)) {
471
            throw new \RuntimeException('Curl error: BOOL received, but STRING expected.');
472
        }
473
474
        if ($httpCode < 200 || $httpCode >= 300) {
475
            throw new BadResponseException('Bad response, HTTP code: ' . $httpCode);
476
        }
477
478
        // CLOSE AND UNSET
479
        curl_close($ch);
480
        unset($ch);
481
482
        // RETURN
483
        return $data;
484
    }
485
486
    /**
487
     * A private utility method used by other public methods to process XML responses.
488
     *
489
     * @throws BadResponseException|\Exception
490
     */
491
    private function processXmlResponse(string $url, string $payload = '', string $contentType = 'application/xml'): \SimpleXMLElement
492
    {
493
        return new \SimpleXMLElement($this->sendRequest($url, $payload, $contentType));
494
    }
495
496
    /**
497
     * A private utility method used by other public methods to process json responses.
498
     *
499
     * @throws BadResponseException
500
     */
501
    private function processJsonResponse(string $url, string $payload = '', string $contentType = 'application/json'): string
502
    {
503
        return $this->sendRequest($url, $payload, $contentType);
504
    }
505
}
506