Categories


Archives


Recent Posts


Categories


Sending Text Messages with PHP, pestle, and Nexmo

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Today we’re going to go a little off the beaten path. I’ve had “professional reasons” to explore voice and SMS APIs in the past few weeks, and I ended up adding some commands for the Nexmo API to the latest release of pestle, (my kitchen sink PHP command line framework).

This article’s going to talk a little bit about the history of identity on the world wide web, demonstrate the new nexmo: commands in pestle, and then dive into some code with the Nexmo provided composer library that powers these new commands.

These commands are also a great example of the non-Magento priorities that drive pestle’s development — a lightweight system for quickly writing simple code.

Old Man Internet Corner

In the early days of the web and the internet that preceded it, an email address quickly became a proxy for identity. Even before the browser, global email was the internet’s killer app. While nothing’s ever 100%, it was a relatively safe bet if someone visited your website, they probably had an email address.

While email itself is still ubiquitous, as an identity proxy some of the shine has worn off. The ability for folks-with-ill-intent to quickly generate new email accounts, the spam problem, the deliverability problem, the by-design-lack-of-a-central-authority, etc. — all of these hamper the usefulness of using email to identify an individual person on the internet. For folks developing software on the internet an email address isn’t always the best, or only, choice.

What’s replacing it? While social media services like Twitter and Facebook dug up Microsoft Passport, dusted it off, and added their own ambitions to its lapels with social login, a far more compelling solution is the mobile phone number.

The Ubiquity of Phones

The introduction of the iPhone, and all the touch based smartphones its introduction begat, changed how people get on the internet. For many folks, their phones are the only way they get online. While internet clients are likely to remains a hodgepodge of desktop computers, laptop computers, tablets, and cell-network connected phones, its not always safe to assume a person browsing the web has (or uses) an ISP/Google/Microsoft/Apple/Yahoo provided email address. Even if you can assume the presence of an email address, mobile phones are quickly becoming the de-facto “two” in two factor authentication systems.

For software developers, this presents a challenge.

Email started as, and is still, an open protocol. Anyone can get on an internet connected server/computer (virtual or otherwise), send a specifically crafted network request to a server, and have that server accept the message as an email message. i.e. A PHP developer can still use the mail function and the server will send an email. Getting through the unsolicited-email protections enacted by each provider requires a bit of domain knowledge, but many of those measures are themselves based on open-standards. Even where email is veering towards less open approaches, those approaches are forced towards more open implementations because email is, at its heart, an open standard based on shared agreements around the SMTP, IMAP, and POP email standards.

The phone system, be it voice or SMS text, is not open. In the United States, the phone system started with the Bell System patent and trickled out to the world. Over the years various market forces and regulation have forced this closed system to open up in minor ways, but at its heart it remains a closed system. If you want to make a phone call, or send a text message using the phone system, you need to communicate with hardware and networks controlled by the phone company. This means doing business with the phone company. i.e. there is no sms(), phone_call(), or phone_tree() function in PHP.

Fortunately, as the mobile phone has risen in importance for software developers, a number of startups have also risen to the duel challenge of doing business with the phone companies, and providing straightforward, easy to use APIs. Behind the scenes these APIs tackle the complicated job of talking with the phone company’s systems, keeping text and voice routes up to date, and dealing with the arbitrary changes (both technical and business) that are inevitable with these closed systems.

Today we’re going to look at one of the best providers — Nexmo. Nexmo’s APIs are clean, PHP developer friendly, and their recent acquisition by Vonage gives them a solid foothold in the carrier world that many similar startups lack. If you’re looking for a more beautiful, crafted, or artisanal reason to chose Nexmo, they’re the default provider for sending Laravel Notifications.

The rest of this article will take a look at the Nexmo commands I’ve added to pestle, as well as the underlying PHP code for using the Nexmo API. If your application, content site, or ecommerce store needs voice and text capabilities, you’ll quickly see why Nexmo’s an obvious first choice.

Pestle Commands

There’s currently four Nexmo related commands in pestle.

nexmo:store-credentials                    Save out credentials for future
                                           requests

nexmo:send-text                            Sends a text message

nexmo:verify-request                       Sends initial request to verify
                                           user's phone number

nexmo:verify-sendcode                      Send verification code

These commands are the results of my initial experiments with the Nexmo API and Composer package. If you’re looking for a more fully featured command line application Nexmo has a complete javascript based CLI you may be interested in.

The nexmo:store-credentials command doesn’t call any Nexmo API methods — instead it stores (in a /tmp file) the Nexmo credentials you get after signing up for an account. You’ll want to use this method to store the key and secret available on your getting started page.

$ pestle.phar nexmo:store-credentials key secret

Once you’ve stored your Nexmo credentials, you can send a text message with the nexmo:send-text command. This command accepts three arguments — the number you want to send the SMS text to, the number the SMS text should come from (limited if you’re using a Nexmo trial account), and the actual contents of the text message.

$ pestle.phar nexmo:send-text 15555555555 12155167753 "Hello World!"
$ pestle.phar nexmo:send-text
Send to phone number? ()] 15555555555
From phone number? (12155167753)] 
Text to send? (You are the best!)] Hello World!    

After running the command, you’ll see the API response object in the terminal

array(2) {
  'message-count' =>
  string(1) "1"
  'messages' =>
  array(1) {
    [0] =>
    array(6) {
      'to' =>
      string(11) "15555555555"
      'message-id' =>
      string(16) "0D00000027C0976D"
      'status' =>
      string(1) "0"
      'remaining-balance' =>
      string(10) "1.84010000"
      'message-price' =>
      string(10) "0.00570000"
      'network' =>
      string(6) "310090"
    }
  }
}

and a message on your phone

Image of iPhone with waiting text message

Verification API

The other two commands, nexmo:verify-request and nexmo:verify-sendcode demonstrate Nexmo’s Verify API. The Verify API is a two step process that allows you to

  1. Collect a phone number from a user
  2. Present that user with a “verify you have access to this phone” form
  3. Send the user a text message (with a voice call as backup) with a code via the aforementioned phone number
  4. Allow the user to enter the code into the form
  5. Validate that code as correct

This is a common workflow for software that requires a user to have a working phone number. The verification API saves developers the initial programming involved in setting something like this up themselves. More importantly, with Nexmo handling your verifications, you’re freed from needing a devops or system engineer to monitor a home brewed system.

Having these commands as part of a command line tool is a little silly, but our point today is to examine base functionality, and the API code that drives it. The first command, nexmo:verify-request, takes two arguments.

$ pestle.phar nexmo:verify-request 15555555555 "Pestle"
$ pestle.phar nexmo:verify-request
Phone number to verify? ()] 15555555555
Brand/Prefix string for code message? (MyApp)] Pestle

The first is the phone number you’re trying to verify, the second is a “Brand” string. Nexmo’s API will use this brand string in the messages it uses when it sends the verification code to the end user. This is the command you’d run after collecting a user’s phone number for the first time. After running the above command, you’ll see the API response in your terminal

array(2) {
  'request_id' =>
  string(32) "xxxxxx51f914941b96a18cxxxxx772"
  'status' =>
  string(1) "0"
}

You should should also have a four digit code waiting for you on your phone

Image of iPhone with waiting text message

This brings us to the next command, nexmo:verify-sendcode. This command accepts two arguments — the request ID from the nexmo:verify-request response, and the four (or six!) digit code send to the user. In a normal situation you’d call this method after sending the verify request, and after the user entered their code.

pestle.phar nexmo:verify-sendcode xxxxxx51f914941b96a18cxxxxx772 2306

The terminal will output the response object returned by the API, or an error if Nexmo failed to validate the response.

array(5) {
  'request_id' =>
  string(32) "xxxxxx51f914941b96a18cxxxxx772"
  'status' =>
  string(1) "0"
  'event_id' =>
  string(16) "0X000000X0XXXXXX"
  'price' =>
  string(10) "0.03000000"
  'currency' =>
  string(3) "EUR"
}

Be careful and quick with these commands! If a particular request ID has three failed code checks, Nexmo will consider the request permanently bad. Also, if more than five minutes elapse from the time you first request the code to the time a user enters their code, Nexmo will still classify the code as invalid.

The Nexmo API and Composer Package

Now that you have a taste of Nexmo’s functionality, let’s take a look at where they really shine for PHP developers: Their REST API and Composer package.

If you’ve ever interacted programmatically with voice systems, you know how gnarly and complex their “APIs” can be. We put APIs in quotes because, while sometimes you’re lucky enough to find a system with SOAP like endpoints, more often than not you’re going to be doing some raw socket programming

That’s the first place Nexmo saves you — their API is completely REST based. You can see this right off the bat in their first code sample, which is a curl request to a URL

curl -X POST  https://rest.nexmo.com/sms/json \
-d api_key=xxxxxxx \
-d api_secret=xxxxxxxxxxxxxxxx \
-d to=TO_NUMBER \
-d from=12155167753 \
-d text="Hello from Nexmo"

Already, a PHP developer should feel at home. Even better than that though is, Nexmo has a fully modern, Composer based library that’s available via standard packagist channels.

Pestle makes use of this package for making API calls. If we take a look at the source of the nexmo:send-text command, we’ll see the following.

#The getClient method is defined in the store credentials library
#File: modules/pulsestorm/nexmo/storecredentials/module.php

function getClient()
{
    $data = readFromCredentialFile();
    $key = $data->key;
    $secret = $data->secret;    
    $client = new \Nexmo\Client(
        new \Nexmo\Client\Credentials\Basic($key, $secret)
    );
    return $client;
}    

#The nexmo:send-text definition file
#File: modules/pulsestorm/nexmo/sendtext/module.php
$client     = getClient();
$message    = false;
try
{
    $message = $client->message()->send([
        'to'   => $argv['to'],
        'from' => $argv['from'],
        'text' => $argv['text']
    ]);    
}
catch(Exception $e)
{
    handleException($e);
}        
if($message)
{
    output($message->getResponseData());
}

You instantiate a client object with some straight forward PHP code

$client = new \Nexmo\Client(
    new \Nexmo\Client\Credentials\Basic($key, $secret)
);    

The client itself is separated into different services — one for the Nexmo messaging API, another for verification, etc. Calling through to those methods is, again, just a simple call to PHP code. The following (from above) is where we call the API’s send method.

$message = $client->message()->send([
    'to'   => $argv['to'],
    'from' => $argv['from'],
    'text' => $argv['text']
]);    

We can see another example in the nexmo:verify-sendcode method.

#File: modules/pulsestorm/nexmo/verifysendcode/module.php
$client = new \Nexmo\Client(
    new \Nexmo\Client\Credentials\Basic($key, $secret)
);        
//...
$clientVerify = $client->verify();
$result = false;
try
{
    $result = $clientVerify->check(
        $verificationRequestId,
        $code
    );    
}
catch(\Exception $e)
{
    output(get_class($e));
    output($e->getMessage());
}
return $result;

Here we access the Verify API via the verify service

$clientVerify = $client->verify();

and call its check method.

#File: modules/pulsestorm/nexmo/verifysendcode/module.php
$result = $clientVerify->check(
    $verificationRequestId,
    $code
);         

This Composer based library is a second abstraction on top of the raw REST abstractions, and makes it incredibly easy for a PHP user to start adding SMS and voice capabilities to their applications.

Series Navigation<< Pestle 1.2.1 ReleasedPestle 1.3 and AbstractModel UI Generation >>

Copyright © Alana Storm 1975 – 2023 All Rights Reserved

Originally Posted: 14th March 2017

email hidden; JavaScript is required