├── .gitmodules ├── TropoClasses.php ├── samples ├── hello_world.php ├── conferencerJoinLeavePrompt.php ├── Provisioning-DeleteAddress.php ├── Provisioning-DeleteApp.php ├── Provisioning-AddNumber.php ├── Provisioning-AddToken.php ├── Provisioning-AddAddress.php ├── callMachineDetection.php ├── Provisioning-CreateApp.php ├── outbound_call.php ├── Provisioning-AddNewURL.php ├── recordingdemo.php ├── event-test.php ├── call-info.php ├── transferWhisper.php ├── conference.php ├── get_zip_code.php └── favorite-movie-webapi.php ├── tests ├── HangupTest.php ├── GeneralLogSecurityTest.php ├── RedirectTest.php ├── WaitTest.php ├── AnswerTest.php ├── OnTest.php ├── SessionTest.php ├── ConferenceTest.php ├── StartRecordingTest.php ├── MessageTest.php ├── AskTest.php ├── RecordTest.php ├── SayTest.php ├── CallTest.php ├── ResultTest.php └── TransferTest.php ├── compatibility.php ├── LICENSE ├── readme.markdown └── tropo-rest.class.php /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "samples/orchestra"] 2 | path = samples/orchestra 3 | url = https://github.com/mheadd/tropo-orchestra.git 4 | -------------------------------------------------------------------------------- /TropoClasses.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /samples/hello_world.php: -------------------------------------------------------------------------------- 1 | say("Hello World!"); 12 | $tropo->renderJson(); 13 | 14 | ?> -------------------------------------------------------------------------------- /tests/HangupTest.php: -------------------------------------------------------------------------------- 1 | Hangup(); 12 | $this->assertEquals('{"tropo":[{"hangup":"null"}]}', sprintf($tropo)); 13 | } 14 | 15 | } 16 | ?> -------------------------------------------------------------------------------- /samples/conferencerJoinLeavePrompt.php: -------------------------------------------------------------------------------- 1 | getFrom(); 11 | $callerID = $from["id"]; 12 | 13 | $tropo->say("You are about to enter the conference"); 14 | 15 | $tropo->conference(null, array( 16 | "id"=>"1234", 17 | "name"=>"joinleave", 18 | "joinPrompt" => "$callerID has entered the conference", 19 | "leavePrompt" => "$callerID has left the conference", 20 | "voice" => "Victor", 21 | )); 22 | 23 | $tropo->RenderJson(); 24 | 25 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-DeleteAddress.php: -------------------------------------------------------------------------------- 1 | deleteApplicationAddress($userid, $password, $applicationID, AddressType::$number, $number); 20 | } 21 | 22 | catch (TropoException $ex) { 23 | echo $ex->getMessage(); 24 | } 25 | 26 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-DeleteApp.php: -------------------------------------------------------------------------------- 1 | deleteApplication($userid, $password, $applicationID); 20 | } 21 | 22 | catch (TropoException $ex) { 23 | echo $ex->getMessage(); 24 | } 25 | 26 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-AddNumber.php: -------------------------------------------------------------------------------- 1 | AddressType::$number, "prefix" => "1407"); 21 | echo $tropo->updateApplicationAddress($userid, $password, $applicationID, $params); 22 | 23 | } 24 | 25 | catch (TropoException $ex) { 26 | echo $ex->getMessage(); 27 | } 28 | 29 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-AddToken.php: -------------------------------------------------------------------------------- 1 | updateApplicationAddress($userid, $password, $applicationID, array("type" => AddressType::$token, "channel" => "messaging")); 20 | } 21 | 22 | catch (TropoException $ex) { 23 | echo $ex->getMessage(); 24 | } 25 | 26 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-AddAddress.php: -------------------------------------------------------------------------------- 1 | AddressType::$aim, "username" => "AIMUser01", "password" => "secret"); 21 | echo $tropo->updateApplicationAddress($userid, $password, $applicationID, $params); 22 | 23 | } 24 | 25 | catch (TropoException $ex) { 26 | echo $ex->getMessage(); 27 | } 28 | 29 | ?> -------------------------------------------------------------------------------- /tests/GeneralLogSecurityTest.php: -------------------------------------------------------------------------------- 1 | generalLogSecurity("suppress"); 11 | $say = new Say("this is not logged.", null, null, null, null, "nolog"); 12 | $tropo->say($say); 13 | $tropo->generalLogSecurity("none"); 14 | $say = new Say("this will be logged.", null, null, null, null, "log"); 15 | $tropo->say($say); 16 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"generalLogSecurity":"suppress"},{"say":[{"value":"this is not logged.","name":"nolog"}]},{"generalLogSecurity":"none"},{"say":[{"value":"this will be logged.","name":"log"}]}]}'); 17 | } 18 | 19 | } 20 | ?> -------------------------------------------------------------------------------- /tests/RedirectTest.php: -------------------------------------------------------------------------------- 1 | true 12 | ); 13 | 14 | $tropo->redirect("sip:pengxli@192.168.26.1:5678", $params); 15 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"redirect":{"to":"sip:pengxli@192.168.26.1:5678","required":true}}]}'); 16 | } 17 | 18 | public function testRedirect1() 19 | { 20 | $tropo = new Tropo(); 21 | $redirect = new Redirect("sip:pengxli@192.168.26.1:5678", null, null, true); 22 | $tropo->redirect($redirect); 23 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"redirect":{"to":"sip:pengxli@192.168.26.1:5678","required":true}}]}'); 24 | } 25 | 26 | } 27 | ?> -------------------------------------------------------------------------------- /samples/callMachineDetection.php: -------------------------------------------------------------------------------- 1 | call("+14071234321", array( 12 | "machineDetection" => "This is just a test to see if you are a human or a machine. PLease hold while we determine. Almost finished. Thank you!", 13 | "voice" => "Victor" 14 | )); 15 | $tropo->on(array("event" => "continue", "next" => "your_app.php?uri=continue")); 16 | 17 | $tropo->RenderJson(); 18 | } 19 | 20 | dispatch_post('/continue', 'app_continue'); 21 | function app_continue() { 22 | 23 | $tropo = new Tropo(); 24 | @$result = new Result(); 25 | 26 | $userType = $result->getUserType(); 27 | $tropo->say("You are a $userType"); 28 | $tropo->RenderJson(); 29 | } 30 | run(); 31 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-CreateApp.php: -------------------------------------------------------------------------------- 1 | "My Awesome App", 23 | "voiceUrl" => "http://www.fake.com/index.php", 24 | "messagingUrl" => "http://www.fake.com/index2.php", 25 | "platform" => "webapi", 26 | "partition" => "staging" 27 | ); 28 | 29 | echo $tropo->createApplication($userid, $password, $appSettings); 30 | 31 | } 32 | 33 | catch (TropoException $ex) { 34 | echo $ex->getMessage(); 35 | } 36 | 37 | ?> -------------------------------------------------------------------------------- /samples/outbound_call.php: -------------------------------------------------------------------------------- 1 | getParameters("numbertodial"); 12 | $name = $session->getParameters("customername"); 13 | $msg = $session->getParameters("msg"); 14 | 15 | //extracts the contents of the passed parameters and assigns them as variables for later use 16 | 17 | $tropo = new Tropo(); 18 | 19 | $tropo->call($to, array('network'=>'SMS')); 20 | $tropo->say("OMG ".$name.", ".$msg."!"); 21 | 22 | //actually creates the call, passed the "to" value and then adds in the other variables for the message 23 | 24 | return $tropo->RenderJson(); 25 | 26 | //defines the response to Tropo in JSON 27 | 28 | ?> -------------------------------------------------------------------------------- /compatibility.php: -------------------------------------------------------------------------------- 1 | = 0) { 13 | echo "OK PHP Version: $version\n"; 14 | } 15 | else 16 | { 17 | echo "WARNING - PHP Version: This library may not perform as expected wih the version of PHP you are currently running: { $version }.\n"; 18 | 19 | } 20 | 21 | // Check to see if errors/warnings are displayed. 22 | if(ini_get('display_errors') == 0) { 23 | echo "OK Display errors: disabled.\n"; 24 | } 25 | else { 26 | echo "WARNING Display errors: Errors are displayed. This may cause issues with how JSON is rendered for Tropo.\n"; 27 | } 28 | 29 | echo "\n======================================================\n\n"; 30 | 31 | ?> -------------------------------------------------------------------------------- /samples/Provisioning-AddNewURL.php: -------------------------------------------------------------------------------- 1 | "My Awesome App", 23 | "voiceUrl" => "http://www.anotherfake.com/index.php", 24 | "messagingUrl" => "http://www.anotherfake.com/index2.php", 25 | "platform" => "webapi", 26 | "partition" => "staging" 27 | ); 28 | 29 | echo $tropo->updateApplicationProperty($userid, $password, $applicationID, $appSettings); 30 | 31 | } 32 | 33 | catch (TropoException $ex) { 34 | echo $ex->getMessage(); 35 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010 Mark Headd, 2011-2013 Voxeo Labs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /samples/recordingdemo.php: -------------------------------------------------------------------------------- 1 | record(array( 14 | 'say' => 'Leave your message at the beep.', 15 | 'url' => getself() . '?record', // append ?record to the URL 16 | )); 17 | print $tropo; 18 | } else { 19 | // Change this path to match the location on your server where you want 20 | // the file to be saved. 21 | $target_path = 'path/to/recording/' . $_FILES['filename']['name']; 22 | if(move_uploaded_file($_FILES['filename']['tmp_name'], $target_path)) { 23 | $log->LogInfo("$target_path [{$_FILES['filename']['size']} bytes] was saved"); 24 | } else { 25 | $log->LogError("$target_path could not be saved."); 26 | } 27 | } 28 | 29 | // Simple function to get the full URL of the current script. 30 | function getself() { 31 | $pageURL = 'http'; 32 | $url = ($_SERVER["HTTPS"] == "on") ? 'https' : 'http'; 33 | $url .= "://" . $_SERVER["SERVER_NAME"]; 34 | $url .= ($_SERVER["SERVER_PORT"] != "80") ? ':'. $_SERVER["SERVER_PORT"] : ''; 35 | $url .= $_SERVER["REQUEST_URI"]; 36 | return $url; 37 | } 38 | ?> -------------------------------------------------------------------------------- /samples/event-test.php: -------------------------------------------------------------------------------- 1 | getId(); 13 | 14 | // Insert the Session object into a CouchDB database called sessions. 15 | try { 16 | $sag = new Sag(); 17 | $sag->setDatabase("sessions"); 18 | $sag->put($session_id, $json); 19 | } 20 | catch (SagCouchException $ex) { 21 | die("*** ".$ex->getMessage()." ***"); 22 | } 23 | 24 | // Create a new Tropo object. 25 | $tropo = new Tropo(); 26 | 27 | // Set options for an Ask. 28 | $options = array("attempts" => 20, "bargein" => true, "choices" => "[5 DIGITS]", "name" => "zip", "timeout" => 5, "allowSignals" => array("tooLong", "farTooLong")); 29 | $tropo->ask("Please enter your 5 digit zip code.", $options); 30 | 31 | // Set event handlers 32 | $tropo->on(array("event" => "continue", "next" => "get_zip_code.php?uri=end", "say" => "Please hold.")); 33 | $tropo->on(array("event" => "tooLong", "next" => "get_zip_code.php?uri=end&tooLong=true", "say" => "Please hold on.")); 34 | $tropo->on(array("event" => "farTooLong", "next" => "get_zip_code.php?uri=end&farTooLong=true", "say" => "Please hold on for dear life.")); 35 | 36 | // Render JSON for Tropo to consume. 37 | $tropo->renderJSON(); 38 | 39 | 40 | ?> -------------------------------------------------------------------------------- /samples/call-info.php: -------------------------------------------------------------------------------- 1 | getFrom(); 16 | 17 | $tropo = new Tropo(); 18 | // $caller now has a hash containing the keys: id, name, channel, and network 19 | $tropo->say("Your phone number is " . $caller['id']); 20 | 21 | $called = $session->getTo(); 22 | 23 | // $called now has a hash containing the keys: id, name, channel, and network 24 | $tropo->say("You called " . $called['id'] . " but you probably already knew that."); 25 | 26 | if ($called['channel'] == "TEXT") { 27 | // This is a text message 28 | $tropo->say("You contacted me via text."); 29 | 30 | // The first text of the session is going to be queued and applied to the first 31 | // ask statement you include... 32 | $tropo->ask("This will catch the first text", array('choices' => '[ANY]')); 33 | 34 | // ... or, you can grab that first text like this straight from the session. 35 | $messsage = $session->getInitialText(); 36 | 37 | $tropo->say("You said " . $message); 38 | } else { 39 | // This is a phone call 40 | $tropo->say("Awww. How nice. You cared enough to call."); 41 | } 42 | 43 | print $tropo; 44 | ?> -------------------------------------------------------------------------------- /samples/transferWhisper.php: -------------------------------------------------------------------------------- 1 | $a); 14 | 15 | //push the ask to the whisper array 16 | array_push($whisper, $ask); 17 | 18 | //The first method will be a say 19 | $say = array("say" => new Say("You are now being connected to the call.")); 20 | 21 | //Push the say to the whisper array 22 | array_push($whisper, $say); 23 | 24 | 25 | $tropo->say("please hold while you are transferred"); 26 | 27 | //Create the connect whisper on event for the transfer with a ring event 28 | $on = array("event" => "connect", "whisper" => $whisper, "ring" => "http://www.phono.com/audio/holdmusic.mp3"); 29 | 30 | //Create the connect whisper on event for the transfer without a ring event 31 | $on = array("event" => "connect", "whisper" => $whisper); 32 | 33 | $options = array( 34 | 'on' => $on, 35 | 'from' => '14071234321' 36 | ); 37 | 38 | //use the connect whisper in the transfer 39 | $tropo->transfer("+14071234321", $options); 40 | $tropo->on(array("event" => "incomplete", "next" => "hangup.php", "say" => "You have opted to not accept this call. Goodbye!")); 41 | 42 | echo $tropo->RenderJson(); 43 | ?> -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | TropoPHP is a set of PHP classes for working with [Tropo's cloud communication service](http://tropo.com/). Tropo allows a developer to create applications that run over the phone, IM, SMS, and Twitter using web technologies. This library communicates with Tropo over JSON. 5 | 6 | Requirements 7 | ============ 8 | 9 | * PHP 5.6 or greater 10 | * PHP Notices disabled (All error reporting disabled is recommended for production use) 11 | 12 | Usage 13 | ===== 14 | 15 | Answer the phone, say something, and hang up. 16 | 17 | say('Yes, Tropo is this easy.', array('name' => 'sayName')); 23 | 24 | // Render the JSON back to Tropo. 25 | $tropo->renderJSON(); 26 | ?> 27 | 28 | Asking for input. 29 | 30 | ask('What is your favorite programming language?', array( 35 | 'choices'=>'PHP, Ruby(Ruby, Rails, Ruby on Rails), Python, Java(Groovy, Java), Perl', 36 | 'event'=> array( 37 | 'nomatch' => 'Never heard of it.', 38 | 'timeout' => 'Speak up!', 39 | ) 40 | )); 41 | // Tell Tropo how to continue if a successful choice was made 42 | $tropo->on(array('event' => 'continue', 'say'=> 'Fantastic! I love that, too!')); 43 | // Render the JSON back to Tropo 44 | $tropo->renderJSON(); 45 | ?> -------------------------------------------------------------------------------- /tests/WaitTest.php: -------------------------------------------------------------------------------- 1 | say($say); 12 | $wait = array( 13 | 'milliseconds' => 8000 14 | ); 15 | $tropo->wait($wait); 16 | $say = new Say("Bye!", null, null, null, null, "bye"); 17 | $tropo->say($say); 18 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Connected!","name":"connected"}]},{"wait":{"milliseconds":8000}},{"say":[{"value":"Bye!","name":"bye"}]}]}'); 19 | } 20 | 21 | public function testWaitWithAllOption() 22 | { 23 | $tropo = new Tropo(); 24 | $say = new Say("Connected!", null, null, null, null, "connected"); 25 | $tropo->say($say); 26 | $wait = array( 27 | 'milliseconds' => 8000, 28 | 'allowSignals' => array('exit','quit') 29 | ); 30 | $tropo->wait($wait); 31 | $say = new Say("Bye!", null, null, null, null, "bye"); 32 | $tropo->say($say); 33 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Connected!","name":"connected"}]},{"wait":{"milliseconds":8000,"allowSignals":["exit","quit"]}},{"say":[{"value":"Bye!","name":"bye"}]}]}'); 34 | } 35 | 36 | public function testWaitObject() 37 | { 38 | $tropo = new Tropo(); 39 | $say = new Say("Connected!", null, null, null, null, "connected"); 40 | $tropo->say($say); 41 | $wait = new Wait(8000); 42 | $tropo->wait($wait); 43 | $say = new Say("Bye!", null, null, null, null, "bye"); 44 | $tropo->say($say); 45 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Connected!","name":"connected"}]},{"wait":{"milliseconds":8000}},{"say":[{"value":"Bye!","name":"bye"}]}]}'); 46 | } 47 | 48 | public function testWaitObject1() 49 | { 50 | $tropo = new Tropo(); 51 | $say = new Say("Connected!", null, null, null, null, "connected"); 52 | $tropo->say($say); 53 | $wait = new Wait(8000, array('exit','quit')); 54 | $tropo->wait($wait); 55 | $say = new Say("Bye!", null, null, null, null, "bye"); 56 | $tropo->say($say); 57 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Connected!","name":"connected"}]},{"wait":{"milliseconds":8000,"allowSignals":["exit","quit"]}},{"say":[{"value":"Bye!","name":"bye"}]}]}'); 58 | } 59 | 60 | } 61 | ?> -------------------------------------------------------------------------------- /samples/conference.php: -------------------------------------------------------------------------------- 1 | map('/', 'start') 27 | ->via('GET') 28 | ->via('POST'); 29 | $app->post('/restart', 'start'); 30 | 31 | function start() { 32 | global $voice; 33 | $tropo = new Tropo(); 34 | $tropo->setVoice($voice); 35 | 36 | $tropo->ask("Enter your conference ID, followed by the pound key.", array( 37 | "choices" => "[1-10 DIGITS]", 38 | "name" => "confid", 39 | "attempts" => 5, 40 | "timeout" => 60, 41 | "mode" => "dtmf", 42 | "terminator" => "#", 43 | "event" => array( 44 | "incomplete" => 'Sorry, I didn\'t hear anything.', 45 | "nomatch" => 'Sorry, that is not a valid conference ID.' 46 | ) 47 | )); 48 | 49 | $tropo->on(array("event" => "continue", "next" => "conference")); 50 | $tropo->on(array("event" => "incomplete", "next" => "restart")); 51 | 52 | $tropo->RenderJson(); 53 | } 54 | 55 | $app->post('/conference', 'conference'); 56 | function conference() { 57 | global $voice; 58 | $tropo = new Tropo(); 59 | $tropo->setVoice($voice); 60 | 61 | $result = new Result(); 62 | $conference = $result->getValue(); 63 | 64 | $tropo->say('Conference ID ' . $conference . ' accepted.'); 65 | $tropo->say('You will now be placed into the conference. Please announce yourself. To exit the conference without disconnecting, press pound.'); 66 | $tropo->conference($conference, array('id' => $conference, 'terminator' => '#')); 67 | $tropo->say('You have left the conference.'); 68 | 69 | $tropo->on(array("event" => "continue", "next" => "restart")); 70 | $tropo->RenderJson(); 71 | } 72 | 73 | $app->run(); 74 | ?> -------------------------------------------------------------------------------- /tests/AnswerTest.php: -------------------------------------------------------------------------------- 1 | answer(); 11 | $params = array("name"=>"say"); 12 | $tropo->say("Hello, you were the first to answer.",$params); 13 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"answer":{}},{"say":[{"value":"Hello, you were the first to answer.","name":"say"}]}]}'); 14 | } 15 | 16 | public function testCallWithMinOptions1() { 17 | $tropo = new Tropo(); 18 | $tropo->answer(null); 19 | $params = array("name"=>"say"); 20 | $tropo->say("Hello, you were the first to answer.",$params); 21 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"answer":{}},{"say":[{"value":"Hello, you were the first to answer.","name":"say"}]}]}'); 22 | } 23 | 24 | public function testCallWithExtraToOptiions() { 25 | $tropo = new Tropo(); 26 | $params = array( 27 | 'headers' => array( 28 | 'P-Header' => 'value goes here', 29 | 'Remote-Party-ID' => '"John Doe";party=calling;id-type=subscriber;privacy=full;screen=yes' 30 | )); 31 | $tropo->answer($params); 32 | $params = array("name"=>"say"); 33 | $tropo->say("Hello, you were the first to answer.",$params); 34 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"answer":{"headers":{"P-Header":"value goes here","Remote-Party-ID":"\"John Doe\";party=calling;id-type=subscriber;privacy=full;screen=yes"}}},{"say":[{"value":"Hello, you were the first to answer.","name":"say"}]}]}'); 35 | } 36 | 37 | public function testCreateMinObject() { 38 | $tropo = new Tropo(); 39 | $answer = new Answer(); 40 | $tropo->answer($answer); 41 | $params = array("name"=>"say"); 42 | $tropo->say("Hello, you were the first to answer.",$params); 43 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"answer":{}},{"say":[{"value":"Hello, you were the first to answer.","name":"say"}]}]}'); 44 | } 45 | 46 | public function testCreateMinObject1() { 47 | $tropo = new Tropo(); 48 | $headers = array( 49 | 'P-Header' => 'value goes here', 50 | 'Remote-Party-ID' => '"John Doe";party=calling;id-type=subscriber;privacy=full;screen=yes' 51 | ); 52 | $answer = new Answer($headers); 53 | $tropo->answer($answer); 54 | $params = array("name"=>"say"); 55 | $tropo->say("Hello, you were the first to answer.",$params); 56 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"answer":{"headers":{"P-Header":"value goes here","Remote-Party-ID":"\"John Doe\";party=calling;id-type=subscriber;privacy=full;screen=yes"}}},{"say":[{"value":"Hello, you were the first to answer.","name":"say"}]}]}'); 57 | } 58 | 59 | } 60 | ?> -------------------------------------------------------------------------------- /tests/OnTest.php: -------------------------------------------------------------------------------- 1 | on($on); 13 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"on":[{"event":"continue","next":"say.php","say":{"value":"object continue!"}}]}]}'); 14 | } 15 | 16 | public function testCreateOnObject1() { 17 | 18 | $tropo = new Tropo(); 19 | $say = new Say("array continue!"); 20 | $on = array( 21 | 'event' => Event::$continue, 22 | 'next' => 'say.php', 23 | 'say' => $say 24 | ); 25 | $tropo->on($on); 26 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"on":[{"event":"continue","next":"say.php","say":{"value":"array continue!"}}]}]}'); 27 | } 28 | 29 | public function testFailsOnWithNoEventParameter1() { 30 | $tropo = new Tropo(); 31 | try { 32 | $say = new Say("object continue!"); 33 | @ $on = new On(null, "say.php", $say); 34 | } catch (Exception $e) { 35 | $this->assertEquals($e->getMessage(), "Missing required property: 'event'"); 36 | } 37 | } 38 | 39 | public function testFailsOnWithNoEventParameter2() { 40 | $tropo = new Tropo(); 41 | try { 42 | $say = new Say("object continue!"); 43 | @ $on = new On("", "say.php", $say); 44 | } catch (Exception $e) { 45 | $this->assertEquals($e->getMessage(), "Missing required property: 'event'"); 46 | } 47 | } 48 | 49 | public function testFailsOnWithNoEventParameter3() { 50 | $tropo = new Tropo(); 51 | try { 52 | $say = new Say("array continue!"); 53 | @ $on = array( 54 | 'next' => 'say.php', 55 | 'say' => $say 56 | ); 57 | $tropo->on($on); 58 | } catch (Exception $e) { 59 | $this->assertEquals($e->getMessage(), "Missing required property: 'event'"); 60 | } 61 | } 62 | 63 | public function testFailsOnWithNoEventParameter4() { 64 | $tropo = new Tropo(); 65 | try { 66 | $say = new Say("array continue!"); 67 | $on = array( 68 | 'event' => null, 69 | 'next' => 'say.php', 70 | 'say' => $say 71 | ); 72 | $tropo->on($on); 73 | } catch (Exception $e) { 74 | $this->assertEquals($e->getMessage(), "Required property: 'event' must be a string."); 75 | } 76 | } 77 | 78 | public function testFailsOnWithNoEventParameter5() { 79 | $tropo = new Tropo(); 80 | try { 81 | $say = new Say("array continue!"); 82 | $on = array( 83 | 'event' => '', 84 | 'next' => 'say.php', 85 | 'say' => $say 86 | ); 87 | $tropo->on($on); 88 | } catch (Exception $e) { 89 | $this->assertEquals($e->getMessage(), "Required property: 'event' must be a string."); 90 | } 91 | } 92 | 93 | public function testFailsOnWithNoSayParameter2() { 94 | $tropo = new Tropo(); 95 | try { 96 | $on = array( 97 | 'event' => Event::$continue, 98 | 'next' => 'say.php', 99 | 'say' => null 100 | ); 101 | $tropo->on($on); 102 | } catch (Exception $e) { 103 | $this->assertEquals($e->getMessage(), "Property: 'say' must be a Say of array or an instance of Say."); 104 | } 105 | } 106 | } 107 | ?> -------------------------------------------------------------------------------- /tests/SessionTest.php: -------------------------------------------------------------------------------- 1 | ","x-sid":"6f1e3b7b2ace2a7785780b6337641388","User-Agent":"X-Lite release 4.9.7.1 stamp 83369","From":";tag=1bb1ef33","Supported":"replaces","Allow":"SUBSCRIBE\\r\\nNOTIFY\\r\\nINVITE\\r\\nACK\\r\\nCANCEL\\r\\nBYE\\r\\nREFER\\r\\nINFO\\r\\nOPTIONS\\r\\nMESSAGE","Via":"SIP/2.0/UDP 192.168.26.111:5060;branch=z9hG4bK1vxcouwp4r78j;rport=5060\\r\\nSIP/2.0/UDP 192.168.26.1:5678;branch=z9hG4bK-524287-1---b1f649005b368755;rport=5678","Contact":"","To":"","Content-Length":"335","Content-Type":"application/sdp"}}}'; 10 | $session = new Session($strSession); 11 | $this->assertEquals($session->getId(), '35b00c154f2fecacba37fad74e64a7e2'); 12 | $this->assertEquals($session->getAccountId(), '1'); 13 | $this->assertEquals($session->getTimestamp(), '2017-06-08T03:40:19.283Z'); 14 | $this->assertEquals($session->getUserType(), 'HUMAN'); 15 | $this->assertEquals($session->getInitialText(), null); 16 | $initialMedia = $session->getInitialMedia(); 17 | $this->assertEquals($session->getStatusFromMedia($initialMedia[0]), "success"); 18 | $this->assertEquals($session->getMediaFromMedia($initialMedia[0]), "http://filehosting.tropo.com/account/1.jpg"); 19 | 20 | $this->assertEquals($session->getStatusFromMedia($initialMedia[1]), "success"); 21 | $this->assertEquals($session->getTextFromMedia($initialMedia[1]), "this is text"); 22 | 23 | $this->assertEquals($session->getStatusFromMedia($initialMedia[2]), "failure"); 24 | $this->assertEquals($session->getDispositionFromMedia($initialMedia[2]), "Failed to upload: 500 Internal Error"); 25 | $this->assertEquals($session->getMediaFromMedia($initialMedia[2]), "2.jpg"); 26 | 27 | $this->assertEquals($session->getSubject(), "Inbound MMS subject"); 28 | $this->assertEquals($session->getCallId(), 'c5b298fc0785fda9029f7f3b5aeef7ab'); 29 | $to = $session->getTo(); 30 | $this->assertEquals($to["id"], '9992801029'); 31 | $this->assertEquals($to["e164Id"], '9992801029'); 32 | $this->assertEquals($to["name"], '9992801029'); 33 | $this->assertEquals($to["channel"], 'VOICE'); 34 | $this->assertEquals($to["network"], 'SIP'); 35 | $from = $session->getFrom(); 36 | $this->assertEquals($from["id"], 'pengxli'); 37 | $this->assertEquals($from["e164Id"], 'pengxli'); 38 | $this->assertEquals($from["name"], 'pengxli'); 39 | $this->assertEquals($from["channel"], 'VOICE'); 40 | $this->assertEquals($from["network"], 'SIP'); 41 | } 42 | 43 | } 44 | ?> -------------------------------------------------------------------------------- /tests/ConferenceTest.php: -------------------------------------------------------------------------------- 1 | conference("1234"); 11 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"conference":{"id":"1234"}}]}'); 12 | } 13 | 14 | public function testConferenceWithAllOptions() { 15 | $tropo = new Tropo(); 16 | $allowSignals = array('exit', 'quit'); 17 | $params = array( 18 | 'allowSignals' => $allowSignals, 19 | 'interdigitTimeout' => 5.0, 20 | 'joinPrompt' => true, 21 | 'leavePrompt' => true, 22 | 'mute' => false, 23 | 'playTones' => true, 24 | 'required' => true, 25 | 'terminator' => '*', 26 | 'promptLogSecurity' => 'suppress', 27 | ); 28 | $tropo->conference("1234", $params); 29 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"conference":{"id":"1234","mute":false,"playTones":true,"required":true,"terminator":"*","allowSignals":["exit","quit"],"interdigitTimeout":5,"promptLogSecurity":"suppress","joinPrompt":true,"leavePrompt":true}}]}'); 30 | } 31 | 32 | public function testConferenceWithAllOptions1() { 33 | $tropo = new Tropo(); 34 | $allowSignals = array('exit', 'quit'); 35 | $joinPrompt = array( 36 | 'value' => 'I am coming.', 37 | 'voice' => Voice::$US_English_female_allison 38 | ); 39 | $leavePrompt = array( 40 | 'value' => 'I am leaving.', 41 | 'voice' => Voice::$US_English_female_allison 42 | ); 43 | $params = array( 44 | 'allowSignals' => $allowSignals, 45 | 'interdigitTimeout' => 5.0, 46 | 'joinPrompt' => $joinPrompt, 47 | 'leavePrompt' => $leavePrompt, 48 | 'mute' => false, 49 | 'playTones' => true, 50 | 'required' => true, 51 | 'terminator' => '*', 52 | 'promptLogSecurity' => 'suppress', 53 | ); 54 | $tropo->conference("1234", $params); 55 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"conference":{"id":"1234","mute":false,"playTones":true,"required":true,"terminator":"*","allowSignals":["exit","quit"],"interdigitTimeout":5,"promptLogSecurity":"suppress","joinPrompt":{"value":"I am coming.","voice":"allison"},"leavePrompt":{"value":"I am leaving.","voice":"allison"}}}]}'); 56 | } 57 | 58 | public function testCreateMinObject() { 59 | $tropo = new Tropo(); 60 | $conference = new Conference(null, "1234"); 61 | $tropo->conference($conference); 62 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"conference":{"id":"1234"}}]}'); 63 | } 64 | 65 | public function testCreateObject1() { 66 | $tropo = new Tropo(); 67 | $allowSignals = array('exit', 'quit'); 68 | $conference = new Conference(null, "1234", false, null, true, true, "*", $allowSignals, 5.0, true, true, null, "suppress"); 69 | $tropo->conference($conference); 70 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"conference":{"id":"1234","mute":false,"playTones":true,"required":true,"terminator":"*","allowSignals":["exit","quit"],"interdigitTimeout":5,"promptLogSecurity":"suppress","joinPrompt":true,"leavePrompt":true}}]}'); 71 | } 72 | 73 | public function testCreateObject2() { 74 | $tropo = new Tropo(); 75 | $allowSignals = array('exit', 'quit'); 76 | $joinPrompt = array( 77 | 'value' => 'I am coming.', 78 | 'voice' => Voice::$US_English_female_allison 79 | ); 80 | $leavePrompt = array( 81 | 'value' => 'I am leaving.', 82 | 'voice' => Voice::$US_English_female_allison 83 | ); 84 | $conference = new Conference(null, "1234", false, null, true, true, "*", $allowSignals, 5.0, $joinPrompt, $leavePrompt, null, "suppress"); 85 | $tropo->conference($conference); 86 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"conference":{"id":"1234","mute":false,"playTones":true,"required":true,"terminator":"*","allowSignals":["exit","quit"],"interdigitTimeout":5,"promptLogSecurity":"suppress","joinPrompt":{"value":"I am coming.","voice":"allison"},"leavePrompt":{"value":"I am leaving.","voice":"allison"}}}]}'); 87 | } 88 | } 89 | ?> -------------------------------------------------------------------------------- /samples/get_zip_code.php: -------------------------------------------------------------------------------- 1 | weather->forecast_information->city["data"]; 18 | $current_conditions = $weatherXML->weather->current_conditions; 19 | $current_weather = array( 20 | "condition" => $current_conditions->condition["data"], 21 | "temperature" => $current_conditions->temp_f["data"]." degrees", 22 | "wind" => formatDirection($current_conditions->wind_condition["data"]), 23 | "city" => $city 24 | ); 25 | return $current_weather; 26 | 27 | } 28 | 29 | // A helper method to format directional abbreviations. 30 | function formatDirection($wind) { 31 | $abbreviated = array(" N ", " S ", " E ", " W ", " NE ", " SE ", " SW ", " NW "); 32 | $full_name = array(" North ", " South ", " East ", " West ", " North East ", " South East ", " South West ", " North West "); 33 | return str_replace($abbreviated, $full_name, str_replace("mph", "miles per hour", $wind)); 34 | } 35 | 36 | // A helper method to format the Tropo object with weather details for a specific zip code. 37 | function formatWeatherResponse(&$tropo, $zip) { 38 | 39 | // Get weather information for the zip code the caller entered. 40 | $weather_info = getWeather($zip); 41 | $city = array_pop($weather_info); 42 | 43 | // Begin telling the user the weather for the city their zip code is in. 44 | $tropo->say("The current weather for $city is..."); 45 | 46 | // Iterate over an array of weather information. 47 | foreach ($weather_info as $info) { 48 | $tropo->say("$info."); 49 | } 50 | 51 | // Say thank you (never hurts to be polite) and end the session. 52 | $tropo->say("Thank you for using Tropo!"); 53 | $tropo->hangup(); 54 | } 55 | 56 | /** 57 | * This is the starting point for the Tropo application. 58 | * Get a 5 digit zip code from the user. 59 | */ 60 | dispatch_post('/start', 'zip_start'); 61 | function zip_start() { 62 | 63 | // Create a new instance of the Session object, and get the channel information. 64 | $session = new Session(); 65 | $from_info = $session->getFrom(); 66 | $channel = $from_info['channel']; 67 | 68 | // Create a new instance of the Tropo object. 69 | $tropo = new Tropo(); 70 | 71 | // See if any text was sent with session start. 72 | $initial_text = $session->getInitialText(); 73 | 74 | // If the initial text is a zip code, skip the input collection and get weather information. 75 | if(strlen($initial_text) == 5 && is_numeric($initial_text)) { 76 | formatWeatherResponse($tropo, $initial_text); 77 | } 78 | 79 | else { 80 | // Welcome prompt (for phone channel, and IM/SMS sessions with invalid initial text). 81 | $tropo->say("Welcome to the Tropo PHP zip code example for $channel"); 82 | 83 | // Set up options form zip code input 84 | $options = array("attempts" => 3, "bargein" => true, "choices" => "[5 DIGITS]", "name" => "zip", "timeout" => 5); 85 | 86 | // Ask the user for input, pass in options. 87 | $tropo->ask("Please enter your 5 digit zip code.", $options); 88 | 89 | // Tell Tropo what to do when the user has entered input, or if there is an error. 90 | $tropo->on(array("event" => "continue", "next" => "get_zip_code.php?uri=end", "say" => "Please hold.")); 91 | $tropo->on(array("event" => "error", "next" => "get_zip_code.php?uri=error", "say" => "An error has occured.")); 92 | } 93 | 94 | // Render the JSON for the Tropo WebAPI to consume. 95 | return $tropo->RenderJson(); 96 | 97 | } 98 | 99 | /** 100 | * After a zip code has been entered, use it to look up weather details for that city. 101 | */ 102 | dispatch_post('/end', 'zip_end'); 103 | function zip_end() { 104 | 105 | // Create a new instance of the result object and get the value of the user input. 106 | $result = new Result(); 107 | $zip = $result->getValue(); 108 | 109 | // Create a new instance of the Tropo object. 110 | $tropo = new Tropo(); 111 | 112 | // Get the weather information for the entered zip code. 113 | formatWeatherResponse($tropo, $zip); 114 | 115 | // Render the JSON for the Tropo WebAPI to consume. 116 | return $tropo->RenderJson(); 117 | 118 | } 119 | 120 | /** 121 | * If an error occurs, end the session. 122 | */ 123 | dispatch_post('/error', 'zip_error'); 124 | function zip_error() { 125 | 126 | // Step 1. Create a new instance of the Tropo object. 127 | $tropo = new Tropo(); 128 | 129 | // Step 2. This is the last thing the user will be told before the session ends. 130 | $tropo->say("Please try your request again later."); 131 | 132 | // Step 3. End the session. 133 | $tropo->hangup(); 134 | 135 | // Step 4. Render the JSON for the Tropo WebAPI to consume. 136 | return $tropo->renderJSON(); 137 | } 138 | 139 | // Run this sucker! 140 | run(); 141 | 142 | ?> -------------------------------------------------------------------------------- /tests/StartRecordingTest.php: -------------------------------------------------------------------------------- 1 | 'http://192.168.26.203/tropo-webapi-php/upload_file.php', 11 | ); 12 | $tropo->startRecording($startRecording); 13 | $say = new Say("I am now recording!", null, null, null, null, "say"); 14 | $tropo->say($say); 15 | $tropo->stopRecording(); 16 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"startRecording":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"}}},{"say":[{"value":"I am now recording!","name":"say"}]},{"stopRecording":"null"}]}'); 17 | } 18 | 19 | public function testStartRecordingWithMinOptions1() { 20 | $tropo = new Tropo(); 21 | $url = new Url('http://192.168.26.203/tropo-webapi-php/upload_file.php'); 22 | $startRecording = array( 23 | 'url' => $url 24 | ); 25 | $tropo->startRecording($startRecording); 26 | $say = new Say("I am now recording!", null, null, null, null, "say"); 27 | $tropo->say($say); 28 | $tropo->stopRecording(); 29 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"startRecording":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"}}},{"say":[{"value":"I am now recording!","name":"say"}]},{"stopRecording":"null"}]}'); 30 | } 31 | 32 | public function testStartRecordingWithMinOptions2() { 33 | $tropo = new Tropo(); 34 | $url = array( 35 | new Url('http://192.168.26.203/tropo-webapi-php/upload_file.php', 'root', '111111', 'POST'), 36 | new Url('http://192.168.26.204/tropo-webapi-php/upload_file.php') 37 | ); 38 | $startRecording = array( 39 | 'url' => $url 40 | ); 41 | $tropo->startRecording($startRecording); 42 | $say = new Say("I am now recording!", null, null, null, null, "say"); 43 | $tropo->say($say); 44 | $tropo->stopRecording(); 45 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"startRecording":{"url":[{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"},{"url":"http://192.168.26.204/tropo-webapi-php/upload_file.php"}]}},{"say":[{"value":"I am now recording!","name":"say"}]},{"stopRecording":"null"}]}'); 46 | } 47 | 48 | public function testRecordWithAllOptions() { 49 | $tropo = new Tropo(); 50 | $startRecording = array( 51 | 'asyncUpload' => false, 52 | 'format' => AudioFormat::$au, 53 | 'method' => 'POST', 54 | 'url' => 'http://192.168.26.203/tropo-webapi-php/upload_file.php', 55 | 'username' => 'root', 56 | 'password' => '111111', 57 | 'transcriptionOutURI' => 'mailto:you@yourmail.com', 58 | 'transcriptionEmailFormat' => 'plain', 59 | 'transcriptionID' => '1234', 60 | 'transcriptionLanguage' => 'pt-br' 61 | ); 62 | $tropo->startRecording($startRecording); 63 | $say = new Say("I am now recording!", null, null, null, null, "say"); 64 | $tropo->say($say); 65 | $tropo->stopRecording(); 66 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"startRecording":{"format":"audio/au","url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"},"transcriptionID":"1234","transcriptionEmailFormat":"plain","transcriptionOutURI":"mailto:you@yourmail.com","transcriptionLanguage":"pt-br","asyncUpload":false}},{"say":[{"value":"I am now recording!","name":"say"}]},{"stopRecording":"null"}]}'); 67 | } 68 | 69 | public function testCreateMinObject() { 70 | $tropo = new Tropo(); 71 | $startRecording = new StartRecording(null, null, null, 'http://192.168.26.203/tropo-webapi-php/upload_file.php'); 72 | $tropo->startRecording($startRecording); 73 | $say = new Say("I am now recording!", null, null, null, null, "say"); 74 | $tropo->say($say); 75 | $tropo->stopRecording(); 76 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"startRecording":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"}}},{"say":[{"value":"I am now recording!","name":"say"}]},{"stopRecording":"null"}]}'); 77 | } 78 | 79 | public function testCreateObject() { 80 | $tropo = new Tropo(); 81 | $startRecording = new StartRecording(AudioFormat::$mp3, "POST", "111111", "http://192.168.26.203/tropo-webapi-php/upload_file.php", "root", "1234", "plain", "mailto:you@yourmail.com", false, "pt-br"); 82 | $tropo->startRecording($startRecording); 83 | $say = new Say("I am now recording!", null, null, null, null, "say"); 84 | $tropo->say($say); 85 | $tropo->stopRecording(); 86 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"startRecording":{"format":"audio/mp3","url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"},"transcriptionID":"1234","transcriptionEmailFormat":"plain","transcriptionOutURI":"mailto:you@yourmail.com","transcriptionLanguage":"pt-br","asyncUpload":false}},{"say":[{"value":"I am now recording!","name":"say"}]},{"stopRecording":"null"}]}'); 87 | } 88 | 89 | } 90 | ?> -------------------------------------------------------------------------------- /samples/favorite-movie-webapi.php: -------------------------------------------------------------------------------- 1 | getFrom(); 16 | $network = $from_info['channel']; 17 | 18 | // Welcome prompt. 19 | $tropo->ask("Welcome to the Tropo PHP example for $network"); 20 | 21 | // Provide a prompt based on the the initial_text value 22 | if ($initial_text == "1") 23 | {$tropo->say("You picked Lord of the Rings. Did you know Gandalf is also Magneto? Weird."); 24 | } 25 | if ($initial_text == "2") 26 | {$tropo->say("You picked the original Star Wars. I hear Leonard Nimoy was awesome in those."); 27 | } 28 | if ($initial_text == "3") 29 | {$tropo->say("You picked the Star Wars prequels. Stop calling this number, Mr. Lucas, we know it's you."); 30 | } 31 | if ($initial_text == "4") 32 | {$tropo->say("You picked the Matrix. Dude, whoa."); 33 | } 34 | 35 | // Tell Tropo what to do next. This redirects to the instructions under dispatch_post('/hangup', 'app_hangup'). 36 | $tropo->on(array("event" => "continue", "next" => "testapp.php?uri=hangup")); 37 | 38 | // Tell Tropo what to do if there's an error. This redirects to the instructions under dispatch_post('/incomplete', 'app_incomplete'). 39 | $tropo->on(array("event" => "incomplete", "next" => "testapp.php?uri=incomplete")); 40 | 41 | } 42 | 43 | dispatch_post('/start', 'app_start'); 44 | function app_start() { 45 | 46 | // Create a new instance of the Session object, and get the channel information. 47 | $session = new Session(); 48 | $from_info = $session->getFrom(); 49 | $network = $from_info['channel']; 50 | 51 | // Create a new instance of the Tropo object. 52 | $tropo = new Tropo(); 53 | 54 | // See if any text was sent with session start. 55 | $initial_text = $session->getInitialText(); 56 | 57 | // If the initial text is a zip code, skip the input collection and go right to results. 58 | if(strlen($initial_text) == 1 && is_numeric($initial_text)) { 59 | valid_text($tropo, $initial_text); 60 | } 61 | 62 | else { 63 | 64 | // Welcome prompt. 65 | $tropo->say("Welcome to the Tropo PHP example for $network"); 66 | 67 | // Set up options for input. 68 | $options = array("attempts" => 3, "bargein" => true, "choices" => "1,2,3,4", "mode" => "dtmf", "name" => "movie", "timeout" => 30); 69 | 70 | // Ask the caller for input, pass in options. 71 | $tropo->ask("Which of these trilogies do you like the best? Press 1 to vote for Lord of the Rings, press 2 for the original Star Wars, 3 for the Star Wars prequels, or press 4 for the Matrix", $options); 72 | 73 | // Tell Tropo what to do when the user has entered input, or if there's a problem. This redirects to the instructions under dispatch_post('/choice', 'app_choice') or dispatch_post('/incomplete', 'app_incomplete'). 74 | $tropo->on(array("event" => "continue", "next" => "testapp.php?uri=choice", "say" => "Please hold.")); 75 | $tropo->on(array("event" => "incomplete", "next" => "testapp.php?uri=incomplete")); 76 | 77 | } 78 | 79 | // Render the JSON for the Tropo WebAPI to consume. 80 | return $tropo->RenderJson(); 81 | 82 | } 83 | 84 | dispatch_post('/choice', 'app_choice'); 85 | function app_choice() { 86 | 87 | // Accessing the result object 88 | $result = new Result(); 89 | $choice = $result->getValue(); 90 | 91 | // Create a new instance of the Tropo object. 92 | $tropo = new Tropo(); 93 | 94 | // Provide a prompt based on the value 95 | if ($choice == "1") 96 | {$tropo->say("You picked Lord of the Rings. Did you know Gandalf is also Mag knee toe? Weird."); 97 | } 98 | if ($choice == "2") 99 | {$tropo->say("You picked the original Star Wars. I hear Leonard Nimoy was awe some in those."); 100 | } 101 | if ($choice == "3") 102 | {$tropo->say("You picked the Star Wars prequels. Stop calling this number, Mr. Lucas, we know it's you."); 103 | } 104 | if ($choice == "4") 105 | {$tropo->say("You picked the Matrix. Dude, woe."); 106 | } 107 | 108 | // Tell Tropo what to do next. This redirects to the instructions under dispatch_post('/hangup', 'app_hangup'). 109 | $tropo->on(array("event" => "continue", "next" => "testapp.php?uri=hangup")); 110 | 111 | // Tell Tropo what to do if there's an problem, like a timeout. This redirects to the instructions under dispatch_post('/incomplete', 'app_incomplete'). 112 | $tropo->on(array("event" => "incomplete", "next" => "testapp.php?uri=incomplete")); 113 | 114 | // Render the JSON for the Tropo WebAPI to consume. 115 | return $tropo->RenderJson(); 116 | } 117 | 118 | dispatch_post('/hangup', 'app_hangup'); 119 | function app_hangup() { 120 | 121 | $tropo = new Tropo(); 122 | 123 | $tropo->say("Thanks for voting!"); 124 | $tropo->hangup(); 125 | return $tropo->RenderJson(); 126 | } 127 | 128 | dispatch_post('/incomplete', 'app_incomplete'); 129 | function app_error() { 130 | 131 | $tropo = new Tropo(); 132 | 133 | $tropo->say("Something has gone wrong, please call back."); 134 | $tropo->hangup(); 135 | return $tropo->RenderJson(); 136 | } 137 | 138 | // Run this sucker! 139 | run(); 140 | 141 | ?> -------------------------------------------------------------------------------- /tests/MessageTest.php: -------------------------------------------------------------------------------- 1 | 'sip:pengxli@192.168.26.1:5678' 12 | ); 13 | $tropo->message("This is an announcement.", $params); 14 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":{"value":"This is an announcement."},"to":"sip:pengxli@192.168.26.1:5678"}}]}'); 15 | } 16 | 17 | public function testMessageWithMMS() { 18 | $tropo = new Tropo(); 19 | $say = new Say("This is the subject",null, null, null, null, null,null,null,"http://user:pass@server.com/1.jpg"); 20 | $message = new Message($say,'sip:pengxli@192.168.26.1:5678',null, Network::$mms); 21 | $tropo->message($message); 22 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":{"value":"This is the subject","media":"http://user:pass@server.com/1.jpg"},"to":"sip:pengxli@192.168.26.1:5678","network":"MMS"}}]}'); 23 | } 24 | 25 | public function testMessageWithMMS1() { 26 | $tropo = new Tropo(); 27 | $say = new Say("This is the subject",null, null, null, null, null,null,null,array("http://server.com/1.jpg", "this is a inline text content", "http://filehosting.tropo.com/account/1/2.text")); 28 | $message = new Message($say,'sip:pengxli@192.168.26.1:5678',null, Network::$mms); 29 | $tropo->message($message); 30 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":{"value":"This is the subject","media":["http://server.com/1.jpg","this is a inline text content","http://filehosting.tropo.com/account/1/2.text"]},"to":"sip:pengxli@192.168.26.1:5678","network":"MMS"}}]}'); 31 | } 32 | 33 | public function testMessageWithExtraSayOptiions() { 34 | $tropo = new Tropo(); 35 | $say = "Remember, you have a meeting at 2 PM."; 36 | $params = array( 37 | 'say' => $say, 38 | 'to' => 'sip:pengxli@192.168.26.1:5678' 39 | ); 40 | $tropo->message("This is an announcement.", $params); 41 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":[{"value":"This is an announcement."},{"value":"Remember, you have a meeting at 2 PM."}],"to":"sip:pengxli@192.168.26.1:5678"}}]}'); 42 | } 43 | 44 | public function testMessageWithAllOptions() { 45 | $tropo = new Tropo(); 46 | $say = array('Remember, you have a meeting at 2 PM.', 'This is tropo.com.'); 47 | $to = array('sip:pengxli@192.168.26.1:5678', 'sip:pengxli@172.16.72.131:5678'); 48 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 49 | $params = array( 50 | 'say' => $say, 51 | 'to' => $to, 52 | 'answerOnMedia' => false, 53 | 'channel' => Channel::$voice, 54 | 'from' => '3055551000', 55 | 'network' => Network::$sip, 56 | 'required' => true, 57 | 'timeout' => 60, 58 | 'voice' => Voice::$US_English_female_allison, 59 | 'promptLogSecurity' => 'suppress', 60 | 'headers' => $headers 61 | ); 62 | $tropo->message("This is an announcement.", $params); 63 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":[{"value":"This is an announcement."},{"value":"Remember, you have a meeting at 2 PM."},{"value":"This is tropo.com."}],"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@172.16.72.131:5678"],"channel":"VOICE","network":"SIP","from":"3055551000","voice":"allison","timeout":60,"answerOnMedia":false,"headers":{"foo":"bar","bling":"baz"},"required":true,"promptLogSecurity":"suppress"}}]}'); 64 | } 65 | 66 | public function testCreateMinObject() { 67 | $tropo = new Tropo(); 68 | $message = new Message(new Say("This is an announcement."), "sip:pengxli@192.168.26.1:5678"); 69 | $tropo->message($message); 70 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":{"value":"This is an announcement."},"to":"sip:pengxli@192.168.26.1:5678"}}]}'); 71 | } 72 | 73 | public function testCreateObject1() { 74 | $tropo = new Tropo(); 75 | $say = array( 76 | new Say("This is an announcement."), 77 | new Say("Remember, you have a meeting at 2 PM.") 78 | ); 79 | $message = new Message($say, "sip:pengxli@192.168.26.1:5678"); 80 | $tropo->message($message); 81 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":[{"value":"This is an announcement."},{"value":"Remember, you have a meeting at 2 PM."}],"to":"sip:pengxli@192.168.26.1:5678"}}]}'); 82 | } 83 | 84 | public function testCreateObject2() { 85 | $tropo = new Tropo(); 86 | $say = array( 87 | new Say("This is an announcement."), 88 | new Say("Remember, you have a meeting at 2 PM."), 89 | new Say("This is tropo.com.") 90 | ); 91 | $to = array( 92 | 'sip:pengxli@192.168.26.1:5678', 93 | 'sip:pengxli@172.16.72.131:5678' 94 | ); 95 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 96 | $message = new Message($say, $to, Channel::$voice, Network::$sip, "3055551000", Voice::$US_English_female_allison, 60, false, $headers, null, true, "suppress"); 97 | $tropo->message($message); 98 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"message":{"say":[{"value":"This is an announcement."},{"value":"Remember, you have a meeting at 2 PM."},{"value":"This is tropo.com."}],"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@172.16.72.131:5678"],"channel":"VOICE","network":"SIP","from":"3055551000","voice":"allison","timeout":60,"answerOnMedia":false,"headers":{"foo":"bar","bling":"baz"},"required":true,"promptLogSecurity":"suppress"}}]}'); 99 | } 100 | } 101 | ?> -------------------------------------------------------------------------------- /tests/AskTest.php: -------------------------------------------------------------------------------- 1 | '[1 DIGIT]' 12 | ); 13 | $tropo->ask("Please say a digit.", $params); 14 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"ask":{"choices":{"value":"[1 DIGIT]"},"say":[{"value":"Please say a digit."}]}}]}'); 15 | } 16 | 17 | public function testAskWithExtraSayOptions() { 18 | $tropo = new Tropo(); 19 | $event = array( 20 | 'timeout' => 'Sorry, I did not hear anything.', 21 | 'nomatch:1' => "Don't think that was a year.", 22 | 'nomatch:2' => 'Nope, still not a year.' 23 | ); 24 | $params = array( 25 | 'choices' => '[4 DIGITS]', 26 | 'event' => $event, 27 | 'attempts' => 3 28 | ); 29 | $tropo->ask("What is your birth year?", $params); 30 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"ask":{"attempts":3,"choices":{"value":"[4 DIGITS]"},"say":[{"event":"timeout","value":"Sorry, I did not hear anything."},{"event":"nomatch:1","value":"Don'."'".'t think that was a year."},{"event":"nomatch:2","value":"Nope, still not a year."},{"value":"What is your birth year?"}]}}]}'); 31 | } 32 | 33 | public function testAskWithAllOptions() { 34 | $tropo = new Tropo(); 35 | $allowSignals = array('quit', 'exit'); 36 | $event = array( 37 | 'timeout' => 'Sorry, I did not hear anything.', 38 | 'nomatch:1' => "Don't think that was a year.", 39 | 'nomatch:2' => 'Nope, still not a year.' 40 | ); 41 | $params = array( 42 | 'choices' => '[4 DIGITS]', 43 | 'mode' => 'dtmf', 44 | 'terminator' => '#', 45 | 'allowSignals' => $allowSignals, 46 | 'attempts' => 3, 47 | 'bargein' => true, 48 | 'interdigitTimeout' => 5.0, 49 | 'minConfidence' => 30.0, 50 | 'name' => 'foo', 51 | 'recognizer' => Recognizer::$US_English, 52 | 'required' => true, 53 | 'event' => $event, 54 | 'sensitivity' => 0.5, 55 | 'speechCompleteTimeout' => 0.5, 56 | 'speechIncompleteTimeout' => 0.5, 57 | 'timeout' => 30.0, 58 | 'voice' => Voice::$US_English_female_allison, 59 | 'promptLogSecurity' => 'suppress', 60 | 'asrLogSecurity' => 'mask', 61 | 'maskTemplate' => 'XXD-' 62 | ); 63 | $tropo->ask("What is your birth year?", $params); 64 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"ask":{"attempts":3,"bargein":true,"choices":{"value":"[4 DIGITS]","mode":"dtmf","terminator":"#"},"minConfidence":30,"name":"foo","required":true,"say":[{"event":"timeout","value":"Sorry, I did not hear anything."},{"event":"nomatch:1","value":"Don'."'".'t think that was a year."},{"event":"nomatch:2","value":"Nope, still not a year."},{"value":"What is your birth year?"}],"timeout":30,"voice":"allison","allowSignals":["quit","exit"],"recognizer":"en-us","interdigitTimeout":5,"sensitivity":0.5,"speechCompleteTimeout":0.5,"speechIncompleteTimeout":0.5,"promptLogSecurity":"suppress","asrLogSecurity":"mask","maskTemplate":"XXD-"}}]}'); 65 | } 66 | 67 | public function testCreateAskObject() { 68 | $tropo = new Tropo(); 69 | $ask = new Ask(null, null, new Choices('[1 DIGIT]'), null, null, null, array(new Say("Please say a digit."))); 70 | $tropo ->ask($ask); 71 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"ask":{"choices":{"value":"[1 DIGIT]"},"say":[{"value":"Please say a digit."}]}}]}'); 72 | } 73 | 74 | public function testCreateAskObject1() { 75 | $tropo = new Tropo(); 76 | $ask = new Ask(3, null, new Choices('[4 DIGITS]'), null, null, null, array(new Say("Sorry, I did not hear anything.", null, "timeout"), new Say("Don't think that was a year.", null , "nomatch:1"), new Say("Nope, still not a year.", null, "nomatch:2"), new Say("What is your birth year?"))); 77 | $tropo ->ask($ask); 78 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"ask":{"attempts":3,"choices":{"value":"[4 DIGITS]"},"say":[{"event":"timeout","value":"Sorry, I did not hear anything."},{"event":"nomatch:1","value":"Don'."'".'t think that was a year."},{"event":"nomatch:2","value":"Nope, still not a year."},{"value":"What is your birth year?"}]}}]}'); 79 | } 80 | 81 | public function testCreateAskObject2() { 82 | $tropo = new Tropo(); 83 | $choices = new Choices("[4 DIGITS]", "dtmf", "#"); 84 | $say = array( 85 | new Say("Sorry, I did not hear anything.", null, "timeout"), 86 | new Say("Don't think that was a year.", null , "nomatch:1"), 87 | new Say("Nope, still not a year.", null, "nomatch:2"), 88 | new Say("What is your birth year?") 89 | ); 90 | $allowSignals = array('quit', 'exit'); 91 | $ask = new Ask(3, true, $choices, 30.0, "foo", true, $say, 30.0, Voice::$US_English_female_allison, $allowSignals, Recognizer::$US_English, 5.0, 0.5, 0.5, 0.5, "suppress", "mask", "XXD-"); 92 | $tropo ->ask($ask); 93 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"ask":{"attempts":3,"bargein":true,"choices":{"value":"[4 DIGITS]","mode":"dtmf","terminator":"#"},"minConfidence":30,"name":"foo","required":true,"say":[{"event":"timeout","value":"Sorry, I did not hear anything."},{"event":"nomatch:1","value":"Don'."'".'t think that was a year."},{"event":"nomatch:2","value":"Nope, still not a year."},{"value":"What is your birth year?"}],"timeout":30,"voice":"allison","allowSignals":["quit","exit"],"recognizer":"en-us","interdigitTimeout":5,"sensitivity":0.5,"speechCompleteTimeout":0.5,"speechIncompleteTimeout":0.5,"promptLogSecurity":"suppress","asrLogSecurity":"mask","maskTemplate":"XXD-"}}]}'); 94 | } 95 | } 96 | ?> -------------------------------------------------------------------------------- /tests/RecordTest.php: -------------------------------------------------------------------------------- 1 | 'http://192.168.26.203/tropo-webapi-php/upload_file.php' 12 | ); 13 | $tropo->record($record); 14 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"}}}]}'); 15 | } 16 | 17 | public function testRecordWithMinOptions1() { 18 | $tropo = new Tropo(); 19 | $url = new Url('http://192.168.26.203/tropo-webapi-php/upload_file.php', 'root', '111111', 'POST'); 20 | $record = array( 21 | 'url' => $url 22 | ); 23 | $tropo->record($record); 24 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"}}}]}'); 25 | } 26 | 27 | public function testRecordWithMinOptions2() { 28 | $tropo = new Tropo(); 29 | $url = array( 30 | new Url('http://192.168.26.203/tropo-webapi-php/upload_file.php', 'root', '111111', 'POST'), 31 | new Url('http://192.168.26.204/tropo-webapi-php/upload_file.php') 32 | ); 33 | $record = array( 34 | 'url' => $url 35 | ); 36 | $tropo->record($record); 37 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"url":[{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"},{"url":"http://192.168.26.204/tropo-webapi-php/upload_file.php"}]}}]}'); 38 | } 39 | 40 | public function testRecordWithAllOptions() { 41 | $tropo = new Tropo(); 42 | $allowSignals = array('exit', 'quit'); 43 | $event = array( 44 | 'timeout' => 'Sorry, I did not hear anything. Please call back.' 45 | ); 46 | $transcription = array( 47 | 'id' => '1234', 48 | 'url' => 'mailto:you@yourmail.com', 49 | 'emailFormat' => 'omit', 50 | 'language' => 'en-uk' 51 | ); 52 | $record = array( 53 | 'attempts' => 2, 54 | 'asyncUpload' => false, 55 | 'allowSignals' => $allowSignals, 56 | 'bargein' => true, 57 | 'beep' => true, 58 | 'choices' => '*', 59 | 'say' => 'Please leave a message.', 60 | 'event' => $event, 61 | 'format' => AudioFormat::$mp3, 62 | 'maxSilence' => 5.0, 63 | 'maxTime' => 30.0, 64 | 'method' => 'POST', 65 | 'required' => true, 66 | 'transcription' => $transcription, 67 | 'url' => 'http://192.168.26.203/tropo-webapi-php/upload_file.php', 68 | 'password' => '111111', 69 | 'username' => 'root', 70 | 'timeout' => 30.0, 71 | 'interdigitTimeout' => 5.0, 72 | 'voice' => Voice::$US_English_female_allison, 73 | 'promptLogSecurity' => 'suppress' 74 | ); 75 | $tropo->record($record); 76 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"attempts":2,"allowSignals":["exit","quit"],"bargein":true,"beep":true,"choices":{"terminator":"*"},"format":"audio/mp3","maxSilence":5,"maxTime":30,"required":true,"say":[{"value":"Please leave a message."},{"event":"timeout","value":"Sorry, I did not hear anything. Please call back."}],"timeout":30,"transcription":{"id":"1234","url":"mailto:you@yourmail.com","emailFormat":"omit","language":"en-uk"},"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"},"voice":"allison","interdigitTimeout":5,"asyncUpload":false,"promptLogSecurity":"suppress"}}]}'); 77 | } 78 | 79 | 80 | public function testCreateMinObject() { 81 | $tropo = new Tropo(); 82 | $record = new Record(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "http://192.168.26.203/tropo-webapi-php/upload_file.php"); 83 | $tropo->record($record); 84 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"}}}]}'); 85 | } 86 | 87 | public function testCreateObject() { 88 | $tropo = new Tropo(); 89 | $allowSignals = array('exit', 'quit'); 90 | $choices = new Choices(null, null, "*"); 91 | $say = array( 92 | new Say("Please leave a message."), 93 | new Say("Sorry, I did not hear anything. Please call back.", null , "timeout") 94 | ); 95 | $transcription = new Transcription("mailto:you@yourmail.com", "1234", "omit", "en-uk"); 96 | $record = new Record(2, $allowSignals, true, true, $choices, AudioFormat::$mp3, 5.0, 30.0, "POST", "111111", true, $say, 30.0, $transcription, "root", "http://192.168.26.203/tropo-webapi-php/upload_file.php", Voice::$US_English_female_allison, null, 5.0, false, null, "suppress"); 97 | $tropo->record($record); 98 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"attempts":2,"allowSignals":["exit","quit"],"bargein":true,"beep":true,"choices":{"terminator":"*"},"format":"audio/mp3","maxSilence":5,"maxTime":30,"required":true,"say":[{"value":"Please leave a message."},{"event":"timeout","value":"Sorry, I did not hear anything. Please call back."}],"timeout":30,"transcription":{"id":"1234","url":"mailto:you@yourmail.com","emailFormat":"omit","language":"en-uk"},"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php","username":"root","password":"111111","method":"POST"},"voice":"allison","interdigitTimeout":5,"asyncUpload":false,"promptLogSecurity":"suppress"}}]}'); 99 | } 100 | 101 | public function testRecordWithSensitivity() { 102 | $tropo = new Tropo(); 103 | $record = array( 104 | 'url' => 'http://192.168.26.203/tropo-webapi-php/upload_file.php', 105 | 'sensitivity' => 0.5 106 | ); 107 | $tropo->record($record); 108 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"},"sensitivity":0.5}}]}'); 109 | } 110 | 111 | public function testCreateObjectWithSensitivity() { 112 | $tropo = new Tropo(); 113 | $record = new Record(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "http://192.168.26.203/tropo-webapi-php/upload_file.php", null, null, null, null, null, null, 0.5); 114 | $tropo->record($record); 115 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"record":{"url":{"url":"http://192.168.26.203/tropo-webapi-php/upload_file.php"},"sensitivity":0.5}}]}'); 116 | } 117 | 118 | } 119 | ?> -------------------------------------------------------------------------------- /tests/SayTest.php: -------------------------------------------------------------------------------- 1 | say("Please enter your account number..."); 10 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number..."}]}]}'); 11 | } 12 | 13 | public function testSayWithOptions() { 14 | $tropo = new Tropo(); 15 | $tropo->say("Please enter your account number...",array('name' => 'say')); 16 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","name":"say"}]}]}'); 17 | } 18 | 19 | public function testSayWithOptions1() { 20 | $tropo = new Tropo(); 21 | $tropo->say("Please enter your account number...",array('name' => 'say','media' => 'http://user:pass@server.com/1.jpg')); 22 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","name":"say","media":"http://user:pass@server.com/1.jpg"}]}]}'); 23 | } 24 | 25 | public function testSayWithOptions2() { 26 | $tropo = new Tropo(); 27 | $tropo->say("Please enter your account number...",array('name' => 'say','media' => array('http://server.com/1.jpg', 'this is a inline text content', 'http://filehosting.tropo.com/account/1/2.text'))); 28 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","name":"say","media":["http://server.com/1.jpg","this is a inline text content","http://filehosting.tropo.com/account/1/2.text"]}]}]}'); 29 | } 30 | 31 | public function testCreateSayObject() 32 | { 33 | $tropo = new Tropo(); 34 | $allowSignals = array('exit','quit'); 35 | $say = new Say("Please enter your account number...", SayAs::$date, null, Voice::$US_English_female_allison, $allowSignals, null, true, "suppress"); 36 | $tropo->say($say); 37 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","as":"DATE","voice":"allison","allowSignals":["exit","quit"],"required":true,"promptLogSecurity":"suppress"}]}]}'); 38 | } 39 | 40 | public function testCreateSayObject1() 41 | { 42 | $tropo = new Tropo(); 43 | $allowSignals = array('exit','quit'); 44 | $params = array( 45 | "as"=>SayAs::$date, 46 | "event"=>"event", 47 | "voice"=>Voice::$US_English_female_allison, 48 | "allowSignals"=>$allowSignals, 49 | "promptLogSecurity"=>"suppress", 50 | "required"=>true); 51 | $tropo->say("Please enter your account number...",$params); 52 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","as":"DATE","voice":"allison","allowSignals":["exit","quit"],"required":true,"promptLogSecurity":"suppress"}]}]}'); 53 | } 54 | 55 | public function testCreateSayObject2() 56 | { 57 | $tropo = new Tropo(); 58 | $allowSignals = array('exit','quit'); 59 | $say = new Say("Please enter your account number...", SayAs::$date, null, Voice::$US_English_female_allison, $allowSignals, null, true, "suppress", "http://user:pass@server.com/1.jpg"); 60 | $tropo->say($say); 61 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","as":"DATE","voice":"allison","allowSignals":["exit","quit"],"required":true,"promptLogSecurity":"suppress","media":"http://user:pass@server.com/1.jpg"}]}]}'); 62 | } 63 | 64 | public function testCreateSayObject3() 65 | { 66 | $tropo = new Tropo(); 67 | $allowSignals = array('exit','quit'); 68 | $say = new Say("Please enter your account number...", SayAs::$date, null, Voice::$US_English_female_allison, $allowSignals, null, true, "suppress", array('http://server.com/1.jpg', 'this is a inline text content', 'http://filehosting.tropo.com/account/1/2.text')); 69 | $tropo->say($say); 70 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","as":"DATE","voice":"allison","allowSignals":["exit","quit"],"required":true,"promptLogSecurity":"suppress","media":["http://server.com/1.jpg","this is a inline text content","http://filehosting.tropo.com/account/1/2.text"]}]}]}'); 71 | } 72 | 73 | public function testCreateSayObject4() 74 | { 75 | $tropo = new Tropo(); 76 | $allowSignals = array('exit','quit'); 77 | $params = array( 78 | "as"=>SayAs::$date, 79 | "event"=>"event", 80 | "voice"=>Voice::$US_English_female_allison, 81 | "allowSignals"=>$allowSignals, 82 | "promptLogSecurity"=>"suppress", 83 | "required"=>true, 84 | "media"=>"http://user:pass@server.com/1.jpg"); 85 | $tropo->say("Please enter your account number...",$params); 86 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","as":"DATE","voice":"allison","allowSignals":["exit","quit"],"required":true,"promptLogSecurity":"suppress","media":"http://user:pass@server.com/1.jpg"}]}]}'); 87 | } 88 | 89 | public function testCreateSayObject5() 90 | { 91 | $tropo = new Tropo(); 92 | $allowSignals = array('exit','quit'); 93 | $params = array( 94 | "as"=>SayAs::$date, 95 | "event"=>"event", 96 | "voice"=>Voice::$US_English_female_allison, 97 | "allowSignals"=>$allowSignals, 98 | "promptLogSecurity"=>"suppress", 99 | "required"=>true, 100 | "media"=>array('http://server.com/1.jpg', 'this is a inline text content', 'http://filehosting.tropo.com/account/1/2.text')); 101 | $tropo->say("Please enter your account number...",$params); 102 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"say":[{"value":"Please enter your account number...","as":"DATE","voice":"allison","allowSignals":["exit","quit"],"required":true,"promptLogSecurity":"suppress","media":["http://server.com/1.jpg","this is a inline text content","http://filehosting.tropo.com/account/1/2.text"]}]}]}'); 103 | } 104 | 105 | public function testFailsSayWithNoValueParameter1() 106 | { 107 | try{ 108 | @ $say = new Say(null); 109 | } catch (Exception $e) { 110 | $this->assertEquals($e->getMessage(), "Missing required property: 'value'"); 111 | } 112 | } 113 | 114 | public function testFailsSayWithNoValueParameter2() 115 | { 116 | try{ 117 | @ $say = new Say(""); 118 | } catch (Exception $e) { 119 | $this->assertEquals($e->getMessage(), "Missing required property: 'value'"); 120 | } 121 | } 122 | 123 | public function testFailsSayWithNoValueParameter4() 124 | { 125 | $tropo = new Tropo(); 126 | try{ 127 | @ $tropo->say(null); 128 | } catch (Exception $e) { 129 | $this->assertEquals($e->getMessage(), "Argument 1 passed to Tropo::say() must be a string or an instance of Say."); 130 | } 131 | } 132 | 133 | public function testFailsSayWithNoValueParameter5() 134 | { 135 | $tropo = new Tropo(); 136 | try{ 137 | @ $tropo->say(""); 138 | } catch (Exception $e) { 139 | $this->assertEquals($e->getMessage(), "Argument 1 passed to Tropo::say() must be a string or an instance of Say."); 140 | } 141 | } 142 | } 143 | ?> -------------------------------------------------------------------------------- /tests/CallTest.php: -------------------------------------------------------------------------------- 1 | call("sip:pengxli@192.168.26.1:5678"); 11 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":"sip:pengxli@192.168.26.1:5678"}}]}'); 12 | } 13 | 14 | public function testCallWithExtraToOptiions() { 15 | $tropo = new Tropo(); 16 | $call = array('sip:pengxli@192.168.26.1:5678', 'sip:pengxli@192.168.26.206:5678'); 17 | $tropo->call($call); 18 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@192.168.26.206:5678"]}}]}'); 19 | } 20 | 21 | public function testCallWithAllOptions() { 22 | $tropo = new Tropo(); 23 | $call = array('sip:pengxli@192.168.26.1:5678', 'sip:pengxli@192.168.26.206:5678'); 24 | $allowSignals = array('exit', 'quit'); 25 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 26 | $params = array( 27 | 'allowSignals' => $allowSignals, 28 | 'answerOnMedia' => false, 29 | 'channel' => Channel::$voice, 30 | 'from' => '3055551000', 31 | 'headers' => $headers, 32 | 'machineDetection' => false, 33 | 'network' => Network::$sip, 34 | 'required' => true, 35 | 'timeout' => 30.0, 36 | 'voice' => Voice::$US_English_female_allison, 37 | 'callbackUrl' => 'http://192.168.26.203/result.php', 38 | 'promptLogSecurity' => 'suppress', 39 | 'label' => 'callLabel' 40 | ); 41 | $tropo->call($call, $params); 42 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@192.168.26.206:5678"],"from":"3055551000","network":"SIP","channel":"VOICE","timeout":30,"answerOnMedia":false,"headers":{"foo":"bar","bling":"baz"},"allowSignals":["exit","quit"],"machineDetection":false,"voice":"allison","required":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"callLabel"}}]}'); 43 | } 44 | 45 | public function testCallWithAllOptions1() { 46 | $tropo = new Tropo(); 47 | $call = array('sip:pengxli@192.168.26.1:5678', 'sip:pengxli@192.168.26.206:5678'); 48 | $allowSignals = array('exit', 'quit'); 49 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 50 | $params = array( 51 | 'allowSignals' => $allowSignals, 52 | 'answerOnMedia' => false, 53 | 'channel' => Channel::$voice, 54 | 'from' => '3055551000', 55 | 'headers' => $headers, 56 | 'machineDetection' => 'For the most accurate results, the "introduction" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.', 57 | 'network' => Network::$sip, 58 | 'required' => true, 59 | 'timeout' => 30.0, 60 | 'voice' => Voice::$US_English_female_allison, 61 | 'callbackUrl' => 'http://192.168.26.203/result.php', 62 | 'promptLogSecurity' => 'suppress', 63 | 'label' => 'callLabel' 64 | ); 65 | $tropo->call($call, $params); 66 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@192.168.26.206:5678"],"from":"3055551000","network":"SIP","channel":"VOICE","timeout":30,"answerOnMedia":false,"headers":{"foo":"bar","bling":"baz"},"allowSignals":["exit","quit"],"machineDetection":{"introduction":"For the most accurate results, the \"introduction\" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.","voice":"allison"},"voice":"allison","required":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"callLabel"}}]}'); 67 | } 68 | 69 | public function testCreateMinObject() { 70 | $tropo = new Tropo(); 71 | $call = new Call("sip:pengxli@192.168.26.1:5678"); 72 | $tropo->call($call); 73 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":"sip:pengxli@192.168.26.1:5678"}}]}'); 74 | } 75 | 76 | public function testCreateObject1() { 77 | $tropo = new Tropo(); 78 | $to = array("sip:pengxli@192.168.26.1:5678", "sip:pengxli@172.16.72.131:5678"); 79 | $call = new Call($to); 80 | $tropo->call($call); 81 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@172.16.72.131:5678"]}}]}'); 82 | } 83 | 84 | public function testCreateObject2() { 85 | $tropo = new Tropo(); 86 | $to = array("sip:pengxli@192.168.26.1:5678", "sip:pengxli@172.16.72.131:5678"); 87 | $allowSignals = array('exit', 'quit'); 88 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 89 | $call = new Call($to, "3055551000", Network::$sip, Channel::$voice, false, 30.0, $headers, null, $allowSignals, false, Voice::$US_English_female_allison, null, true, "http://192.168.26.203/result.php", "suppress", "callLabel"); 90 | $tropo->call($call); 91 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@172.16.72.131:5678"],"from":"3055551000","network":"SIP","channel":"VOICE","timeout":30,"answerOnMedia":false,"headers":{"foo":"bar","bling":"baz"},"allowSignals":["exit","quit"],"machineDetection":false,"voice":"allison","required":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"callLabel"}}]}'); 92 | } 93 | 94 | public function testCreateObject3() { 95 | $tropo = new Tropo(); 96 | $to = array("sip:pengxli@192.168.26.1:5678", "sip:pengxli@172.16.72.131:5678"); 97 | $allowSignals = array('exit', 'quit'); 98 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 99 | $machineDetection = 'For the most accurate results, the "introduction" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.'; 100 | $call = new Call($to, "3055551000", Network::$sip, Channel::$voice, false, 30.0, $headers, null, $allowSignals, $machineDetection, Voice::$US_English_female_allison, null, true, "http://192.168.26.203/result.php", "suppress", "callLabel"); 101 | $tropo->call($call); 102 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"call":{"to":["sip:pengxli@192.168.26.1:5678","sip:pengxli@172.16.72.131:5678"],"from":"3055551000","network":"SIP","channel":"VOICE","timeout":30,"answerOnMedia":false,"headers":{"foo":"bar","bling":"baz"},"allowSignals":["exit","quit"],"machineDetection":{"introduction":"For the most accurate results, the \"introduction\" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.","voice":"allison"},"voice":"allison","required":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"callLabel"}}]}'); 103 | } 104 | } 105 | ?> -------------------------------------------------------------------------------- /tests/ResultTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($result->getSessionId(), '26a5aa37ff9d14d11990a48865abb5d2'); 12 | $this->assertEquals($result->getCallId(), 'b11948c7073e815a768fd3f393cc92a6'); 13 | $this->assertEquals($result->getState(), 'ANSWERED'); 14 | $this->assertEquals($result->getSessionDuration(), 158); 15 | $this->assertEquals($result->getSequence(), 1); 16 | $this->assertEquals($result->isComplete(), true); 17 | $this->assertEquals($result->getError(), null); 18 | $this->assertEquals($result->getCalledid(), '9992801029'); 19 | $this->assertEquals($result->getUserType(), null); 20 | $this->assertEquals($result->getName(), 'foo'); 21 | $this->assertEquals($result->getAttempts(), null); 22 | $this->assertEquals($result->getDisposition(), 'SUCCESS'); 23 | $this->assertEquals($result->getConfidence(), null); 24 | $this->assertEquals($result->getInterpretation(), null); 25 | $this->assertEquals($result->getUtterance(), null); 26 | $this->assertEquals($result->getValue(), null); 27 | $this->assertEquals($result->getConcept(), null); 28 | $this->assertEquals($result->getXml(), null); 29 | $this->assertEquals($result->getUploadStatus(), null); 30 | $this->assertEquals($result->getDuration(), 149); 31 | $this->assertEquals($result->getConnectedDuration(), 145); 32 | $this->assertEquals($result->getUrl(), null); 33 | $this->assertEquals($result->getActionUserType(), 'HUMAN'); 34 | } 35 | 36 | public function testResult1() { 37 | $json = '{"result":{"sessionId":"26a5aa37ff9d14d11990a48865abb5d2","callId":"b11948c7073e815a768fd3f393cc92a6","state":"ANSWERED","sessionDuration":158,"sequence":1,"complete":true,"error":null,"calledid":"9992801029","actions":{"name":"foo","duration":149,"connectedDuration":145,"disposition":"SUCCESS","timestamp":"2017-06-23T02:45:22.849Z","calledid":"pengxli","userType":"HUMAN"}}}'; 38 | $result = new Result($json); 39 | $this->assertEquals($result->getSessionId(), '26a5aa37ff9d14d11990a48865abb5d2'); 40 | $this->assertEquals($result->getCallId(), 'b11948c7073e815a768fd3f393cc92a6'); 41 | $this->assertEquals($result->getState(), 'ANSWERED'); 42 | $this->assertEquals($result->getSessionDuration(), 158); 43 | $this->assertEquals($result->getSequence(), 1); 44 | $this->assertEquals($result->isComplete(), true); 45 | $this->assertEquals($result->getError(), null); 46 | $this->assertEquals($result->getCalledid(), '9992801029'); 47 | $this->assertEquals($result->getUserType(), null); 48 | $actions = $result->getActions(); 49 | $action = $actions; 50 | $this->assertEquals($result->getNameFromAction($action), 'foo'); 51 | $this->assertEquals($result->getAttemptsFromAction($action), null); 52 | $this->assertEquals($result->getDispositionFromAction($action), 'SUCCESS'); 53 | $this->assertEquals($result->getConfidenceFromAction($action), null); 54 | $this->assertEquals($result->getInterpretationFromAction($action), null); 55 | $this->assertEquals($result->getUtteranceFromAction($action), null); 56 | $this->assertEquals($result->getValueFromAction($action), null); 57 | $this->assertEquals($result->getConceptFromAction($action), null); 58 | $this->assertEquals($result->getXmlFromAction($action), null); 59 | $this->assertEquals($result->getUploadStatusFromAction($action), null); 60 | $this->assertEquals($result->getDurationFromAction($action), 149); 61 | $this->assertEquals($result->getConnectedDurationFromAction($action), 145); 62 | $this->assertEquals($result->getUrlFromAction($action), null); 63 | $this->assertEquals($result->getActionUserTypeFromAction($action), 'HUMAN'); 64 | } 65 | 66 | public function testResult2() { 67 | $json = '{"result":{"sessionId":"349e753764123e3b90245162a0f7758a","callId":"925f666b73ea1e41211d624489deea17","state":"ANSWERED","sessionDuration":13,"sequence":1,"complete":true,"error":null,"calledid":"9992801029","actions":[{"name":"foo","attempts":1,"disposition":"SUCCESS","confidence":100,"interpretation":"1234","utterance":"1234","value":"1234","xml":"\\r\\n\\r\\n \\r\\n \\r\\n 1234<\\/input>\\r\\n <\\/interpretation>\\r\\n<\\/result>\\r\\n"},{"name":"foo","attempts":1,"disposition":"SUCCESS","confidence":100,"interpretation":"1234","utterance":"1234","value":"1234","xml":"\\r\\n\\r\\n \\r\\n \\r\\n 1234<\\/input>\\r\\n <\\/interpretation>\\r\\n<\\/result>\\r\\n"}]}}'; 68 | $result = new Result($json); 69 | $this->assertEquals($result->getSessionId(), '349e753764123e3b90245162a0f7758a'); 70 | $this->assertEquals($result->getCallId(), '925f666b73ea1e41211d624489deea17'); 71 | $this->assertEquals($result->getState(), 'ANSWERED'); 72 | $this->assertEquals($result->getSessionDuration(), 13); 73 | $this->assertEquals($result->getSequence(), 1); 74 | $this->assertEquals($result->isComplete(), true); 75 | $this->assertEquals($result->getError(), null); 76 | $this->assertEquals($result->getCalledid(), '9992801029'); 77 | $this->assertEquals($result->getUserType(), null); 78 | $actions = $result->getActions(); 79 | $action = $actions[0]; 80 | $this->assertEquals($result->getNameFromAction($action), 'foo'); 81 | $this->assertEquals($result->getAttemptsFromAction($action), 1); 82 | $this->assertEquals($result->getDispositionFromAction($action), 'SUCCESS'); 83 | $this->assertEquals($result->getConfidenceFromAction($action), 100); 84 | $this->assertEquals($result->getInterpretationFromAction($action), '1234'); 85 | $this->assertEquals($result->getUtteranceFromAction($action), '1234'); 86 | $this->assertEquals($result->getValueFromAction($action), '1234'); 87 | $this->assertEquals($result->getConceptFromAction($action), null); 88 | $this->assertEquals($result->getXmlFromAction($action), "\r\n\r\n \r\n \r\n 1234\r\n \r\n\r\n"); 89 | $this->assertEquals($result->getUploadStatusFromAction($action), null); 90 | $this->assertEquals($result->getDurationFromAction($action), null); 91 | $this->assertEquals($result->getConnectedDurationFromAction($action), null); 92 | $this->assertEquals($result->getUrlFromAction($action), null); 93 | $this->assertEquals($result->getActionUserTypeFromAction($action), null); 94 | $this->assertEquals($result->getTranscriptionFromAction($action), null); 95 | } 96 | } 97 | ?> -------------------------------------------------------------------------------- /tropo-rest.class.php: -------------------------------------------------------------------------------- 1 | true'; 18 | 19 | public function __construct() { 20 | parent::__construct(); 21 | } 22 | 23 | 24 | public function setBaseURL($url) { 25 | $this->base = $url; 26 | } 27 | 28 | protected function getBaseURL() { 29 | return $this->base; 30 | } 31 | 32 | /** 33 | * Launch a new Tropo session. 34 | * 35 | * @param string $token 36 | * @param array $params 37 | * @return boolean 38 | */ 39 | public function createSession($token, Array $params = null) { 40 | 41 | $querystring = ''; 42 | if(isset($params)) { 43 | foreach ($params as $key=>$value) { 44 | @ $querystring .= '&'. urlencode($key) . '=' . urlencode($value); 45 | } 46 | } 47 | 48 | curl_setopt($this->ch, CURLOPT_URL, $this->base . 'sessions?action=create&token=' . $token . $querystring); 49 | curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1); 50 | $result = curl_exec($this->ch); 51 | $error = curl_error($this->ch); 52 | parent::__destruct(); 53 | 54 | //check result and parse 55 | if($result === false OR !($xml = new SimpleXMLElement($result))) { 56 | throw new Exception('An error occurred: '.$error); 57 | } else { 58 | if(!($xml->success == 'true')){ 59 | throw new Exception('An error occurred: Tropo session launch failed.'); 60 | } 61 | return trim((string) $xml->id); 62 | } 63 | } 64 | } 65 | 66 | class EventAPI extends RestBase { 67 | 68 | // URL for the Tropo session API. 69 | var $base = 'https://api.tropo.com/1.0/'; 70 | 71 | // Success response from Tropo Session API. 72 | const EventResponse = 'QUEUED'; 73 | 74 | public function __construct() { 75 | parent::__construct(); 76 | } 77 | 78 | /** 79 | * Send an event into a running Tropo session. 80 | * 81 | * @param string $token 82 | * @param array $params 83 | * @return boolean 84 | */ 85 | public function sendEvent($session_id, $event) { 86 | 87 | $url = $this->base . '%session_id%/signals?action=signal&value=%value%'; 88 | $url = str_replace(array('%session_id%', '%value%'), array($session_id, $event), $url); 89 | 90 | curl_setopt($this->ch, CURLOPT_URL, $url); 91 | curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1); 92 | $result = curl_exec($this->ch); 93 | $error = curl_error($this->ch); 94 | parent::__destruct(); 95 | 96 | if($result === false) { 97 | throw new Exception('An error occurred: '.$error); 98 | } else { 99 | if (strpos($result, self::EventResponse) === false) { 100 | throw new Exception('An error occurred: Tropo event injection failed.'); 101 | } 102 | return true; 103 | } 104 | } 105 | } 106 | 107 | class ProvisioningAPI extends RestBase { 108 | 109 | // URLs for the Tropo provisioning API. 110 | //const ApplicationProvisioningURLBase = 'https://api.tropo.com/v1/'; 111 | var $base = 'https://api.tropo.com/v1/'; 112 | 113 | public function __construct($userid, $password) { 114 | parent::__construct($userid, $password); 115 | } 116 | 117 | public function setBaseURL($url) { 118 | $this->base = $url; 119 | } 120 | 121 | protected function getBaseURL() { 122 | return $this->base; 123 | } 124 | 125 | /** 126 | * Create a new Tropo application. 127 | * 128 | * @param string $href 129 | * @param string $name 130 | * @param string $voiceUrl 131 | * @param string $messagingUrl 132 | * @param string $platform 133 | * @param string $partition 134 | * @return string JSON 135 | */ 136 | public function createApplication($href, $name, $voiceUrl, $messagingUrl, $platform, $partition) { 137 | 138 | $payload = json_encode(new Application($href, $name, $voiceUrl, $messagingUrl, $platform, $partition)); 139 | $url = $this->base . 'applications'; 140 | return self::makeAPICall('POST', $url, $payload); 141 | 142 | } 143 | 144 | /** 145 | * Update an existing Tropo application to add an address. 146 | * 147 | * @param string $applicationID 148 | * @param string $type 149 | * @param string $prefix 150 | * @param string $number 151 | * @param string $city 152 | * @param string $state 153 | * @param string $channel 154 | * @param string $username 155 | * @param string $password 156 | * @param string $token 157 | * @return string JSON 158 | */ 159 | public function updateApplicationAddress($applicationID, $type, $prefix=NULL, $number=NULL, $city=NULL, $state=NULL, $channel=NULL, $username=NULL, $password=NULL, $token=NULL) { 160 | 161 | $payload = json_encode(new Address($type, $prefix, $number, $city, $state, $channel, $username, $password, $token)); 162 | $url = $this->base . 'applications/'.$applicationID.'/addresses'; 163 | return self::makeAPICall('POST', $url, $payload); 164 | 165 | } 166 | 167 | /** 168 | * Update an application property. 169 | * 170 | * @param string $applicationID 171 | * @param string $href 172 | * @param string $name 173 | * @param string $voiceUrl 174 | * @param string $messagingUrl 175 | * @param string $platform 176 | * @param string $partition 177 | * @return string JSON 178 | */ 179 | public function updateApplicationProperty($applicationID, $href=NULL, $name=NULL, $voiceUrl=NULL, $messagingUrl=NULL, $platform=NULL, $partition=NULL) { 180 | 181 | $payload = json_encode(new Application($href, $name, $voiceUrl, $messagingUrl, $platform, $partition)); 182 | $url = $this->base . 'applications/'.$applicationID; 183 | return self::makeAPICall('PUT', $url, $payload); 184 | 185 | } 186 | 187 | /** 188 | * Delete an existing Tropo application. 189 | * 190 | * @param string $applicationID 191 | * @return string JSON 192 | */ 193 | public function deleteApplication($applicationID) { 194 | 195 | $url = $this->base . 'applications/'.$applicationID; 196 | return self::makeAPICall('DELETE', $url); 197 | 198 | } 199 | 200 | /** 201 | * Delete an application address. 202 | * 203 | * @param string $applicationID 204 | * @param string $type 205 | * @param string $address 206 | * @return string JSON 207 | */ 208 | public function deleteApplicationAddress($applicationID, $type, $address) { 209 | 210 | $url = $this->base . 'applications/'.$applicationID.'/addresses/'.$type.'/'.$address; 211 | return self::makeAPICall('DELETE', $url); 212 | 213 | } 214 | 215 | /** 216 | * View all applications for an account. 217 | * 218 | * @return string JSON 219 | */ 220 | public function viewApplications() { 221 | 222 | $url = $this->base . 'applications'; 223 | return self::makeAPICall('GET', $url); 224 | 225 | } 226 | 227 | /** 228 | * View the details of a specific application. 229 | * 230 | * @param string $applicationID 231 | * @return string JSON 232 | */ 233 | public function viewSpecificApplication($applicationID) { 234 | 235 | $url = $this->base . 'applications/'.$applicationID; 236 | return self::makeAPICall('GET', $url); 237 | 238 | } 239 | 240 | /** 241 | * View all of the addreses for an application. 242 | * 243 | * @param string $applicationID 244 | * @return string JSON 245 | */ 246 | public function viewAddresses($applicationID) { 247 | 248 | $url = $this->base . 'applications/'.$applicationID.'/addresses'; 249 | return self::makeAPICall('GET', $url); 250 | 251 | } 252 | 253 | /** 254 | * View a list of availalbe exchanges 255 | * 256 | * @return string JSON 257 | */ 258 | public function viewExchanges() { 259 | 260 | $url = $this->base . 'exchanges'; 261 | return self::makeAPICall('GET', $url); 262 | 263 | } 264 | 265 | /** 266 | * Method to make REST API call. 267 | * 268 | * @param string $method 269 | * @param string $url 270 | * @param string $payload 271 | * @return string JSON 272 | */ 273 | protected function makeAPICall($method, $url, $payload=NULL) { 274 | 275 | if(($method == 'POST' || $method == 'PUT') && !isset($payload)) { 276 | throw new Exception("Method $method requires payload for request body."); 277 | } 278 | 279 | curl_setopt($this->ch, CURLOPT_URL, $url); 280 | curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); 281 | 282 | switch($method) { 283 | 284 | case 'POST': 285 | curl_setopt($this->ch, CURLOPT_POST, true); 286 | curl_setopt($this->ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: '.strlen($payload))); 287 | curl_setopt($this->ch, CURLOPT_POSTFIELDS, $payload); 288 | break; 289 | 290 | case 'PUT': 291 | curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, 'PUT'); 292 | curl_setopt($this->ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: '.strlen($payload))); 293 | curl_setopt($this->ch, CURLOPT_POSTFIELDS, $payload); 294 | break; 295 | 296 | case 'DELETE': 297 | curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); 298 | 299 | default: 300 | curl_setopt($this->ch, CURLOPT_HTTPGET, true); 301 | 302 | } 303 | 304 | $this->result = curl_exec($this->ch); 305 | $this->error = curl_error($this->ch); 306 | $this->curl_info = curl_getinfo($this->ch); 307 | $this->curl_http_code = curl_getinfo($this->ch, CURLINFO_HTTP_CODE); 308 | 309 | if($this->result === false) { 310 | throw new Exception('An error occurred: '.$this->error); 311 | } else { 312 | if (substr($this->curl_http_code, 0, 1) != '2') { 313 | $body = json_decode($this->result); 314 | throw new Exception($body->error, $this->curl_http_code); 315 | } 316 | return $this->result; 317 | } 318 | } 319 | 320 | public function getResult() { 321 | return $this->result; 322 | } 323 | 324 | public function getInfo() { 325 | return $this->curl_info; 326 | } 327 | 328 | public function getHTTPCode() { 329 | return $this->curl_http_code; 330 | } 331 | 332 | public function __destruct() { 333 | parent::__destruct(); 334 | } 335 | 336 | } 337 | 338 | /** 339 | * Base class for all REST classes. 340 | * 341 | */ 342 | class RestBase { 343 | 344 | protected $ch; 345 | protected $result; 346 | protected $error; 347 | protected $curl_info; 348 | protected $curl_http_code; 349 | 350 | public function __construct($userid=NULL, $password=NULL) { 351 | if (!function_exists('curl_init')) { 352 | throw new Exception('PHP curl not installed.'); 353 | } 354 | $this->ch = curl_init(); 355 | if(isset($userid) && isset($password)) { 356 | curl_setopt($this->ch, CURLOPT_USERPWD, "$userid:$password"); 357 | } 358 | } 359 | 360 | public function __destruct() { 361 | @ curl_close($this->ch); 362 | } 363 | 364 | 365 | } 366 | 367 | /** 368 | * Application class. Represents a Tropo application. 369 | * 370 | */ 371 | class Application { 372 | 373 | public function __construct($href=NULL, $name=NULL, $voiceUrl=NULL, $messagingUrl=NULL, $platform=NULL, $partition=NULL) { 374 | if(isset($href)) { $this->href = $href; } 375 | if(isset($name)) { $this->name = $name; } 376 | if(isset($voiceUrl)) { $this->voiceUrl = $voiceUrl; } 377 | if(isset($messagingUrl)) { $this->messagingUrl = $messagingUrl; } 378 | if(isset($platform)) { $this->platform = $platform; } 379 | if(isset($partition)) { $this->partition = $partition; } 380 | } 381 | 382 | public function __set($attribute, $value) { 383 | $this->$attribute= $value; 384 | } 385 | } 386 | 387 | /** 388 | * Address class. Represents an address assigned to a Tropo application. 389 | * 390 | */ 391 | class Address { 392 | 393 | public function __construct($type=NULL, $prefix=NULL, $number=NULL, $city=NULL, $state=NULL, $channel=NULL, $username=NULL, $password=NULL, $token=NULL) { 394 | if(isset($type)) { $this->type = $type; } 395 | if(isset($prefix)) { $this->prefix = $prefix; } 396 | if(isset($number)) { $this->number = $number; } 397 | if(isset($city)) { $this->type = $type; } 398 | if(isset($state)) { $this->state = $state; } 399 | if(isset($channel)) { $this->channel = $channel; } 400 | if(isset($username)) { $this->username = $username; } 401 | if(isset($password)) { $this->password = $password; } 402 | if(isset($token)) { $this->token = $token; } 403 | } 404 | 405 | public function __set($attribute, $value) { 406 | $this->$attribute= $value; 407 | } 408 | } 409 | 410 | /** 411 | * Exchange class. Represents an exchange. 412 | * 413 | */ 414 | class Exchange { 415 | 416 | public function __construct($prefix=NULL, $city=NULL, $state=NULL, $country=NULL) { 417 | if(isset($prefix)) { $this->prefix = $prefix; } 418 | if(isset($city)) { $this->city = $city; } 419 | if(isset($state)) { $this->state = $state; } 420 | if(isset($country)) { $this->country = $country; } 421 | if(isset($description)) { $this->description = $description; } 422 | } 423 | 424 | public function __set($attribute, $value) { 425 | $this->$attribute= $value; 426 | } 427 | } 428 | /** 429 | * Helper class listing the type of addresses available to use with Tropo applications. 430 | * 431 | */ 432 | 433 | class AddressType { 434 | public static $number = "number"; 435 | public static $token = "token"; 436 | public static $aim = "aim"; 437 | public static $gtalk = "gtalk"; 438 | public static $jabber = "jabber"; 439 | public static $msn = "msn"; 440 | public static $yahoo = "yahoo"; 441 | public static $skype = "skype"; 442 | } 443 | 444 | ?> -------------------------------------------------------------------------------- /tests/TransferTest.php: -------------------------------------------------------------------------------- 1 | transfer("sip:pengxli@172.16.72.131:5678", $params); 11 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678"}}]}'); 12 | } 13 | 14 | public function testTransferWithMinOptions1() { 15 | $tropo = new Tropo(); 16 | $tropo->transfer(array("sip:pengxli@172.16.72.131:5678", "sip:pengxli@192.168.26.1:5678"), $params); 17 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":["sip:pengxli@172.16.72.131:5678","sip:pengxli@192.168.26.1:5678"]}}]}'); 18 | } 19 | 20 | public function testTransferWithChoicesOptions() { 21 | $tropo = new Tropo(); 22 | $choices = new Choices(null, null, "#"); 23 | $params = array( 24 | 'choices' => $choices, 25 | ); 26 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 27 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","choices":{"terminator":"#"}}}]}'); 28 | } 29 | 30 | public function testTransferWithChoicesOptions1() { 31 | $tropo = new Tropo(); 32 | $params = array( 33 | 'choices' => '#', 34 | ); 35 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 36 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","choices":{"terminator":"#"}}}]}'); 37 | } 38 | 39 | public function testTransferWithChoicesAndTerminatorOptions() { 40 | $tropo = new Tropo(); 41 | $choices = new Choices(null, null, "#"); 42 | $params = array( 43 | 'choices' => $choices, 44 | 'terminator' => '*', 45 | ); 46 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 47 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","choices":{"terminator":"*"}}}]}'); 48 | } 49 | 50 | public function testTransferWithChoicesAndTerminatorOptions1() { 51 | $tropo = new Tropo(); 52 | $params = array( 53 | 'choices' => '#', 54 | 'terminator' => '*', 55 | ); 56 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 57 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","choices":{"terminator":"*"}}}]}'); 58 | } 59 | 60 | public function testTransferWithOnOptions() { 61 | $tropo = new Tropo(); 62 | $on = new On("ring", null, new Say("http://www.phono.com/audio/holdmusic.mp3")); 63 | $params = array( 64 | 'ringRepeat' => 2, 65 | 'on' => $on, 66 | ); 67 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 68 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","ringRepeat":2,"on":{"event":"ring","say":{"value":"http://www.phono.com/audio/holdmusic.mp3"}}}}]}'); 69 | } 70 | 71 | public function testTransferWithAllOptions() { 72 | $tropo = new Tropo(); 73 | $allowSignals = array("exit", "quit"); 74 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 75 | $onRing = new On("ring", null, new Say("http://www.phono.com/audio/holdmusic.mp3")); 76 | $say = array( 77 | new Say("Sorry. Please enter you 5 digit account number again.", null, "nomatch"), 78 | new Say("Sorry, I did not hear anything.", null , "timeout"), 79 | new Say("Please enter 5 digit account number.") 80 | ); 81 | $ask = new Ask(3, true, new Choices("[5 DIGITS]", "dtmf", null), null, "ask", true, $say); 82 | $onConnect = new On("connect", null, null, null, $ask); 83 | $on = array($onRing, $onConnect); 84 | $params = array( 85 | 'from' => '14155551212', 86 | 'timeout' => 30.0, 87 | 'answerOnMedia' => false, 88 | 'required' => true, 89 | 'allowSignals' => $allowSignals, 90 | 'machineDetection' => false, 91 | 'terminator' => '#', 92 | 'headers' => $headers, 93 | 'interdigitTimeout' => 5.0, 94 | 'ringRepeat' => 2, 95 | 'playTones' => true, 96 | 'on' => $on, 97 | 'voice' => Voice::$US_English_female_allison, 98 | 'callbackUrl' => 'http://192.168.26.203/result.php', 99 | 'promptLogSecurity' => 'suppress', 100 | 'label' => 'transferLabel' 101 | ); 102 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 103 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","answerOnMedia":false,"choices":{"terminator":"#"},"from":"14155551212","ringRepeat":2,"timeout":30,"on":[{"event":"ring","say":{"value":"http://www.phono.com/audio/holdmusic.mp3"}},{"event":"connect","ask":{"attempts":3,"bargein":true,"choices":{"value":"[5 DIGITS]","mode":"dtmf"},"name":"ask","required":true,"say":[{"event":"nomatch","value":"Sorry. Please enter you 5 digit account number again."},{"event":"timeout","value":"Sorry, I did not hear anything."},{"value":"Please enter 5 digit account number."}]}}],"allowSignals":["exit","quit"],"headers":{"foo":"bar","bling":"baz"},"machineDetection":false,"voice":"allison","required":true,"interdigitTimeout":5,"playTones":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"transferLabel"}}]}'); 104 | } 105 | 106 | public function testTransferWithAllOptions1() { 107 | $tropo = new Tropo(); 108 | $allowSignals = array("exit", "quit"); 109 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 110 | $onRing = new On("ring", null, new Say("http://www.phono.com/audio/holdmusic.mp3")); 111 | $say = array( 112 | new Say("Sorry. Please enter you 5 digit account number again.", null, "nomatch"), 113 | new Say("Sorry, I did not hear anything.", null , "timeout"), 114 | new Say("Please enter 5 digit account number.") 115 | ); 116 | $ask = new Ask(3, true, new Choices("[5 DIGITS]", "dtmf", null), null, "ask", true, $say); 117 | $onConnect = new On("connect", null, null, null, $ask); 118 | $on = array($onRing, $onConnect); 119 | $params = array( 120 | 'from' => '14155551212', 121 | 'timeout' => 30.0, 122 | 'answerOnMedia' => false, 123 | 'required' => true, 124 | 'allowSignals' => $allowSignals, 125 | 'machineDetection' => 'For the most accurate results, the "introduction" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.', 126 | 'terminator' => '#', 127 | 'headers' => $headers, 128 | 'interdigitTimeout' => 5.0, 129 | 'ringRepeat' => 2, 130 | 'playTones' => true, 131 | 'on' => $on, 132 | 'voice' => Voice::$US_English_female_allison, 133 | 'callbackUrl' => 'http://192.168.26.203/result.php', 134 | 'promptLogSecurity' => 'suppress', 135 | 'label' => 'transferLabel' 136 | ); 137 | $tropo->transfer("sip:pengxli@172.16.72.131:5678", $params); 138 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","answerOnMedia":false,"choices":{"terminator":"#"},"from":"14155551212","ringRepeat":2,"timeout":30,"on":[{"event":"ring","say":{"value":"http://www.phono.com/audio/holdmusic.mp3"}},{"event":"connect","ask":{"attempts":3,"bargein":true,"choices":{"value":"[5 DIGITS]","mode":"dtmf"},"name":"ask","required":true,"say":[{"event":"nomatch","value":"Sorry. Please enter you 5 digit account number again."},{"event":"timeout","value":"Sorry, I did not hear anything."},{"value":"Please enter 5 digit account number."}]}}],"allowSignals":["exit","quit"],"headers":{"foo":"bar","bling":"baz"},"machineDetection":{"introduction":"For the most accurate results, the \"introduction\" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.","voice":"allison"},"voice":"allison","required":true,"interdigitTimeout":5,"playTones":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"transferLabel"}}]}'); 139 | } 140 | 141 | 142 | public function testCreateMinObject() { 143 | $tropo = new Tropo(); 144 | $transfer = new Transfer("sip:pengxli@172.16.72.131:5678"); 145 | $tropo->transfer($transfer); 146 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678"}}]}'); 147 | } 148 | 149 | public function testCreateObject() { 150 | $tropo = new Tropo(); 151 | $transfer = new Transfer(array("sip:pengxli@172.16.72.131:5678", "sip:pengxli@192.168.26.1:5678")); 152 | $tropo->transfer($transfer); 153 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":["sip:pengxli@172.16.72.131:5678","sip:pengxli@192.168.26.1:5678"]}}]}'); 154 | } 155 | 156 | public function testCreateObject1() { 157 | $tropo = new Tropo(); 158 | $choices = new Choices(null, null, "#"); 159 | $transfer = new Transfer(array("sip:pengxli@172.16.72.131:5678", "sip:pengxli@192.168.26.1:5678"), null, $choices); 160 | $tropo->transfer($transfer); 161 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":["sip:pengxli@172.16.72.131:5678","sip:pengxli@192.168.26.1:5678"],"choices":{"terminator":"#"}}}]}'); 162 | } 163 | 164 | public function testCreateObject2() { 165 | $tropo = new Tropo(); 166 | $on = new On("ring", null, new Say("http://www.phono.com/audio/holdmusic.mp3")); 167 | $transfer = new Transfer("sip:pengxli@172.16.72.131:5678", null, null, null, 2, null, $on); 168 | $tropo->transfer($transfer); 169 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","ringRepeat":2,"on":{"event":"ring","say":{"value":"http://www.phono.com/audio/holdmusic.mp3"}}}}]}'); 170 | } 171 | 172 | public function testCreateObject3() { 173 | $tropo = new Tropo(); 174 | $choices = new Choices(null, null, "#"); 175 | $allowSignals = array("exit", "quit"); 176 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 177 | $onRing = new On("ring", null, new Say("http://www.phono.com/audio/holdmusic.mp3")); 178 | $say = array( 179 | new Say("Sorry. Please enter you 5 digit account number again.", null, "nomatch"), 180 | new Say("Sorry, I did not hear anything.", null , "timeout"), 181 | new Say("Please enter 5 digit account number.") 182 | ); 183 | $ask = new Ask(3, true, new Choices("[5 DIGITS]", "dtmf", null), null, "ask", true, $say); 184 | $onConnect = new On("connect", null, null, null, $ask); 185 | $on = array($onRing, $onConnect); 186 | $transfer = new Transfer("sip:pengxli@172.16.72.131:5678", false, $choices, "14155551212", 2, 30.0, $on, $allowSignals, $headers, false, Voice::$US_English_female_allison, null, true, 5.0, true, "http://192.168.26.203/result.php", "suppress", "transferLabel"); 187 | $tropo->transfer($transfer); 188 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","answerOnMedia":false,"choices":{"terminator":"#"},"from":"14155551212","ringRepeat":2,"timeout":30,"on":[{"event":"ring","say":{"value":"http://www.phono.com/audio/holdmusic.mp3"}},{"event":"connect","ask":{"attempts":3,"bargein":true,"choices":{"value":"[5 DIGITS]","mode":"dtmf"},"name":"ask","required":true,"say":[{"event":"nomatch","value":"Sorry. Please enter you 5 digit account number again."},{"event":"timeout","value":"Sorry, I did not hear anything."},{"value":"Please enter 5 digit account number."}]}}],"allowSignals":["exit","quit"],"headers":{"foo":"bar","bling":"baz"},"machineDetection":false,"voice":"allison","required":true,"interdigitTimeout":5,"playTones":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"transferLabel"}}]}'); 189 | } 190 | 191 | public function testCreateObject4() { 192 | $tropo = new Tropo(); 193 | $choices = new Choices(null, null, "#"); 194 | $allowSignals = array("exit", "quit"); 195 | $headers = array('foo' => 'bar', 'bling' => 'baz'); 196 | $machineDetection = 'For the most accurate results, the "introduction" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.'; 197 | $onRing = new On("ring", null, new Say("http://www.phono.com/audio/holdmusic.mp3")); 198 | $say = array( 199 | new Say("Sorry. Please enter you 5 digit account number again.", null, "nomatch"), 200 | new Say("Sorry, I did not hear anything.", null , "timeout"), 201 | new Say("Please enter 5 digit account number.") 202 | ); 203 | $ask = new Ask(3, true, new Choices("[5 DIGITS]", "dtmf", null), null, "ask", true, $say); 204 | $onConnect = new On("connect", null, null, null, $ask); 205 | $on = array($onRing, $onConnect); 206 | $transfer = new Transfer("sip:pengxli@172.16.72.131:5678", false, $choices, "14155551212", 2, 30.0, $on, $allowSignals, $headers, $machineDetection, Voice::$US_English_female_allison, null, true, 5.0, true, "http://192.168.26.203/result.php", "suppress", "transferLabel"); 207 | $tropo->transfer($transfer); 208 | $this->assertEquals(sprintf($tropo), '{"tropo":[{"transfer":{"to":"sip:pengxli@172.16.72.131:5678","answerOnMedia":false,"choices":{"terminator":"#"},"from":"14155551212","ringRepeat":2,"timeout":30,"on":[{"event":"ring","say":{"value":"http://www.phono.com/audio/holdmusic.mp3"}},{"event":"connect","ask":{"attempts":3,"bargein":true,"choices":{"value":"[5 DIGITS]","mode":"dtmf"},"name":"ask","required":true,"say":[{"event":"nomatch","value":"Sorry. Please enter you 5 digit account number again."},{"event":"timeout","value":"Sorry, I did not hear anything."},{"value":"Please enter 5 digit account number."}]}}],"allowSignals":["exit","quit"],"headers":{"foo":"bar","bling":"baz"},"machineDetection":{"introduction":"For the most accurate results, the \"introduction\" should be long enough to give Tropo time to detect a human or machine. The longer the introduction, the more time we have to determine how the call was answered.","voice":"allison"},"voice":"allison","required":true,"interdigitTimeout":5,"playTones":true,"callbackUrl":"http://192.168.26.203/result.php","promptLogSecurity":"suppress","label":"transferLabel"}}]}'); 209 | } 210 | 211 | } 212 | ?> --------------------------------------------------------------------------------