Upload
david-stockton
View
112
Download
0
Embed Size (px)
Citation preview
Phone Calls and SMS from PHP
PHP World 2016 David Stockton
November 16, 2016
Standard Interactions
Input
Web Pages / Forms
APIs
CLI
Output
HTML
Graphics
Documents
Reports
JSON
Console Output
Files
How else can we receive input and produce
output?
Input: Phone Call
Input: SMS Message
Output: Text Message
Output: MMS Message
Output: Phone Call
APIs for Phone Interaction
Twilio SDK
composer require twilio/sdk
Let's Send an SMS
new \Twilio\Rest\Client($config['sid'], $config['token']);
Make a client
Let's Send an SMS
$client->messages->create( $toNumber, array( 'from' => '+1<purchased#>', 'body' => $fortune ));
All Together$toNumber = $argv[1] ?? '<default #>';$toNumber = \PhpWorld\Utility::normalizeNumber($toNumber);$fortune = $argv[2] ?? `fortune`;$client->messages->create( $toNumber, array( 'from' => '+<purchased #>', 'body' => $fortune ));
How to Use?
$ php bin/fortune.php
$ php bin/fortune.php <destination #>
$ php bin/fortune.php <destination #> "Text message from the command line"
php bin/fortune.php
php bin/fortune.php 7206757471
php bin/fortune.php 7206757471 "Your account has been created or something."
What can we do?
• Notifications
• Two-Factor Authentication (2FA)
• Responses to Queries
Make a Phone Call
• API Call to Twitter
• Twitter contacts URL for instructions
TwiML
• Twilio's Markup Language for controlling phone calls
• XML
TwiML Commands• Say - Read text to the caller
• Play - Play an audio file for the caller
• Dial - Add another party to the call
• Record - Record the caller's voice
• Gather - Collect digits the caller types on their keypad
• Sms - Send an SMS message during a phone call
More TwiML• Hangup - Hang up the call
• Queue - Add the caller to a queue of callers.
• Redirect - Redirect call flow to a different TwiML document.
• Pause - Wait before executing more instructions
• Reject - Decline an incoming call without being billed.
• Message - Send an MMS or SMS message reply
How Outgoing Calls Work
Your App TwilioAPI Call
TwiMLCalleeTwilio Plays Twiml
TwiML
<?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="woman">Your call is very important to us, but not so important we'll answer it with a human. Please leave a message. </Say> <Record maxLength="20" playBeep="true"/></Response>
XML
<?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="woman">Your call is very important to us, but not so important we'll answer it with a human. Please leave a message. </Say> <Record maxLength="20" playBeep="true"/></Response>
Root Element
<?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="woman">Your call is very important to us, but not so important we'll answer it with a human. Please leave a message. </Say> <Record maxLength="20" playBeep="true"/></Response>
Commands - Say
<?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="woman">Your call is very important to us, but not so important we'll answer it with a human. Please leave a message. </Say> <Record maxLength="20" playBeep="true"/></Response>
<?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="woman">Your call is very important to us, but not so important we'll answer it with a human. Please leave a message. </Say> <Record maxLength="20" playBeep="true"/></Response>
Commands - Record
Configure Twilio
Let's Make a Call
<?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="man"> Due to inclement weather, school will be closed tomorrow. Please stay home and stay safe. </Say></Response>
The Full File
<?php header('Content-Type: text/xml'); ?><?xml version="1.0" encoding="UTF-8"?><Response> <Say voice="man" loop="2"> Due to inclement weather, school will be closed tomorrow. Please stay home and stay safe. </Say></Response>
Tell Twilio Who To Call<?phprequire_once __DIR__ . '/../vendor/autoload.php';/** @var \Twilio\Rest\Client $client */$client = require_once __DIR__ . '/../src/PhpWorld/client.php';$to = \PhpWorld\Utility::normalizeNumber($argv[1] ?? '+<default #>');$from = '+<purchased #>';$options = [ 'url' => 'http://' . $_SERVER['HTTP_HOST'] . '/twiml/school_outage.php',];$client->calls->create($to, $from, $options);
Tell Twilio Who To Call<?phprequire_once __DIR__ . '/../vendor/autoload.php';/** @var \Twilio\Rest\Client $client */$client = require_once __DIR__ . '/../src/PhpWorld/client.php';$to = \PhpWorld\Utility::normalizeNumber($argv[1] ?? '+<default #>');$from = '+<purchased #>';$options = [ 'url' => 'http://' . $_SERVER['HTTP_HOST'] . '/twiml/school_outage.php',];$client->calls->create($to, $from, $options);
Tell Twilio Who To Call<?phprequire_once __DIR__ . '/../vendor/autoload.php';/** @var \Twilio\Rest\Client $client */$client = require_once __DIR__ . '/../src/PhpWorld/client.php';$to = \PhpWorld\Utility::normalizeNumber($argv[1] ?? '+<default #>');$from = '+<purchased #>';$options = [ 'url' => 'http://' . $_SERVER['HTTP_HOST'] . '/twiml/school_outage.php',];$client->calls->create($to, $from, $options);
Tell Twilio Who To Call<?phprequire_once __DIR__ . '/../vendor/autoload.php';/** @var \Twilio\Rest\Client $client */$client = require_once __DIR__ . '/../src/PhpWorld/client.php';$to = \PhpWorld\Utility::normalizeNumber($argv[1] ?? '+<default #>');$from = '+<purchased #>';$options = [ 'url' => 'http://' . $_SERVER['HTTP_HOST'] . '/twiml/school_outage.php',];$client->calls->create($to, $from, $options);
Tell Twilio Who To Call<?phprequire_once __DIR__ . '/../vendor/autoload.php';/** @var \Twilio\Rest\Client $client */$client = require_once __DIR__ . '/../src/PhpWorld/client.php';$to = \PhpWorld\Utility::normalizeNumber($argv[1] ?? '+<default #>');$from = '+<purchased #>';$options = [ 'url' => 'http://' . $_SERVER['HTTP_HOST'] . '/twiml/school_outage.php',];$client->calls->create($to, $from, $options);
Tell Twilio Who To Call<?phprequire_once __DIR__ . '/../vendor/autoload.php';/** @var \Twilio\Rest\Client $client */$client = require_once __DIR__ . '/../src/PhpWorld/client.php';$to = \PhpWorld\Utility::normalizeNumber($argv[1] ?? '+<default #>');$from = '+<purchased #>';$options = [ 'url' => 'http://' . $_SERVER['HTTP_HOST'] . '/twiml/school_outage.php',];$client->calls->create($to, $from, $options);
Phone and SMS Conversations
• Twilio is like a well-behaved HTTP client
• It uses sessions
• We can use session to remember things about the caller or the conversation
Phone IVR
• Give callers a menu
• Look up information
• Connect to people
• Solve problems
• Give answers
First TwiML<?php header('Content-Type: text/xml'); ?> <?xml version="1.0" encoding="UTF-8"?> <Response> <Say> Thanks for calling my demo IVR. Please listen closely as this is the first time you've heard this menu. </Say> <Gather numDigits="1" action="/twiml/process_ivr_menu.php"> <Say> Press 1 to hear a random sound. Press 2 to connect to a conference call. Press 3 to hear some wisdom. Press 4 to be connected to support. </Say> </Gather> <Say> I don't understand. Please try again later. </Say> <Hangup/></Response>
<?php header('Content-Type: text/xml'); ?> <?xml version="1.0" encoding="UTF-8"?> <Response> <Say> Thanks for calling my demo IVR. Please listen closely as this is the first time you've heard this menu. </Say> <Gather numDigits="1" action="/twiml/process_ivr_menu.php"> <Say> Press 1 to hear a random sound. Press 2 to connect to a conference call. Press 3 to hear some wisdom. Press 4 to be connected to support. </Say> </Gather> <Say> I don't understand. Please try again later. </Say> <Hangup/></Response>
Greeting
<?php header('Content-Type: text/xml'); ?> <?xml version="1.0" encoding="UTF-8"?> <Response> <Say> Thanks for calling my demo IVR. Please listen closely as this is the first time you've heard this menu. </Say> <Gather numDigits="1" action="/twiml/process_ivr_menu.php"> <Say> Press 1 to hear a random sound. Press 2 to connect to a conference call. Press 3 to hear some wisdom. Press 4 to be connected to support. </Say> </Gather> <Say> I don't understand. Please try again later. </Say> <Hangup/></Response>
Menu
Error Handling<?php header('Content-Type: text/xml'); ?> <?xml version="1.0" encoding="UTF-8"?> <Response> <Say> Thanks for calling my demo IVR. Please listen closely as this is the first time you've heard this menu. </Say> <Gather numDigits="1" action="/twiml/process_ivr_menu.php"> <Say> Press 1 to hear a random sound. Press 2 to connect to a conference call. Press 3 to hear some wisdom. Press 4 to be connected to support. </Say> </Gather> <Say> I don't understand. Please try again later. </Say> <Hangup/></Response>
Goodbye.<?php header('Content-Type: text/xml'); ?> <?xml version="1.0" encoding="UTF-8"?> <Response> <Say> Thanks for calling my demo IVR. Please listen closely as this is the first time you've heard this menu. </Say> <Gather numDigits="1" action="/twiml/process_ivr_menu.php"> <Say> Press 1 to hear a random sound. Press 2 to connect to a conference call. Press 3 to hear some wisdom. Press 4 to be connected to support. </Say> </Gather> <Say> I don't understand. Please try again later. </Say> <Hangup/></Response>
Now What?
• What if they press something that's not 1-4?
• What if they press 1-4?
• Need to figure out what to do next
Handle ! 1-4<?phprequire_once __DIR__ . '/../vendor/autoload.php';session_start();$digits = $_POST['Digits'] ?? 0; switch ($digits) { case 1: // Random sound case 2: // Conference call case 3: // Random Phrase case 4: // Support queue default: if (countFailures() >= 3) { echo bailOnCall(); return; } echo badInput(); return;}
countFailures()
function countFailures($count = null){ $badInput = $count ?? $_SESSION[__FUNCTION__] ?? 0; $badInput++; $_SESSION[__FUNCTION__] = $badInput; return $badInput;}
badInput()
function badInput(){ header('Content-type: text/xml'); $twiml = new \Twilio\Twiml(); $twiml->say('That was not a valid selection.'); $twiml->redirect('/twiml/ivr_menu.php'); return $twiml;}
bailOnCall()function bailOnCall(){ header('Content-type: text/xml'); $twiml = new \Twilio\Twiml(); $twiml->say('Your rotary phone is not compatible with this app.'); $twiml->say('Goodbye.'); $twiml->hangup(); return $twiml;}
Call Handlerswitch ($digits) { case 1: // Random sound echo randomSound(); break; case 2: // Conference call echo conferenceCall(); break; case 3: // Random Phrase echo fortune(); break; case 4: // Support queue echo supportQueue(); break; default: ... }
randomSound()function randomSound(){ header('Content-type: text/xml'); countFailures(-1); $sounds = ['gull.mp3', 'lawnmower.mp3', 'monkey.mp3']; $index = array_rand($sounds); $twiml = new \Twilio\Twiml(); $twiml->play('/sounds/' . $sounds[$index]); $twiml->redirect('/twiml/ivr_menu.php'); return $twiml;}
Conference Call
function conferenceCall(){ header('Content-type: text/xml'); $response = new \Twilio\Twiml(); $response->say('You have joined the conference.'); $dial = $response->dial(); $dial->conference('PHP World'); return $response;}
fortune()
function fortune(){ $fortune = `fortune -s`; header('Content-type: text/xml'); $response = new \Twilio\Twiml(); $response->sms($fortune); $response->say($fortune); return $response;}
supportQueue()function supportQueue() { header('Content-type: text/xml'); $response = new \Twilio\Twiml(); if ($_POST['From'] == '<my number>') { // Support agent $dial = $response->dial(); $dial->queue('support', ['url' => '/twiml/about_to_connect.php']); } else { // Enqueue $response->enqueue('support'); } return $response;}
supportQueue()function supportQueue() { header('Content-type: text/xml'); $response = new \Twilio\Twiml(); if ($_POST['From'] == '<my number>') { // Support agent $dial = $response->dial(); $dial->queue('support', ['url' => '/twiml/about_to_connect.php']); } else { // Enqueue $response->enqueue('support'); } return $response;}
Just Scratching the Surface
• Twilio can keep our application informed about how calls are going
• We can interact with ongoing calls via the REST API
Questions?
• Twitter: @dstockto
• Joind.in - https://joind.in/talk/e2e2b
20162016