Passed
Push — master ( 568ae1...ec0a70 )
by Ghazi
02:23 queued 15s
created

BigBlueButton::getInsertDocumentUrl()   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\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
    protected UrlBuilder $urlBuilder;
68
69
    /**
70
     * @var array<int, mixed>
71
     */
72
    protected array $curlOpts = [];
73
    protected int $timeOut    = 10;
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
     * Checks weather a meeting is existing.
230
     *
231
     * @throws BadResponseException
232
     */
233
    public function isMeetingExisting(string $meetingId): bool
234
    {
235
        $getMeetingInfoParameters = new GetMeetingInfoParameters($meetingId);
236
        $meetingInfoResponse      = $this->getMeetingInfo($getMeetingInfoParameters);
237
238
        return $meetingInfoResponse->success();
239
    }
240
241
    /**
242
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
243
     */
244
    public function getMeetingsUrl(): string
245
    {
246
        return $this->urlBuilder->getMeetingsUrl();
247
    }
248
249
    /**
250
     * @throws BadResponseException|\RuntimeException
251
     */
252
    public function getMeetings(): GetMeetingsResponse
253
    {
254
        $xml = $this->processXmlResponse($this->urlBuilder->getMeetingsUrl());
255
256
        return new GetMeetingsResponse($xml);
257
    }
258
259
    /**
260
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
261
     */
262
    public function getMeetingInfoUrl(GetMeetingInfoParameters $meetingParams): string
263
    {
264
        return $this->urlBuilder->getMeetingInfoUrl($meetingParams);
265
    }
266
267
    /**
268
     * @throws BadResponseException|\RuntimeException
269
     */
270
    public function getMeetingInfo(GetMeetingInfoParameters $meetingParams): GetMeetingInfoResponse
271
    {
272
        $xml = $this->processXmlResponse($this->urlBuilder->getMeetingInfoUrl($meetingParams));
273
274
        return new GetMeetingInfoResponse($xml);
275
    }
276
277
    // __________________ BBB RECORDING METHODS _________________
278
    /* The methods in the following section support the following categories of the BBB API:
279
    -- getRecordings
280
    -- publishRecordings
281
    -- deleteRecordings
282
    */
283
284
    /**
285
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
286
     */
287
    public function getRecordingsUrl(GetRecordingsParameters $recordingsParams): string
288
    {
289
        return $this->urlBuilder->getRecordingsUrl($recordingsParams);
290
    }
291
292
    /**
293
     * @param mixed $recordingParams
294
     *
295
     * @throws BadResponseException|\RuntimeException
296
     */
297
    public function getRecordings($recordingParams): GetRecordingsResponse
298
    {
299
        $xml = $this->processXmlResponse($this->urlBuilder->getRecordingsUrl($recordingParams));
300
301
        return new GetRecordingsResponse($xml);
302
    }
303
304
    /**
305
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
306
     */
307
    public function getPublishRecordingsUrl(PublishRecordingsParameters $recordingParams): string
308
    {
309
        return $this->urlBuilder->getPublishRecordingsUrl($recordingParams);
310
    }
311
312
    /**
313
     * @throws BadResponseException
314
     */
315
    public function publishRecordings(PublishRecordingsParameters $recordingParams): PublishRecordingsResponse
316
    {
317
        $xml = $this->processXmlResponse($this->urlBuilder->getPublishRecordingsUrl($recordingParams));
318
319
        return new PublishRecordingsResponse($xml);
320
    }
321
322
    /**
323
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
324
     */
325
    public function getDeleteRecordingsUrl(DeleteRecordingsParameters $recordingParams): string
326
    {
327
        return $this->urlBuilder->getDeleteRecordingsUrl($recordingParams);
328
    }
329
330
    /**
331
     * @throws BadResponseException|\RuntimeException
332
     */
333
    public function deleteRecordings(DeleteRecordingsParameters $recordingParams): DeleteRecordingsResponse
334
    {
335
        $xml = $this->processXmlResponse($this->urlBuilder->getDeleteRecordingsUrl($recordingParams));
336
337
        return new DeleteRecordingsResponse($xml);
338
    }
339
340
    /**
341
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
342
     */
343
    public function getUpdateRecordingsUrl(UpdateRecordingsParameters $recordingParams): string
344
    {
345
        return $this->urlBuilder->getUpdateRecordingsUrl($recordingParams);
346
    }
347
348
    /**
349
     * @throws BadResponseException|\RuntimeException
350
     */
351
    public function updateRecordings(UpdateRecordingsParameters $recordingParams): UpdateRecordingsResponse
352
    {
353
        $xml = $this->processXmlResponse($this->urlBuilder->getUpdateRecordingsUrl($recordingParams));
354
355
        return new UpdateRecordingsResponse($xml);
356
    }
357
358
    /**
359
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
360
     */
361
    public function getRecordingTextTracksUrl(GetRecordingTextTracksParameters $getRecordingTextTracksParameters): string
362
    {
363
        return $this->urlBuilder->getRecordingTextTracksUrl($getRecordingTextTracksParameters);
364
    }
365
366
    /**
367
     * @throws BadResponseException
368
     */
369
    public function getRecordingTextTracks(GetRecordingTextTracksParameters $getRecordingTextTracksParams): GetRecordingTextTracksResponse
370
    {
371
        $json = $this->processJsonResponse($this->urlBuilder->getRecordingTextTracksUrl($getRecordingTextTracksParams));
372
373
        return new GetRecordingTextTracksResponse($json);
374
    }
375
376
    /**
377
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
378
     */
379
    public function getPutRecordingTextTrackUrl(PutRecordingTextTrackParameters $putRecordingTextTrackParams): string
380
    {
381
        return $this->urlBuilder->getPutRecordingTextTrackUrl($putRecordingTextTrackParams);
382
    }
383
384
    /**
385
     * @throws BadResponseException
386
     */
387
    public function putRecordingTextTrack(PutRecordingTextTrackParameters $putRecordingTextTrackParams): PutRecordingTextTrackResponse
388
    {
389
        $json = $this->processJsonResponse($this->urlBuilder->getPutRecordingTextTrackUrl($putRecordingTextTrackParams));
390
391
        return new PutRecordingTextTrackResponse($json);
392
    }
393
394
    // ____________________ WEB HOOKS METHODS ___________________
395
396
    /**
397
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
398
     */
399
    public function getHooksCreateUrl(HooksCreateParameters $hookCreateParams): string
400
    {
401
        return $this->urlBuilder->getHooksCreateUrl($hookCreateParams);
402
    }
403
404
    /**
405
     * @param mixed $hookCreateParams
406
     *
407
     * @throws BadResponseException
408
     */
409
    public function hooksCreate($hookCreateParams): HooksCreateResponse
410
    {
411
        $xml = $this->processXmlResponse($this->urlBuilder->getHooksCreateUrl($hookCreateParams));
412
413
        return new HooksCreateResponse($xml);
414
    }
415
416
    /**
417
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
418
     */
419
    public function getHooksListUrl(): string
420
    {
421
        return $this->urlBuilder->getHooksListUrl();
422
    }
423
424
    /**
425
     * @throws BadResponseException
426
     */
427
    public function hooksList(): HooksListResponse
428
    {
429
        $xml = $this->processXmlResponse($this->urlBuilder->getHooksListUrl());
430
431
        return new HooksListResponse($xml);
432
    }
433
434
    /**
435
     * @deprecated Replaced by same function-name provided by UrlBuilder-class
436
     */
437
    public function getHooksDestroyUrl(HooksDestroyParameters $hooksDestroyParams): string
438
    {
439
        return $this->urlBuilder->getHooksDestroyUrl($hooksDestroyParams);
440
    }
441
442
    /**
443
     * @param mixed $hooksDestroyParams
444
     *
445
     * @throws BadResponseException
446
     */
447
    public function hooksDestroy($hooksDestroyParams): HooksDestroyResponse
448
    {
449
        $xml = $this->processXmlResponse($this->urlBuilder->getHooksDestroyUrl($hooksDestroyParams));
450
451
        return new HooksDestroyResponse($xml);
452
    }
453
454
    // ____________________ SPECIAL METHODS ___________________
455
456
    public function getJSessionId(): string
457
    {
458
        return $this->jSessionId;
459
    }
460
461
    public function setJSessionId(string $jSessionId): void
462
    {
463
        $this->jSessionId = $jSessionId;
464
    }
465
466
    /**
467
     * @param array<int, mixed> $curlOpts
468
     */
469
    public function setCurlOpts(array $curlOpts): void
470
    {
471
        $this->curlOpts = $curlOpts;
472
    }
473
474
    /**
475
     * Set Curl Timeout (Optional), Default 10 Seconds.
476
     */
477
    public function setTimeOut(int $TimeOutInSeconds): self
478
    {
479
        $this->timeOut = $TimeOutInSeconds;
480
481
        return $this;
482
    }
483
484
    /**
485
     * @deprecated Replaced by same function-name provided by UrlBuilder-BigBlueButton
486
     *
487
     * Public accessor for buildUrl.
488
     */
489
    public function buildUrl(string $method = '', string $params = '', bool $append = true): string
490
    {
491
        return $this->urlBuilder->buildUrl($method, $params, $append);
492
    }
493
494
    // ____________________ INTERNAL CLASS METHODS ___________________
495
496
    /**
497
     * A private utility method used by other public methods to request HTTP responses.
498
     *
499
     * @throws BadResponseException|\RuntimeException
500
     */
501
    private function sendRequest(string $url, string $payload = '', string $contentType = 'application/xml'): string
502
    {
503
        if (!extension_loaded('curl')) {
504
            throw new \RuntimeException('Post XML data set but curl PHP module is not installed or not enabled.');
505
        }
506
507
        $ch         = curl_init();
508
        $cookieFile = tmpfile();
509
510
        if (!$ch) {  // @phpstan-ignore-line
511
            throw new \RuntimeException('Unhandled curl error: ' . curl_error($ch));
512
        }
513
514
        // JSESSIONID
515
        if ($cookieFile) {
0 ignored issues
show
introduced by
$cookieFile is of type resource, thus it always evaluated to false.
Loading history...
516
            $cookieFilePath = stream_get_meta_data($cookieFile)['uri'];
517
            $cookies        = file_get_contents($cookieFilePath);
518
519
            curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFilePath);
520
            curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFilePath);
521
522
            if ($cookies) {
523
                if (false !== mb_strpos($cookies, 'JSESSIONID')) {
524
                    preg_match('/(?:JSESSIONID\s*)(?<JSESSIONID>.*)/', $cookies, $output_array);
525
                    $this->setJSessionId($output_array['JSESSIONID']);
526
                }
527
            }
528
        }
529
530
        // PAYLOAD
531
        if (!empty($payload)) {
532
            curl_setopt($ch, CURLOPT_HEADER, 0);
533
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
534
            curl_setopt($ch, CURLOPT_POST, 1);
535
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
536
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
537
                'Content-type: ' . $contentType,
538
                'Content-length: ' . mb_strlen($payload),
539
            ]);
540
        }
541
542
        // OTHERS
543
        foreach ($this->curlOpts as $opt => $value) {
544
            curl_setopt($ch, $opt, $value);
545
        }
546
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
547
        curl_setopt($ch, CURLOPT_ENCODING, 'UTF-8');
548
        curl_setopt($ch, CURLOPT_URL, $url);
549
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
550
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
551
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeOut);
552
553
        // EXECUTE and RESULT
554
        $data     = curl_exec($ch);
555
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
556
557
        // ANALYSE
558
        if (false === $data) {
559
            throw new \RuntimeException('Unhandled curl error: ' . curl_error($ch));
560
        }
561
562
        if (is_bool($data)) {
563
            throw new \RuntimeException('Curl error: BOOL received, but STRING expected.');
564
        }
565
566
        if ($httpCode < 200 || $httpCode >= 300) {
567
            throw new BadResponseException('Bad response, HTTP code: ' . $httpCode);
568
        }
569
570
        // CLOSE AND UNSET
571
        curl_close($ch);
572
        unset($ch);
573
574
        // RETURN
575
        return $data;
576
    }
577
578
    /**
579
     * A private utility method used by other public methods to process XML responses.
580
     *
581
     * @throws BadResponseException|\Exception
582
     */
583
    private function processXmlResponse(string $url, string $payload = ''): \SimpleXMLElement
584
    {
585
        $response = $this->sendRequest($url, $payload, $contentType);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $contentType seems to be never defined.
Loading history...
586
587
        return new \SimpleXMLElement($response);
588
    }
589
590
    /**
591
     * A private utility method used by other public methods to process json responses.
592
     *
593
     * @throws BadResponseException
594
     */
595
    private function processJsonResponse(string $url, string $payload = ''): string
596
    {
597
        return $this->sendRequest($url, $payload, 'application/json');
598
    }
599
}
600