You are here

sms_twilio.module in Twilio SMS Integration 6

Same filename and directory in other branches
  1. 7.2 sms_twilio.module
  2. 7 sms_twilio.module

Adds support for sending SMS messages using the Twilio gateway.

File

sms_twilio.module
View source
<?php

/**
 * @file
 * Adds support for sending SMS messages using the Twilio gateway.
 */

/**
 * Implementation of hook_gateway_info().
 */
function sms_twilio_gateway_info() {
  return array(
    'twilio' => array(
      'name' => 'Twilio',
      'configure form' => 'sms_twilio_admin_form',
      'receive' => TRUE,
      'send' => 'sms_twilio_send',
      'send form' => 'sms_twilio_send_form',
    ),
  );
}

/**
 * Admin/settings form.
 */
function sms_twilio_admin_form($configuration) {
  $form['sms_twilio_api_sid'] = array(
    '#type' => 'textfield',
    '#title' => t('Account SID'),
    '#description' => t('Twilio Account SID - the 34 character string beginning with AC'),
    '#size' => 40,
    '#maxlength' => 255,
    '#default_value' => $configuration['sms_twilio_api_sid'],
  );
  $form['sms_twilio_api_auth_token'] = array(
    '#type' => 'textfield',
    '#title' => t('API ID'),
    '#description' => t('Twilio auth token - <a href="https://www.twilio.com/user/account">available on your dashboard</a>'),
    '#size' => 40,
    '#maxlength' => 255,
    '#default_value' => $configuration['sms_twilio_api_auth_token'],
  );
  $form['sms_twilio_number'] = array(
    '#type' => 'textfield',
    '#title' => t('Number'),
    '#description' => t('A <a href="https://www.twilio.com/user/account/phone-numbers" target="_new">phone number</a> from your Twilio account'),
    '#size' => 40,
    '#maxlength' => 255,
    '#default_value' => $configuration['sms_twilio_number'],
  );
  $form['sms_twilio_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Twilio library path'),
    '#description' => t('The path to the twilio library'),
    '#size' => 40,
    '#maxlength' => 255,
    '#default_value' => !empty($configuration['sms_twilio_path']) ? $configuration['sms_twilio_path'] : 'sites/all/libraries/twilio',
  );
  return $form;
}

/**
 * Validates the submission of the configuration form.
 */
function sms_twilio_admin_form_validate($form, &$form_state) {
}

/**
 * Returns custom additions to be added to the send forms
 */
function sms_twilio_send_form() {
  $form['country'] = array(
    '#type' => 'select',
    '#title' => t('Country'),
    '#multiple' => FALSE,
    '#options' => sms_twilio_country_codes(),
    '#default_value' => -1,
  );
  return $form;
}

/**
 * Callback for sending messages.
 */
function sms_twilio_send($number, $message, $options) {
  $number = preg_replace("/[^0-9]/", '', $number);
  $number = trim($number);
  $number = ltrim($number, '0');

  // Remove leading zeros
  $index = strpos($number, $options['country']);
  if ($index === FALSE || $index > 0) {
    $number = $options['country'] . $number;
  }
  return sms_twilio_command('sendmsg', array(
    'number' => $number,
    'message' => $message,
  ), NULL, $account);
}

/**
 * Executes a command using the Twilio API
 */
function sms_twilio_command($command = 'auth', $data = array(), $config = NULL, $account = '') {
  if (!isset($config)) {
    $gateway = sms_gateways('gateway', 'twilio');
    $config = $gateway['configuration'];
  }

  // Include the PHP TwilioRest library
  require_once $config['sms_twilio_path'] . '/twilio.php';

  // Twilio REST API version
  $ApiVersion = "2008-08-01";

  // Set our AccountSid and AuthToken
  $AccountSid = $config['sms_twilio_api_sid'];
  $AuthToken = $config['sms_twilio_api_auth_token'];

  // Instantiate a new Twilio Rest Client
  $client = new TwilioRestClient($AccountSid, $AuthToken);
  switch ($command) {
    case 'sendmsg':

      // Check if the message requires unicode handling
      $response = $client
        ->request("/{$ApiVersion}/Accounts/{$AccountSid}/SMS/Messages", "POST", array(
        "To" => $data['number'],
        "From" => $config['sms_twilio_number'],
        "Body" => $data['message'],
      ));
      break;
  }
  watchdog('sms_twilio', print_r($response, TRUE));

  // Check for HTTP errors
  if ($response->IsError) {
    $result = array(
      'status' => FALSE,
      'message' => t('An error occured during the HTTP request: @error', array(
        '@error' => $response->ErrorMessage,
      )),
    );
  }
  else {
    $result = array(
      'status' => TRUE,
      'data' => t('Message sent to @number', array(
        '@number' => $data['number'],
      )),
    );
  }
  return $result;
}

/**
 * @todo: this should be in the sms framework rather then each gateway needing
 * to re-define this list.
 */
function sms_twilio_country_codes() {
  return array(
    93 => "Afghanistan",
    355 => "Albania",
    213 => "Algeria",
    376 => "Andorra",
    244 => "Angola",
    1264 => "Anguilla",
    1268 => "Antigua & Barbuda",
    54 => "Argentina",
    374 => "Armenia",
    297 => "Aruba",
    61 => "Australia",
    43 => "Austria",
    994 => "Azerbaijan",
    1242 => "Bahamas",
    973 => "Bahrain",
    880 => "Bangladesh",
    1246 => "Barbados",
    375 => "Belarus",
    32 => "Belgium",
    501 => "Belize",
    229 => "Benin",
    1441 => "Bermuda",
    975 => "Bhutan",
    591 => "Bolivia",
    387 => "Bosnia-Herzegovina",
    267 => "Botswana",
    55 => "Brazil",
    1284 => "British Virgin Islands",
    673 => "Brunei",
    359 => "Bulgaria",
    226 => "Burkina Faso",
    257 => "Burundi",
    855 => "Cambodia",
    237 => "Cameroon",
    34 => "Canary Islands",
    238 => "Cape Verde",
    1345 => "Cayman Islands",
    236 => "Central African Republic",
    235 => "Chad",
    56 => "Chile",
    86 => "China",
    57 => "Colombia",
    269 => "Comoros",
    242 => "Congo",
    243 => "Democratic Republic Congo",
    682 => "Cook Islands",
    385 => "Croatia",
    53 => "Cuba",
    357 => "Cyprus",
    420 => "Czech Republic",
    45 => "Denmark",
    253 => "Djibouti",
    1767 => "Dominica",
    670 => "East Timor",
    593 => "Ecuador",
    20 => "Egypt",
    503 => "El Salvador",
    240 => "Equatorial Guinea",
    372 => "Estonia",
    251 => "Ethiopia",
    500 => "Falkland Islands",
    298 => "Faroe Islands",
    679 => "Fiji",
    358 => "Finland",
    33 => "France",
    594 => "French Guiana",
    689 => "French Polynesia",
    241 => "Gabon",
    220 => "Gambia",
    995 => "Georgia",
    49 => "Germany",
    233 => "Ghana",
    350 => "Gibraltar",
    881 => "Global Mobile Satellite",
    30 => "Greece",
    299 => "Greenland",
    1473 => "Grenada",
    590 => "Guadeloupe",
    1671 => "Guam",
    502 => "Guatemala",
    224 => "Guinea",
    592 => "Guyana",
    509 => "Haiti",
    504 => "Honduras",
    852 => "HongKong",
    36 => "Hungary",
    354 => "Iceland",
    91 => "India",
    62 => "Indonesia",
    98 => "Iran",
    964 => "Iraq",
    353 => "Ireland",
    972 => "Israel",
    39 => "Italy / Vatican City State",
    225 => "Ivory Coast",
    1876 => "Jamaica",
    81 => "Japan",
    962 => "Jordan",
    254 => "Kenya",
    82 => "Korea (South)",
    965 => "Kuwait",
    996 => "Kyrgyzstan",
    856 => "Lao",
    371 => "Latvia",
    961 => "Lebanon",
    266 => "Lesotho",
    231 => "Liberia",
    218 => "Libya",
    423 => "Liechtenstein",
    370 => "Lithuania",
    352 => "Luxembourg",
    853 => "Macau",
    389 => "Macedonia",
    261 => "Madagascar",
    265 => "Malawi",
    60 => "Malaysia",
    960 => "Maldives",
    223 => "Mali",
    356 => "Malta",
    596 => "Martinique",
    222 => "Mauritania",
    230 => "Mauritius",
    269 => "Mayotte Island (Comoros)",
    52 => "Mexico",
    373 => "Moldova",
    377 => "Monaco (Kosovo)",
    976 => "Mongolia",
    382 => "Montenegro",
    1664 => "Montserrat",
    212 => "Morocco",
    258 => "Mozambique",
    95 => "Myanmar",
    264 => "Namibia",
    977 => "Nepal",
    31 => "Netherlands",
    599 => "Netherlands Antilles",
    687 => "New Caledonia",
    64 => "New Zealand",
    505 => "Nicaragua",
    227 => "Niger",
    234 => "Nigeria",
    47 => "Norway",
    968 => "Oman",
    92 => "Pakistan",
    970 => "Palestine (+970)",
    9725 => "Palestine (+9725)",
    507 => "Panama",
    675 => "Papua New Guinea",
    595 => "Paraguay",
    51 => "Peru",
    63 => "Philippines",
    48 => "Poland",
    351 => "Portugal",
    974 => "Qatar",
    262 => "Reunion",
    40 => "Romania",
    7 => "Russia / Kazakhstan",
    250 => "Rwanda",
    1670 => "Saipan",
    1684 => "Samoa (American)",
    685 => "Samoa (Western)",
    378 => "San Marino",
    882 => "Satellite-Thuraya",
    966 => "Saudi Arabia",
    221 => "Senegal",
    381 => "Serbia",
    248 => "Seychelles",
    232 => "Sierra Leone",
    65 => "Singapore",
    421 => "Slovakia",
    386 => "Slovenia",
    252 => "Somalia",
    27 => "South Africa",
    34 => "Spain",
    94 => "Sri Lanka",
    1869 => "St. Kitts And Nevis",
    1758 => "St. Lucia",
    1784 => "St. Vincent",
    249 => "Sudan",
    597 => "Suriname",
    268 => "Swaziland",
    46 => "Sweden",
    41 => "Switzerland",
    963 => "Syria",
    886 => "Taiwan",
    992 => "Tajikistan",
    255 => "Tanzania",
    66 => "Thailand",
    228 => "Togo",
    676 => "Tonga Islands",
    1868 => "Trinidad and Tobago",
    216 => "Tunisia",
    90 => "Turkey",
    993 => "Turkmenistan",
    1649 => "Turks and Caicos Islands",
    256 => "Uganda",
    44 => "UK / Isle of Man / Jersey / Guernsey",
    380 => "Ukraine",
    971 => "United Arab Emirates",
    598 => "Uruguay",
    1 => "USA / Canada / Dominican Rep. / Puerto Rico",
    998 => "Uzbekistan",
    678 => "Vanuatu",
    58 => "Venezuela",
    84 => "Vietnam",
    967 => "Yemen",
    260 => "Zambia",
    255 => "Zanzibar",
    263 => "Zimbabwe",
    '' => "-- No country --",
  );
}

/**
 * Implementation of hook_menu().
 *
 * Twilio will POST to this path when an SMS is received
 */
function sms_twilio_menu() {
  $items = array();
  $items['sms/twilio/incoming'] = array(
    'title' => 'Incoming Twilio SMS',
    'page callback' => 'sms_twilio_incoming',
    'access callback' => TRUE,
    'menu_name' => 'SMS',
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Informs the SMS Framework of the incoming SMS
 */
function sms_twilio_incoming() {
  global $base_url;
  if (isset($_REQUEST['From']) and isset($_REQUEST['To']) and isset($_REQUEST['FromCountry']) and isset($_REQUEST['FromCity']) and isset($_REQUEST['FromState']) and isset($_REQUEST['FromZip'])) {

    // Details on validating the Twilio signature: http://www.twilio.com/docs/security
    $gateway = sms_gateways('gateway', 'twilio');
    $config = $gateway['configuration'];
    $string_to_sign = $base_url . "/sms/twilio/incoming";
    ksort($_POST);
    foreach ($_POST as $key => $value) {
      $string_to_sign .= $key . $value;
    }
    $sig = base64_encode(hash_hmac("sha1", $string_to_sign, $config['sms_twilio_api_auth_token'], true));
    $from = $_REQUEST['From'];
    $body = $_REQUEST['Body'];
    if (strcmp($_SERVER["HTTP_X_TWILIO_SIGNATURE"], $sig) != 0) {
      watchdog('sms_twilio', 'Incoming sms from @from has a bad Twilio signature - dropping!', array(
        '@from' => $from,
      ), WATCHDOG_WARNING);
    }
    else {

      // watchdog('sms_twilio', 'Handling incoming sms from '.$from.': '.$body);
      $opts = array();
      $opts['to'] = $_REQUEST['To'];
      $opts['fromcountry'] = $_REQUEST['FromCountry'];
      $opts['fromcity'] = $_REQUEST['FromCity'];
      $opts['fromstate'] = $_REQUEST['FromState'];
      $opts['fromzip'] = $_REQUEST['FromZip'];
      sms_incoming($from, $body, $opts);
    }
  }
}

Functions

Namesort descending Description
sms_twilio_admin_form Admin/settings form.
sms_twilio_admin_form_validate Validates the submission of the configuration form.
sms_twilio_command Executes a command using the Twilio API
sms_twilio_country_codes @todo: this should be in the sms framework rather then each gateway needing to re-define this list.
sms_twilio_gateway_info Implementation of hook_gateway_info().
sms_twilio_incoming Informs the SMS Framework of the incoming SMS
sms_twilio_menu Implementation of hook_menu().
sms_twilio_send Callback for sending messages.
sms_twilio_send_form Returns custom additions to be added to the send forms