This repository has been archived by the owner on Dec 17, 2021. It is now read-only.
forked from leoken/plivohelper-php
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plivohelper.php
992 lines (856 loc) · 34.3 KB
/
plivohelper.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
<?php
// VERSION: 0.1
// Plivo REST Helpers
// ========================================================================
// ensure Curl is installed
if(!extension_loaded("curl"))
throw(new Exception(
"Curl extension is required for PlivoRestClient to work"));
/*
* PlivoRestResponse holds all the REST response data
* Before using the reponse, check IsError to see if an exception
* occurred with the data sent to Plivo
* ResponseJson contains the raw json response
* Url and QueryString are from the request
* HttpStatus is the response code of the request
*/
class PlivoRestResponse {
public $ResponseJson;
public $Response;
public $HttpStatus;
public $Url;
public $QueryString;
public $IsError;
public $ErrorMessage;
public function __construct($url, $text, $status) {
preg_match('/([^?]+)\??(.*)/', $url, $matches);
$this->Url = $matches[1];
$this->QueryString = $matches[2];
$this->ResponseJson = $text;
$this->HttpStatus = $status;
if($this->HttpStatus != 204)
$this->Response = @json_decode($text);
if($this->IsError = ($status >= 400)) {
if($status == 401) {
$this->ErrorMessage = "Authentication required";
} else {
$this->ErrorMessage =
(string)$this->Response->Message;
}
}
}
}
/* PlivoRestClient throws PlivoException on error
* Useful to catch this exception separately from general PHP
* exceptions, if you want
*/
class PlivoException extends Exception {}
/*
* PlivoRestBaseClient: the core Rest client, talks to the Plivo REST
* API. Returns a PlivoRestResponse object for all responses if Plivo's
* API was reachable Throws a PlivoException if Plivo's REST API was
* unreachable
*/
class PlivoRestClient {
protected $Endpoint;
protected $AccountSid;
protected $AuthToken;
protected $ApiVersion;
/*
* __construct
* $username : Plivo Sid
* $password : Plivo AuthToken
* $endpoint : The Plivo REST URL
* $ApiVersion : The API version
*/
public function __construct($endpoint, $accountSid, $authToken, $ApiVersion = 'v0.1') {
$this->AccountSid = $accountSid;
$this->AuthToken = $authToken;
$this->Endpoint = $endpoint;
$this->ApiVersion = $ApiVersion;
}
/*
* sendRequst
* Sends a REST Request to the Plivo REST API
* $path : the URL (relative to the endpoint URL, after the /v1)
* $method : the HTTP method to use, defaults to GET
* $vars : for POST or PUT, a key/value associative array of data to
* send, for GET will be appended to the URL as query params
*/
public function request($path, $method = "GET", $vars = array()) {
$fp = null;
$tmpfile = "";
$encoded = "";
foreach($vars AS $key=>$value)
$encoded .= "$key=".urlencode($value)."&";
$encoded = substr($encoded, 0, -1);
// construct full url
$url = "{$this->Endpoint}/$path";
// if GET and vars, append them
if($method == "GET")
$url .= (FALSE === strpos($path, '?')?"?":"&").$encoded;
// initialize a new curl object
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
switch(strtoupper($method)) {
case "GET":
curl_setopt($curl, CURLOPT_HTTPGET, TRUE);
break;
case "POST":
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $encoded);
break;
case "PUT":
// curl_setopt($curl, CURLOPT_PUT, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $encoded);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "PUT");
file_put_contents($tmpfile = tempnam("/tmp", "put_"),
$encoded);
curl_setopt($curl, CURLOPT_INFILE, $fp = fopen($tmpfile,
'r'));
curl_setopt($curl, CURLOPT_INFILESIZE,
filesize($tmpfile));
break;
case "DELETE":
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
break;
default:
throw(new PlivoException("Unknown method $method"));
break;
}
// send credentials
curl_setopt($curl, CURLOPT_USERPWD,
$pwd = "{$this->AccountSid}:{$this->AuthToken}");
// do the request. If FALSE, then an exception occurred
if(FALSE === ($result = curl_exec($curl)))
throw(new PlivoException(
"Curl failed with error " . curl_error($curl)));
// get result code
$responseCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
// unlink tmpfiles
if($fp)
fclose($fp);
if(strlen($tmpfile))
unlink($tmpfile);
return new PlivoRestResponse($url, $result, $responseCode);
}
// REST Reload Plivo Config Helper
public function reload_config($vars = array()) {
$path = "$this->ApiVersion/ReloadConfig/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Reload Plivo Cache Config Helper
public function reload_cache_config($vars = array()) {
$path = "$this->ApiVersion/ReloadCacheConfig/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Call Helper
public function call($vars = array()) {
$path = "$this->ApiVersion/Call/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Bulk Call Helper
public function bulk_call($vars = array()) {
$path = "$this->ApiVersion/BulkCall/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Group Call Helper
public function group_call($vars = array()) {
$path = "$this->ApiVersion/GroupCall/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Transfer Live Call Helper
public function transfer_call($vars = array()) {
$path = "$this->ApiVersion/TransferCall/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Hangup All Live Calls Helper
public function hangup_all_calls() {
$path = "$this->ApiVersion/HangupAllCalls/";
$method = "POST";
return $this->request($path, $method);
}
// REST Hangup Live Call Helper
public function hangup_call($vars = array()) {
$path = "$this->ApiVersion/HangupCall/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Schedule Hangup Helper
public function schedule_hangup($vars = array()) {
$path = "$this->ApiVersion/ScheduleHangup/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Cancel a Scheduled Hangup Helper
public function cancel_scheduled_hangup($vars = array()) {
$path = "$this->ApiVersion/CancelScheduledHangup/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST RecordStart helper
public function record_start($vars = array()) {
$path = "$this->ApiVersion/RecordStart/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST RecordStop
public function record_stop($vars = array()) {
$path = "$this->ApiVersion/RecordStop/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Play something on a Call Helper
public function play($vars = array()) {
$path = "$this->ApiVersion/Play/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST PlayStop something on a Call Helper
public function play_stop($vars = array()) {
$path = "$this->ApiVersion/PlayStop/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Schedule Play Helper
public function schedule_play($vars = array()) {
$path = "$this->ApiVersion/SchedulePlay/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Cancel a Scheduled Play Helper
public function cancel_scheduled_play($vars = array()) {
$path = "$this->ApiVersion/CancelScheduledPlay/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Add soundtouch audio effects to a Call Helper
public function sound_touch($vars = array()) {
$path = "$this->ApiVersion/SoundTouch/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Remove soundtouch audio effects on a Call Helper
public function sound_touch_stop($vars = array()) {
$path = "$this->ApiVersion/SoundTouchStop/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Send digits to a Call Helper
public function send_digits($vars = array()) {
$path = "$this->ApiVersion/SendDigits/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Mute helper
public function conference_mute($vars = array()) {
$path = "$this->ApiVersion/ConferenceMute/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Unmute helper
public function conference_unmute($vars = array()) {
$path = "$this->ApiVersion/ConferenceUnmute/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Kick helper
public function conference_kick($vars = array()) {
$path = "$this->ApiVersion/ConferenceKick/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Hangup helper
public function conference_hangup($vars = array()) {
$path = "$this->ApiVersion/ConferenceHangup/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Deaf helper
public function conference_deaf($vars = array()) {
$path = "$this->ApiVersion/ConferenceDeaf/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Undeaf helper
public function conference_undeaf($vars = array()) {
$path = "$this->ApiVersion/ConferenceUndeaf/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference RecordStart helper
public function conference_record_start($vars = array()) {
$path = "$this->ApiVersion/ConferenceRecordStart/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference RecordStop
public function conference_record_stop($vars = array()) {
$path = "$this->ApiVersion/ConferenceRecordStop/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Play helper
public function conference_play($vars = array()) {
$path = "$this->ApiVersion/ConferencePlay/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference Speak helper
public function conference_speak($vars = array()) {
$path = "$this->ApiVersion/ConferenceSpeak/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference List Helper
public function conference_list($vars = array()) {
$path = "$this->ApiVersion/ConferenceList/";
$method = "POST";
return $this->request($path, $method, $vars);
}
// REST Conference List Members Helper
public function conference_list_members($vars = array()) {
$path = "$this->ApiVersion/ConferenceListMembers/";
$method = "POST";
return $this->request($path, $method, $vars);
}
}
// RESTXML Response Helpers
// ========================================================================
/*
* Element: Base class for all RESTXML element elements used in creating Responses
* Throws a PlivoException if an non-supported attribute or
* attribute value is added to the element. All methods in Element are protected
* or private
*/
class Element {
private $tag;
private $body;
private $attr;
private $children;
/*
* __construct
* $body : Element contents
* $body : Element attributes
*/
function __construct($body=NULL, $attr = array()) {
if (is_array($body)) {
$attr = $body;
$body = NULL;
}
$this->tag = get_class($this);
$this->body = $body;
$this->attr = array();
$this->children = array();
self::addAttributes($attr);
}
/*
* addAttributes
* $attr : A key/value array of attributes to be added
* $valid : A key/value array containging the accepted attributes
* for this element
* Throws an exception if an invlaid attribute is found
*/
private function addAttributes($attr) {
foreach ($attr as $key => $value) {
if(in_array($key, $this->valid))
$this->attr[$key] = $value;
else
throw new PlivoException($key . ', ' . $value .
" is not a supported attribute pair");
}
}
/*
* append
* Nests other element elements inside self.
*/
function append($element) {
if (!isset($this->nesting) or is_null($this->nesting))
throw new PlivoException($this->tag ." doesn't support nesting");
else if(!is_object($element))
throw new PlivoException($element->tag . " is not an object");
else if(!in_array(get_class($element), $this->nesting))
throw new PlivoException($element->tag . " is not an allowed element here");
else {
$this->children[] = $element;
return $element;
}
}
/*
* set
* $attr : An attribute to be added
* $valid : The attrbute value for this element
* No error checking here
*/
function set($key, $value){
$this->attr[$key] = $value;
}
/* Convenience Methods */
function addSpeak($body=NULL, $attr = array()){
return self::append(new Speak($body, $attr));
}
function addPlay($body=NULL, $attr = array()){
return self::append(new Play($body, $attr));
}
function addDial($body=NULL, $attr = array()){
return self::append(new Dial($body, $attr));
}
function addNumber($body=NULL, $attr = array()){
return self::append(new Number($body, $attr));
}
function addGetDigits($attr = array()){
return self::append(new GetDigits($attr));
}
function addGetSpeech($attr = array()){
return self::append(new GetSpeech($attr));
}
function addRecord($attr = array()){
return self::append(new Record($attr));
}
function addHangup($attr = array()){
return self::append(new Hangup($attr));
}
function addRedirect($body=NULL, $attr = array()){
return self::append(new Redirect($body, $attr));
}
function addSIPTransfer($body=NULL, $attr = array()){
return self::append(new SIPTransfer($body, $attr));
}
function addWait($attr = array()){
return self::append(new Wait($attr));
}
function addConference($body=NULL, $attr = array()){
return self::append(new Conference($body, $attr));
}
function addPreAnswer($attr = array()){
return self::append(new PreAnswer(NULL, $attr));
}
/*
* write
* Output the XML for this element and all it's children
* $parent: This element's parent element
* $writeself : If FALSE, Element will not output itself,
* only its children
*/
protected function write($parent, $writeself=TRUE){
if($writeself) {
$elem = $parent->addChild($this->tag, htmlspecialchars($this->body));
foreach($this->attr as $key => $value)
$elem->addAttribute($key, $value);
foreach($this->children as $child)
$child->write($elem);
} else {
foreach($this->children as $child)
$child->write($parent);
}
}
}
class Response extends Element {
private $xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response></Response>";
protected $nesting = array('Speak', 'Play', 'GetDigits', 'Record',
'Dial', 'Redirect', 'Wait', 'Hangup', 'PreAnswer', 'Conference', 'GetSpeech', 'SIPTransfer');
function __construct(){
parent::__construct(NULL);
}
function Respond($sendHeader = true) {
// try to force the xml data type
// this is generally unneeded by Plivo, but nice to have
if($sendHeader)
{
if(!headers_sent())
{
header("Content-type: text/xml");
}
}
$simplexml = new SimpleXMLElement($this->xml);
$this->write($simplexml, FALSE);
print $simplexml->asXML();
}
function asURL($encode = TRUE){
$simplexml = new SimpleXMLElement($this->xml);
$this->write($simplexml, FALSE);
if($encode)
return urlencode($simplexml->asXML());
else
return $simplexml->asXML();
}
}
/**
* The <Speak> element converts text to speech that is read back to the caller.
* <Speak> is useful for development or saying dynamic text that is difficult to pre-record.
*/
class Speak extends Element {
protected $valid = array('voice','language','loop', 'engine', 'method', 'type');
/**
* Speak Constructor
*
* Instatiates a new Speak object with text and optional attributes.
* Possible attributes are:
* "voice" => 'man'|'woman',
* "language" => 'en'|'es'|'fr'|'de',
* "loop" => integer >= 0
*
* @param string $text
* @param array $attr Optional attributes
* @return Speak
*/
function __construct($text='', $attr = array()) {
parent::__construct($text, $attr);
}
}
/**
* The <Play> element plays an audio file back to the caller.
* Plivo retrieves the file from a URL that you provide.
*/
class Play extends Element {
protected $valid = array('loop');
/**
* Play Constructor
*
* Instatiates a new Play object with a URL and optional attributes.
* Possible attributes are:
* "loop" => integer >= 0
*
* @param string $url The URL of an audio file that Plivo will retrieve and play to the caller.
* @param array $attr Optional attributes
* @return Play
*/
function __construct($url='', $attr = array()) {
parent::__construct($url, $attr);
}
}
/**
* The <Record> element records the caller's voice and returns to you the URL
* of a file containing the audio recording. You can optionally generate
* text transcriptions of recorded calls by setting the 'transcribe'
* attribute of the <Record> element to 'true'.
*/
class Record extends Element {
protected $valid = array('action', 'method', 'timeout','finishOnKey',
'maxLength', 'bothLegs', 'playBeep',
'fileFormat', 'filePath', 'fileName');
/**
* Record Constructor
*
* Instatiates a new Record object with optional attributes.
* Possible attributes are:
* "action" => absolute url,
* "method" => 'GET'|'POST', (default: POST)
* "timeout" => positive integer, (default: 5)
* "finishOnKey" => any digit, #, * (default: 1234567890*#)
* "maxLength" => integer >= 1, (default: 3600, 1hr)
* "playBeep" => true|false, (default: true)
*
* @param array $attr Optional attributes
* @return Record
*/
function __construct($attr = array()) {
parent::__construct($attr);
}
}
/**
* The <Dial> element connects the current caller to an another phone.
* If the called party picks up, the two parties are connected and can
* communicate until one hangs up. If the called party does not pick up,
* if a busy signal is received, or if the number doesn't exist,
* the dial element will finish.
*
* When the dialed call ends, Plivo makes a GET or POST request to
* the 'action' URL if provided. Call flow will continue using
* the RESTXML received in response to that request.
*/
class Dial extends Element {
protected $valid = array('action','method','timeout','hangupOnStar',
'timeLimit', 'callerId', 'callerName', 'confirmSound', 'dialMusic', 'confirmKey', 'redirect',
'callbackUrl', 'callbackMethod', 'digitsMatch');
protected $nesting = array('Number');
/**
* Dial Constructor
*
* Instatiates a new Dial object with a number and optional attributes.
* Possible attributes are:
* "action" => absolute url
* "method" => 'GET'|'POST', (default: POST)
* "timeout" => positive integer, (default: 30)
* "hangupOnStar" => true|false, (default: false)
* "timeLimit" => integer >= 0, (default: 14400, 4hrs)
* "callerId" => valid phone #, (default: Caller's callerid)
* "redirect" => true|false, if 'false', don't redirect to 'action', only request url
* and continue to next element. (default 'true')
*
* @param string|Number|Conference $number The number or conference you wish to call
* @param array $attr Optional attributes
* @return Dial
*/
function __construct($number='', $attr = array()) {
parent::__construct($number, $attr);
}
}
/**
* The <Redirect> element transfers control of a call to the RESTXML at a
* different URL. All element elements after <Redirect> are unreachable and ignored.
*/
class Redirect extends Element {
protected $valid = array('method');
/**
* Redirect Constructor
*
* Instatiates a new Redirect object with text and optional attributes.
* Possible attributes are:
* "method" => 'GET'|'POST', (default: POST)
*
* @param string $url An absolute or relative URL for a different RESTXML document.
* @param array $attr Optional attributes
* @return Redirect
*/
function __construct($url='', $attr = array()) {
parent::__construct($url, $attr);
}
}
/**
* The <SIPTransfer> element transfers a sip call.
*/
class SIPTransfer extends Element {
protected $valid = array();
/**
* SIPTransfer Constructor
*
* Instatiates a new SIPTransfer object with text and optional attributes.
* @param string $url An absolute or relative URL for a different RESTXML document.
* @return SIPTransfer
*/
function __construct($url='', $attr = array()) {
parent::__construct($url, $attr);
}
}
/**
* The <Wait> element waits silently for a specific number of seconds.
* If <Wait> is the first element in a RESTXML document, Plivo will wait
* the specified number of seconds before picking up the call.
*/
class Wait extends Element {
protected $valid = array('length');
/**
* Wait Constructor
*
* Instatiates a new Wait object with text and optional attributes.
* Possible attributes are:
* "length" => integer > 0, (default: 1)
*
* @param array $attr Optional attributes
* @return Wait
*/
function __construct($attr = array()) {
parent::__construct(NULL, $attr);
}
}
/**
* The <Hangup> element ends a call. If used as the first element in a RESTXML
* response it does not prevent Plivo from answering the call and billing
* your account. The only way to not answer a call and prevent billing
* is to use the <Reject> element.
*/
class Hangup extends Element {
protected $valid = array('reason', 'schedule');
/**
* Hangup Constructor
*
* Instatiates a new Hangup object object with optional attributes.
* Possible attributes are:
* "reason" => 'rejected'|'busy'
* "schedule" => '25'
*
* @return Hangup
*/
function __construct($attr = array()) {
parent::__construct(NULL, $attr);
}
}
/**
* The <GetDigits> element collects digits that a caller enters into his or her
* telephone keypad. When the caller is done entering data, Plivo submits
* that data to the provided 'action' URL in an HTTP GET or POST request,
* just like a web browser submits data from an HTML form.
* If no input is received before timeout, <GetDigits> falls through to the
* next element in the RESTXML document.
*
* You may optionally nest <Speak> and <Play> within a <GetDigits> element while
* waiting for input. This allows you to read menu options to the caller
* while letting her enter a menu selection at any time. After the first
* digit is received the audio will stop playing.
*/
class GetDigits extends Element {
protected $valid = array('action','method','timeout','finishOnKey',
'numDigits', 'retries', 'invalidDigitsSound', 'validDigits', 'playBeep');
protected $nesting = array('Speak', 'Play', 'Wait');
/**
* GetDigits Constructor
*
* Instatiates a new GetDigits object with optional attributes.
* Possible attributes are:
* "action" => absolute url
* "method" => 'GET'|'POST', (default: POST)
* "timeout" => positive integer, (default: 5)
* "finishOnKey" => any digit, #, *, (default: #)
* "numDigits" => integer >= 1 (default: unlimited)
*
* @param array $attr Optional attributes
* @return GetDigits
*/
function __construct($attr = array()){
parent::__construct(NULL, $attr);
}
}
/**
* The <Dial> element's <Number> noun specifies a phone number to dial.
* Using the noun's attributes you can specify particular behaviors
* that Plivo should apply when dialing the number.
*
* You can use multiple <Number> nouns within a <Dial> element to simultaneously
* call all of them at once. The first call to pick up is connected
* to the current call and the rest are hung up.
*/
class Number extends Element {
protected $valid = array('sendDigits', 'sendOnPreanswer', 'gateways', 'gatewayCodecs',
'gatewayTimeouts', 'gatewayRetries', 'extraDialString');
/**
* Number Constructor
*
* Instatiates a new Number object with optional attributes.
* Possible attributes are:
* "sendDigits" => any digits
*
* @param string $number Number you wish to dial
* @param array $attr Optional attributes
* @return Number
*/
function __construct($number = '', $attr = array()){
parent::__construct($number, $attr);
}
}
/**
* The <Dial> element's <Conference> noun allows you to connect to a conference
* room. Much like how the <Number> noun allows you to connect to another
* phone number, the <Conference> noun allows you to connect to a named
* conference room and talk with the other callers who have also connected
* to that room.
*
* The name of the room is up to you and is namespaced to your account.
* This means that any caller who joins 'room1234' via your account will
* end up in the same conference room, but callers connecting through
* different accounts would not. The maximum number of participants in a
* single Plivo conference room is 40.
*/
class Conference extends Element {
protected $valid = array('muted','beep','startConferenceOnEnter',
'endConferenceOnExit','waitSound','enterSound', 'exitSound',
'timeLimit', 'hangupOnStar', 'maxMembers', 'recordFilePath',
'recordFileFormat', 'recordFileName', 'action', 'method',
'callbackUrl', 'callbackMethod', 'digitsMatch',
'floorEvent', 'stayAlone');
/**
* Conference Constructor
*
* Instatiates a new Conference object with room and optional attributes.
* Possible attributes are:
* waitSound: sound to play while alone in conference
* (default no sound)
* muted: enter conference muted
* (default false)
* startConferenceOnEnter: the conference start when this member joins
* (default true)
* endConferenceOnExit: close conference after this member leaves
* (default false)
* maxMembers: max members in conference
* (0 for max : 200)
* enterSound: if "", disabled
* if beep:1, play one beep when a member enters
* if beep:2 play two beeps when a member enters
* (default "")
* exitSound: if "", disabled
* if beep:1, play one beep when a member exits
* if beep:2 play two beeps when a member exits
* (default "")
* timeLimit: max time before closing conference
* (default 14400 seconds)
* hangupOnStar: exit conference when member press '*'
* (default false)
* action: redirect to this URL after leaving conference
* method: submit to 'action' url using GET or POST
* callbackUrl: url to request when call enters/leaves conference
or has pressed digits matching (digitsMatch)
* callbackMethod: submit to 'callbackUrl' url using GET or POST
* digitsMatch: a list of matching digits to send with callbackUrl
Can be a list of digits patterns separated by comma.
*
* @param string $room Conference room to join
* @param array $attr Optional attributes
* @return Conference
*/
function __construct($room = '', $attr = array()){
parent::__construct($room, $attr);
}
}
/**
* The <GetSpeech> element collects speech from caller voice
* If no input is received before timeout, <GetSpeech> falls through to the
* next element in the RESTXML document.
*
* You may optionally nest <Speak> and <Play> within a <GetDigits> element while
* waiting for input.
*/
class GetSpeech extends Element {
protected $valid = array('action','method','timeout', 'engine', 'grammar', 'playBeep');
protected $nesting = array('Speak', 'Play', 'Wait');
/**
* GetSpeech Constructor
* @param array $attr Optional attributes
* @return GetSpeech
*/
function __construct($attr = array()){
parent::__construct(NULL, $attr);
}
}
/**
* The <PreAnswer> element answers the call in early media mode.
*/
class PreAnswer extends Element {
protected $valid = array();
protected $nesting = array('Speak', 'Play', 'Wait', 'GetDigits', 'GetSpeech', 'Redirect', 'SIPTransfer');
function __construct($attr = array()){
parent::__construct($attr);
}
}
// Plivo Utility function and Request Validation
// ========================================================================
class PlivoUtils {
protected $AccountSid;
protected $AuthToken;
function __construct($id, $token){
$this->AuthToken = $token;
$this->AccountSid = $id;
}
public function validateRequest($expected_signature, $url, $data = array()) {
// sort the array by keys
ksort($data);
// append them to the data string in order
// with no delimiters
foreach($data AS $key=>$value)
$url .= "$key$value";
// This function calculates the HMAC hash of the data with the key
// passed in
// Note: hash_hmac requires PHP 5 >= 5.1.2 or PECL hash:1.1-1.5
// Or http://pear.php.net/package/Crypt_HMAC/
$calculated_signature = base64_encode(hash_hmac("sha1",$url, $this->AuthToken, true));
return $calculated_signature == $expected_signature;
}
}
?>