Skip to content

Instantly share code, notes, and snippets.

@loren138
Created May 3, 2016 17:03
Show Gist options
  • Save loren138/d6dccf91950957049c229fa59e1d32b0 to your computer and use it in GitHub Desktop.
Save loren138/d6dccf91950957049c229fa59e1d32b0 to your computer and use it in GitHub Desktop.
Validate Twilio TwilML SMS Request with Laravel (also a Twilio Controller for Laravel)
<?php
// Place in app/config/api.php
// You'll need to get your TWILIO authToken from https://www.twilio.com/user/account/monitor/getting-started
// and place it in your .env file (or directly in this file, but that's less secure)
return [
'twilio' => [
'authToken' => env('TWILIO_AUTHTOKEN')
]
];
<?php
/**
* Twilio Request Validator Class
* This file goes in app/Models/Twilio (or you can move it around and change the namespace)
* It requires that you have a file config/api.php
* Source: https://raw.githubusercontent.com/twilio/twilio-php/3d02ee1f1bde8e860e7dbfd9d2d0d2b7ca7d625c/Services/Twilio/RequestValidator.php
*/
namespace App\Models\Twilio;
class RequestValidator
{
// You might want to grab the current source for this class from
// https://raw.githubusercontent.com/twilio/twilio-php/master/Services/Twilio/RequestValidator.php
protected $AuthToken;
public function __construct($token)
{
$this->AuthToken = $token;
}
public function computeSignature($url, $data = array())
{
// sort the array by keys
ksort($data);
// append them to the data string in order
// with no delimiters
foreach ($data as $key => $value) {
$url .= "$key$value";
}
// This function calculates the HMAC hash of the data with the key
// passed in
// Note: hash_hmac requires PHP 5 >= 5.1.2 or PECL hash:1.1-1.5
// Or http://pear.php.net/package/Crypt_HMAC/
return base64_encode(hash_hmac("sha1", $url, $this->AuthToken, true));
}
public function validate($expectedSignature, $url, $data = array())
{
return self::compare(
$this->computeSignature($url, $data),
$expectedSignature
);
}
/**
* Time insensitive compare, function's runtime is governed by the length
* of the first argument, not the difference between the arguments.
* @param $a string First part of the comparison pair
* @param $b string Second part of the comparison pair
* @return bool True if $a == $b, false otherwise.
*/
public static function compare($a, $b)
{
$result = true;
if (strlen($a) != strlen($b)) {
return false;
}
if (!$a && !$b) {
return true;
}
$limit = strlen($a);
for ($i = 0; $i < $limit; ++$i) {
if ($a[$i] != $b[$i]) {
$result = false;
}
}
return $result;
}
}
<?php
namespace App\Http\Controllers\Shared;
use App\Models\Twilio\RequestValidator;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class TwilioController extends Controller
{
public function postText(Request $request, JenzabarName $jenzabarName)
{
$validator = new RequestValidator(config('api.twilio.authToken'));
if (!$validator->validate(
$request->header('X-Twilio-Signature'),
$request->getUri(),
$request->request->all()
)) {
return $this->textError(
'your request is invalid!'
);
}
$phone = $request->input('From');
// Do something with the phone number?
$action = explode(' ', strtolower($request->input('Body')));
$function = "action" . ucfirst($action[0]);
if (method_exists($this, $function)) {
return $this->$function($action, $id[0]['ID_NUM']);
} else {
return $this->textError('we could not understand your request.');
}
}
public function actionReply($text, $id)
{
$this->text('Hello.');
}
public function textError($error)
{
return $this->text('We were unable to process your request because '.$error);
}
public function text($text)
{
$xml = '<?xml version="1.0" encoding="UTF-8"?>'."\n".
'<Response><Sms>'.$text.'</Sms></Response>';
return response($xml, 200, ['Content-type' => 'text/xml']);
}
public function postVoice()
{
$xml = '<?xml version="1.0" encoding="UTF-8"?>'."\n".
'<Response><Say voice="man" language="en">Thanks for calling.</Say></Response>';
return response($xml, 200, ['Content-type' => 'text/xml']);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment