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

littleredbutton / bigbluebutton-api-php / 6370630715

01 Oct 2023 12:39PM UTC coverage: 91.995% (-0.4%) from 92.44%
6370630715

Pull #158

github

web-flow
Merge 20ca055c8 into 7ea8e1342
Pull Request #158: Updated PHPUnit to version 9 (fixes #89)

1 of 1 new or added line in 1 file covered. (100.0%)

678 of 737 relevant lines covered (91.99%)

36.95 hits per line

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

62.5
/src/BigBlueButton.php
1
<?php
2
/**
3
 * BigBlueButton open source conferencing system - https://www.bigbluebutton.org/.
4
 *
5
 * Copyright (c) 2016-2018 BigBlueButton Inc. and by respective authors (see below).
6
 *
7
 * This program is free software; you can redistribute it and/or modify it under the
8
 * terms of the GNU Lesser General Public License as published by the Free Software
9
 * Foundation; either version 3.0 of the License, or (at your option) any later
10
 * version.
11
 *
12
 * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY
13
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
14
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public License along
17
 * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

20
namespace BigBlueButton;
21

22
use BigBlueButton\Core\ApiMethod;
23
use BigBlueButton\Exceptions\ConfigException;
24
use BigBlueButton\Exceptions\NetworkException;
25
use BigBlueButton\Exceptions\ParsingException;
26
use BigBlueButton\Exceptions\RuntimeException;
27
use BigBlueButton\Http\Transport\CurlTransport;
28
use BigBlueButton\Http\Transport\TransportInterface;
29
use BigBlueButton\Http\Transport\TransportRequest;
30
use BigBlueButton\Parameters\CreateMeetingParameters;
31
use BigBlueButton\Parameters\DeleteRecordingsParameters;
32
use BigBlueButton\Parameters\EndMeetingParameters;
33
use BigBlueButton\Parameters\GetMeetingInfoParameters;
34
use BigBlueButton\Parameters\GetRecordingsParameters;
35
use BigBlueButton\Parameters\GetRecordingTextTracksParameters;
36
use BigBlueButton\Parameters\HooksCreateParameters;
37
use BigBlueButton\Parameters\HooksDestroyParameters;
38
use BigBlueButton\Parameters\InsertDocumentParameters;
39
use BigBlueButton\Parameters\IsMeetingRunningParameters;
40
use BigBlueButton\Parameters\JoinMeetingParameters;
41
use BigBlueButton\Parameters\PublishRecordingsParameters;
42
use BigBlueButton\Parameters\PutRecordingTextTrackParameters;
43
use BigBlueButton\Parameters\UpdateRecordingsParameters;
44
use BigBlueButton\Responses\ApiVersionResponse;
45
use BigBlueButton\Responses\CreateMeetingResponse;
46
use BigBlueButton\Responses\DeleteRecordingsResponse;
47
use BigBlueButton\Responses\EndMeetingResponse;
48
use BigBlueButton\Responses\GetMeetingInfoResponse;
49
use BigBlueButton\Responses\GetMeetingsResponse;
50
use BigBlueButton\Responses\GetRecordingsResponse;
51
use BigBlueButton\Responses\GetRecordingTextTracksResponse;
52
use BigBlueButton\Responses\HooksCreateResponse;
53
use BigBlueButton\Responses\HooksDestroyResponse;
54
use BigBlueButton\Responses\HooksListResponse;
55
use BigBlueButton\Responses\InsertDocumentResponse;
56
use BigBlueButton\Responses\IsMeetingRunningResponse;
57
use BigBlueButton\Responses\JoinMeetingResponse;
58
use BigBlueButton\Responses\PublishRecordingsResponse;
59
use BigBlueButton\Responses\PutRecordingTextTrackResponse;
60
use BigBlueButton\Responses\UpdateRecordingsResponse;
61
use BigBlueButton\Util\UrlBuilder;
62

63
/**
64
 * Class BigBlueButton.
65
 *
66
 * @final since 4.0.
67
 */
68
class BigBlueButton
69
{
70
    public const CONNECTION_ERROR_BASEURL = 1;
71
    public const CONNECTION_ERROR_SECRET = 2;
72

73
    /**
74
     * @var string
75
     */
76
    protected $securitySecret;
77

78
    /**
79
     * @var string
80
     */
81
    protected $bbbServerBaseUrl;
82

83
    /**
84
     * @var UrlBuilder
85
     */
86
    protected $urlBuilder;
87

88
    /**
89
     * @var string|null
90
     */
91
    protected $jSessionId;
92

93
    /**
94
     * @var int|null
95
     */
96
    protected $connectionError;
97

98
    /**
99
     * @var TransportInterface
100
     */
101
    protected $transport;
102

103
    /**
104
     * @param string|null             $baseUrl   (optional) If not given, it will be retrieved from the environment
105
     * @param string|null             $secret    (optional) If not given, it will be retrieved from the environment
106
     * @param TransportInterface|null $transport (optional) Use a custom transport for all HTTP requests. Will fallback to default CurlTransport.
107
     *
108
     * @throws ConfigException
109
     */
110
    public function __construct(string $baseUrl = null, string $secret = null, TransportInterface $transport = null)
111
    {
112
        // Keeping backward compatibility with older deployed versions
113
        $this->securitySecret = $secret ?: getenv('BBB_SECURITY_SALT') ?: getenv('BBB_SECRET');
19✔
114
        $this->bbbServerBaseUrl = $baseUrl ?: getenv('BBB_SERVER_BASE_URL');
19✔
115

116
        if (empty($this->bbbServerBaseUrl)) {
19✔
117
            throw new ConfigException('Base url required');
1✔
118
        }
119

120
        $this->urlBuilder = new UrlBuilder($this->securitySecret, $this->bbbServerBaseUrl);
19✔
121
        $this->transport = $transport ?? CurlTransport::createWithDefaultOptions();
19✔
122
    }
123

124
    /**
125
     * @throws NetworkException
126
     * @throws ParsingException
127
     * @throws RuntimeException
128
     */
129
    public function getApiVersion(): ApiVersionResponse
130
    {
131
        $xml = $this->processXmlResponse($this->urlBuilder->buildUrl());
1✔
132

133
        return new ApiVersionResponse($xml);
1✔
134
    }
135

136
    /**
137
     * Check if connection to api can be established with the baseurl and secret.
138
     *
139
     * @return bool connection successful
140
     */
141
    public function isConnectionWorking(): bool
142
    {
143
        // Reset connection error
144
        $this->connectionError = null;
1✔
145

146
        try {
147
            $response = $this->isMeetingRunning(
1✔
148
                new IsMeetingRunningParameters('connection_check')
1✔
149
            );
1✔
150

151
            // url and secret working
152
            if ($response->success()) {
1✔
153
                return true;
1✔
154
            }
155

156
            // Checksum error - invalid secret
157
            if ($response->hasChecksumError()) {
1✔
158
                $this->connectionError = self::CONNECTION_ERROR_SECRET;
1✔
159

160
                return false;
1✔
161
            }
162

163
            // HTTP exception or XML parse
164
        } catch (\Exception $e) {
1✔
165
        }
166

167
        $this->connectionError = self::CONNECTION_ERROR_BASEURL;
1✔
168

169
        return false;
1✔
170
    }
171

172
    /**
173
     * Return connection error type.
174
     *
175
     * @return int|null Connection error (const CONNECTION_ERROR_BASEURL or CONNECTION_ERROR_SECRET)
176
     */
177
    public function getConnectionError(): ?int
178
    {
179
        return $this->connectionError;
1✔
180
    }
181

182
    /* __________________ BBB ADMINISTRATION METHODS _________________ */
183
    /* The methods in the following section support the following categories of the BBB API:
184
    -- create
185
    -- join
186
    -- end
187
    */
188

189
    public function getCreateMeetingUrl(CreateMeetingParameters $createMeetingParams): string
190
    {
191
        return $this->urlBuilder->buildUrl(ApiMethod::CREATE, $createMeetingParams->getHTTPQuery());
4✔
192
    }
193

194
    /**
195
     * @throws NetworkException
196
     * @throws ParsingException
197
     * @throws RuntimeException
198
     */
199
    public function createMeeting(CreateMeetingParameters $createMeetingParams): CreateMeetingResponse
200
    {
201
        $xml = $this->processXmlResponse($this->getCreateMeetingUrl($createMeetingParams), $createMeetingParams->getPresentationsAsXML());
3✔
202

203
        return new CreateMeetingResponse($xml);
1✔
204
    }
205

206
    public function getJoinMeetingURL(JoinMeetingParameters $joinMeetingParams): string
207
    {
208
        return $this->urlBuilder->buildUrl(ApiMethod::JOIN, $joinMeetingParams->getHTTPQuery());
2✔
209
    }
210

211
    /**
212
     * @throws NetworkException
213
     * @throws ParsingException
214
     * @throws RuntimeException
215
     */
216
    public function joinMeeting(JoinMeetingParameters $joinMeetingParams): JoinMeetingResponse
217
    {
218
        $xml = $this->processXmlResponse($this->getJoinMeetingURL($joinMeetingParams));
1✔
219

220
        return new JoinMeetingResponse($xml);
1✔
221
    }
222

223
    public function getEndMeetingURL(EndMeetingParameters $endParams): string
224
    {
225
        return $this->urlBuilder->buildUrl(ApiMethod::END, $endParams->getHTTPQuery());
2✔
226
    }
227

228
    /**
229
     * @throws NetworkException
230
     * @throws ParsingException
231
     * @throws RuntimeException
232
     */
233
    public function endMeeting(EndMeetingParameters $endParams): EndMeetingResponse
234
    {
235
        $xml = $this->processXmlResponse($this->getEndMeetingURL($endParams));
1✔
236

237
        return new EndMeetingResponse($xml);
1✔
238
    }
239

240
    public function getIsMeetingRunningUrl(IsMeetingRunningParameters $meetingParams): string
241
    {
242
        return $this->urlBuilder->buildUrl(ApiMethod::IS_MEETING_RUNNING, $meetingParams->getHTTPQuery());
1✔
243
    }
244

245
    /**
246
     * @throws NetworkException
247
     * @throws ParsingException
248
     * @throws RuntimeException
249
     */
250
    public function isMeetingRunning(IsMeetingRunningParameters $meetingParams): IsMeetingRunningResponse
251
    {
252
        $xml = $this->processXmlResponse($this->getIsMeetingRunningUrl($meetingParams));
1✔
253

254
        return new IsMeetingRunningResponse($xml);
1✔
255
    }
256

257
    public function getMeetingsUrl(): string
258
    {
259
        return $this->urlBuilder->buildUrl(ApiMethod::GET_MEETINGS);
2✔
260
    }
261

262
    /**
263
     * @throws NetworkException
264
     * @throws ParsingException
265
     * @throws RuntimeException
266
     */
267
    public function getMeetings(): GetMeetingsResponse
268
    {
269
        $xml = $this->processXmlResponse($this->getMeetingsUrl());
1✔
270

271
        return new GetMeetingsResponse($xml);
1✔
272
    }
273

274
    public function getMeetingInfoUrl(GetMeetingInfoParameters $meetingParams): string
275
    {
276
        return $this->urlBuilder->buildUrl(ApiMethod::GET_MEETING_INFO, $meetingParams->getHTTPQuery());
×
277
    }
278

279
    /**
280
     * @throws NetworkException
281
     * @throws ParsingException
282
     * @throws RuntimeException
283
     */
284
    public function getMeetingInfo(GetMeetingInfoParameters $meetingParams): GetMeetingInfoResponse
285
    {
286
        $xml = $this->processXmlResponse($this->getMeetingInfoUrl($meetingParams));
×
287

288
        return new GetMeetingInfoResponse($xml);
×
289
    }
290

291
    public function getRecordingsUrl(GetRecordingsParameters $recordingsParams): string
292
    {
293
        return $this->urlBuilder->buildUrl(ApiMethod::GET_RECORDINGS, $recordingsParams->getHTTPQuery());
1✔
294
    }
295

296
    /**
297
     * @throws NetworkException
298
     * @throws ParsingException
299
     * @throws RuntimeException
300
     */
301
    public function getRecordings(GetRecordingsParameters $recordingParams): GetRecordingsResponse
302
    {
303
        $xml = $this->processXmlResponse($this->getRecordingsUrl($recordingParams));
×
304

305
        return new GetRecordingsResponse($xml);
×
306
    }
307

308
    public function getPublishRecordingsUrl(PublishRecordingsParameters $recordingParams): string
309
    {
310
        return $this->urlBuilder->buildUrl(ApiMethod::PUBLISH_RECORDINGS, $recordingParams->getHTTPQuery());
1✔
311
    }
312

313
    /**
314
     * @throws NetworkException
315
     * @throws ParsingException
316
     * @throws RuntimeException
317
     */
318
    public function publishRecordings(PublishRecordingsParameters $recordingParams): PublishRecordingsResponse
319
    {
320
        $xml = $this->processXmlResponse($this->getPublishRecordingsUrl($recordingParams));
×
321

322
        return new PublishRecordingsResponse($xml);
×
323
    }
324

325
    public function getDeleteRecordingsUrl(DeleteRecordingsParameters $recordingParams): string
326
    {
327
        return $this->urlBuilder->buildUrl(ApiMethod::DELETE_RECORDINGS, $recordingParams->getHTTPQuery());
1✔
328
    }
329

330
    /**
331
     * @throws NetworkException
332
     * @throws ParsingException
333
     * @throws RuntimeException
334
     */
335
    public function deleteRecordings(DeleteRecordingsParameters $recordingParams): DeleteRecordingsResponse
336
    {
337
        $xml = $this->processXmlResponse($this->getDeleteRecordingsUrl($recordingParams));
×
338

339
        return new DeleteRecordingsResponse($xml);
×
340
    }
341

342
    public function getUpdateRecordingsUrl(UpdateRecordingsParameters $recordingParams): string
343
    {
344
        return $this->urlBuilder->buildUrl(ApiMethod::UPDATE_RECORDINGS, $recordingParams->getHTTPQuery());
1✔
345
    }
346

347
    /**
348
     * @throws NetworkException
349
     * @throws ParsingException
350
     * @throws RuntimeException
351
     */
352
    public function updateRecordings(UpdateRecordingsParameters $recordingParams): UpdateRecordingsResponse
353
    {
354
        $xml = $this->processXmlResponse($this->getUpdateRecordingsUrl($recordingParams));
×
355

356
        return new UpdateRecordingsResponse($xml);
×
357
    }
358

359
    public function getRecordingTextTracksUrl(GetRecordingTextTracksParameters $getRecordingTextTracksParams): string
360
    {
361
        return $this->urlBuilder->buildUrl(ApiMethod::GET_RECORDING_TEXT_TRACKS, $getRecordingTextTracksParams->getHTTPQuery());
×
362
    }
363

364
    /**
365
     * @throws NetworkException
366
     * @throws RuntimeException
367
     */
368
    public function getRecordingTextTracks(GetRecordingTextTracksParameters $getRecordingTextTracksParams): GetRecordingTextTracksResponse
369
    {
370
        return new GetRecordingTextTracksResponse(
×
371
            $this->processJsonResponse($this->getRecordingTextTracksUrl($getRecordingTextTracksParams))
×
372
        );
×
373
    }
374

375
    public function getPutRecordingTextTrackUrl(PutRecordingTextTrackParameters $putRecordingTextTrackParams): string
376
    {
377
        return $this->urlBuilder->buildUrl(ApiMethod::PUT_RECORDING_TEXT_TRACK, $putRecordingTextTrackParams->getHTTPQuery());
×
378
    }
379

380
    /**
381
     * @throws NetworkException
382
     * @throws RuntimeException
383
     */
384
    public function putRecordingTextTrack(PutRecordingTextTrackParameters $putRecordingTextTrackParams): PutRecordingTextTrackResponse
385
    {
386
        $url = $this->getPutRecordingTextTrackUrl($putRecordingTextTrackParams);
×
387
        $file = $putRecordingTextTrackParams->getFile();
×
388

389
        return new PutRecordingTextTrackResponse(
×
390
            $file === null ?
×
391
                $this->processJsonResponse($url) :
×
392
                $this->processJsonResponse($url, $file, $putRecordingTextTrackParams->getContentType())
×
393
        );
×
394
    }
395

396
    public function getHooksCreateUrl(HooksCreateParameters $hookCreateParams): string
397
    {
398
        return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_CREATE, $hookCreateParams->getHTTPQuery());
×
399
    }
400

401
    /**
402
     * @throws NetworkException
403
     * @throws RuntimeException
404
     * @throws ParsingException
405
     */
406
    public function hooksCreate(HooksCreateParameters $hookCreateParams): HooksCreateResponse
407
    {
408
        $xml = $this->processXmlResponse($this->getHooksCreateUrl($hookCreateParams));
×
409

410
        return new HooksCreateResponse($xml);
×
411
    }
412

413
    public function getHooksListUrl(): string
414
    {
415
        return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_LIST);
×
416
    }
417

418
    public function hooksList(): HooksListResponse
419
    {
420
        $xml = $this->processXmlResponse($this->getHooksListUrl());
×
421

422
        return new HooksListResponse($xml);
×
423
    }
424

425
    public function getHooksDestroyUrl(HooksDestroyParameters $hooksDestroyParams): string
426
    {
427
        return $this->urlBuilder->buildUrl(ApiMethod::HOOKS_DESTROY, $hooksDestroyParams->getHTTPQuery());
×
428
    }
429

430
    /**
431
     * @throws NetworkException
432
     * @throws RuntimeException
433
     * @throws ParsingException
434
     */
435
    public function hooksDestroy(HooksDestroyParameters $hooksDestroyParams): HooksDestroyResponse
436
    {
437
        $xml = $this->processXmlResponse($this->getHooksDestroyUrl($hooksDestroyParams));
×
438

439
        return new HooksDestroyResponse($xml);
×
440
    }
441

442
    public function getInsertDocumentUrl(InsertDocumentParameters $insertDocumentParams): string
443
    {
444
        return $this->urlBuilder->buildUrl(ApiMethod::INSERT_DOCUMENT, $insertDocumentParams->getHTTPQuery());
1✔
445
    }
446

447
    /**
448
     * @throws NetworkException
449
     * @throws ParsingException
450
     * @throws RuntimeException
451
     */
452
    public function insertDocument(InsertDocumentParameters $insertDocumentParams): InsertDocumentResponse
453
    {
454
        $xml = $this->processXmlResponse($this->getInsertDocumentUrl($insertDocumentParams), $insertDocumentParams->getPresentationsAsXML());
1✔
455

456
        return new InsertDocumentResponse($xml);
1✔
457
    }
458

459
    /* ____________________ SPECIAL METHODS ___________________ */
460

461
    public function getJSessionId(): ?string
462
    {
463
        return $this->jSessionId;
1✔
464
    }
465

466
    public function setJSessionId(string $jSessionId): void
467
    {
468
        $this->jSessionId = $jSessionId;
1✔
469
    }
470

471
    /* ____________________ INTERNAL CLASS METHODS ___________________ */
472

473
    /**
474
     * A private utility method used by other public methods to process XML responses.
475
     *
476
     * @throws NetworkException
477
     * @throws ParsingException
478
     * @throws RuntimeException
479
     */
480
    private function processXmlResponse(string $url, string $payload = '', string $contentType = 'application/xml'): \SimpleXMLElement
481
    {
482
        try {
483
            return new \SimpleXMLElement($this->requestUrl($url, $payload, $contentType));
9✔
484
        } catch (NetworkException|RuntimeException $e) {
3✔
485
            throw $e;
1✔
486
        } catch (\Throwable $e) {
2✔
487
            throw new ParsingException('Could not parse payload as XML', 0, $e);
2✔
488
        }
489
    }
490

491
    /**
492
     * A private utility method used by other public methods to process json responses.
493
     *
494
     * @throws RuntimeException|NetworkException
495
     */
496
    private function processJsonResponse(string $url, string $payload = '', string $contentType = 'application/json'): string
497
    {
498
        return $this->requestUrl($url, $payload, $contentType);
×
499
    }
500

501
    /**
502
     * A private utility method used by other public methods to request from the api.
503
     *
504
     * @return string Response body
505
     *
506
     * @throws RuntimeException|NetworkException
507
     */
508
    private function requestUrl(string $url, string $payload = '', string $contentType = 'application/xml'): string
509
    {
510
        $response = $this->transport->request(new TransportRequest($url, $payload, $contentType));
9✔
511

512
        if (null !== $sessionId = $response->getSessionId()) {
8✔
513
            $this->setJSessionId($sessionId);
1✔
514
        }
515

516
        return $response->getBody();
8✔
517
    }
518

519
    public function buildUrl(string $method = '', string $params = '', bool $append = true): string
520
    {
521
        return $this->urlBuilder->buildUrl($method, $params, $append);
1✔
522
    }
523
}
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