Advertisement

Create an SMS Signup Form: Part 2

by
Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →
This post is part of a series called Create an SMS Signup form.
Create an SMS Signup Form: Part 1

Welcome to part two of this tutorial on using SMS technology to create a signup form. Previous, in part one of this series, we used HTML, JavaScript, MySQL, and PHP to create a signup form. In this tutorial we will cover integration with an SMS gateway and the code necessary to finish processing the signup form.


Step 1: Where We Left Off

In the first part of this series, we created two functions: signup and activate. As the names indicate, the first is used for the form signup and the second for entering the activation code. We'll continue by demonstrating how to use two different SMS gateway services for sending messages. What is an SMS gateway? It is essentially a service that provides access to mobile network traffic with one or multiple cell phone carriers. So, why use two different services? My first choice was Clickatell, but in order to send SMS messages in the US without a shortcode, I had to find another service. SmsMatrix is a great service that can send messages in many different countries, including the U.S. I could have just used SmsMatrix alone, but instead I will use both services to demonstrate how you would enable the server to select a service based on the country you are targeting. This may well happen in the real world, as you may vary gateways to save on the cost per message or as a backup in case the first service you try responds with an error code.


Step 2: The Clickatell Class

Clickatell is among the largest online SMS gateways available. According to the information on their website, Clickatell currently supports 221 countries and territories. They have a lot of features, including simple SMS, two-way SMS, and shortcode SMS. They also have an impressive user-base, serving over 10,000 clients around the world. Some of these clients include CNN, Continental Airlines, Vodafone, Oracle, Nokia and other big players in IT and business. The nice thing about Clickatell is that you can signup for a free account and use 10 free credits for sending SMS messages while you are learning. SMS gateways typically work with credits that you buy to send SMS messages. The amount of credits a single SMS message will cost varies depending on where (geographically) the message is sent. Go to Clickatell and signup for a free account. When you send with the test credits, the content of the message will be replaced with information about testing, but that should work fine for our needs. When you signup, be carefull to signup for Clickatell Central and select Coverage excluding the USA, as you need a special shortcode number for sending to the USA.

After you have succesfully activated your account and logged in, click the "click here to create a new connection" link. This will setup an api_id with which you can send SMS.

Select HTTP as the connection type. Clickatell offers many options for sending SMS, the easiest one being probably to send an email to a certain adress. They support a lot of protocols like XML, SOAP, and even FTP for bulk messaging. The HTTP connection is all we will need.

Continue and click on Get API ID. You will get a page with an example string. Copy the example string into your browser and replace the username, password and to parameters with your username, password and mobile phone number. You'll get a result in the browser with an "OK" or "ERR" message followed by a code. This is what we need to build our Clickatell library.

To begin creating the Clickatell library, create a new file called Clickatell_api.php in the application/libraries folder. Enter the following code:


class Clickatell_api {
    
    //change this to the actual user and password
    private $username = 'username';
    private $password = 'password';
    private $api_id   = 'api id';
    private $url      = 'http://api.clickatell.com/http/sendmsg';
	
    public function send_sms( $phone, $text ){
        $url = $this->url . '?user=' . $this->username .
        '&password=' . $this->password .
        '&api_id=' . $this->api_id .
        '&to=' . $phone .
        '&text=' . urlencode( $text );
		
        $r = @file( $url );
        $res = substr( $r[0], 0, 2);
		
        if( $res == 'ER' ){
            return false;
        }
        return true;
    }
    
}

The code is pretty self explanatory, but before we begin reviewing it, note that in a production environment this script should either reside in a directory outside of the web root or rely on your server configuration to prevent public access. The last thing you want is for someone to be able to call this script directly from a browser or another script.

In the example above, we create a Clickatell_api class which has a few memebers: username, password, api_id and the url which we will build upon. Replace with your own username, password and api_id. Inside the class we have a single send_sms() function which accepts a phone number and the text message to be sent. The class builds the url by concatenating the class members and forming a final url. We use urlencode() to encode the text in the url and later pass it to file(). Of course, for servers that have the file() function blocked, you can use CURL, but that's not the point of the tutorial. We then get the result and use subtr() to get the first two characters from the first line. If the response is 'ER', which comes from ERROR, we return false, else we return true. This is all the class does, but it is still better to use a class as you can reuse it later in any application.


Step 3: The SmsMatrix Class

SmsMatrix is another powerfull service. This one has a lot more advanced stuff, like text-to-voice conversion, programmable response ( "please press 2 for yes or 1 for no"), and voice messages, but the most important thing for us is that it doesn't require you to have a shortcode number to send SMS messages in the U.S. They also have a free account option which gives you 5 credits to test your SMS app. Getting setup with SmsMatrix is simpler than Clickatell: you create the account, and then you use your username and password to send the SMS message. You'll need the sms sending guide, but the idea is the same: you form a special url and access it with PHP. Let's create an smsmatrix_api library for this. Create a file named Smsmatrix_api.php in the application/libraries folder and write the following:

class Smsmatrix_api {

	//change this to the actual user and password
	private $username = 'username';
	private $password = 'password';
	private $url	  = 'http://www.smsmatrix.com/matrix';
	
	
	public function send_sms( $phone, $text ){
		$url = $this->url . '?username='.urlencode( $this->username ) .
		'&password=' . urlencode( $this->password ) .
		'&phone=' . $phone .
		'&txt=' . urlencode( $text );
		
		$r = @file( $url );
		$res = substr( $r[2], 11);
		if( $res > 399 ){
			return false;
		}
		return true;
	}

}

Again, we create a class with the username, password and members and create the same send_sms() function. We called it the same, so that the classes could be interchangable. We create the final url, we access it with file() and we get the result code. The result code is in the 3rd line of the result string, so we use subtrs( $r[2], 11) to get the number after the string 'STATUSCODE='. I got the error codes from the pdf guide and basically any code below 399 is success so we return true, otherwise we return false.


Step 4: Controller Integration

Ok, it's time to go back to our signup controller. Go to the function process() and enter the following code after the database insertion:

// send auth SMS if in US
if( $this->input->post('country') == 1 ){
    $this->load->library('smsmatrix_api');
    $this->smsmatrix_api->send_sms( $signup['mobile'], $signup['activation'] );
} else { // when not USA
    $this->load->library('clickatell_api');
    $this->clickatell_api->send_sms( $signup['mobile'], $signup['activation'] );
}

First, we check the country code, if it's 1 ( i.e. United States ) we will use SmsMatrix, so we load it with $this->load->library('smsmatrix_api'). If the country is not United States, we load the clickatell_api. Either way, we use send_sms() to send the activation code to the mobile number. You'll notice the mobile number is inserted before in the database by concatenating the country value ( which holds the prefix for that country ) with the mobile number. We could actually complete the second parameter in the library load to access it with a certain name, and only use send on the library:

// send auth sms if in US
if( $this->input->post('country') == 1 ){
	$this->load->library('smsmatrix_api', 'sms_api');
} else { // when not in US
	$this->load->library('clickatell_api', 'sms_api');
}
$this->sms_api->send_sms( $signup['mobile'], $signup['activation'] );

This way, we load only the appropriate library with the same name, accesing it with 'sms_api', but it's the same thing. Basically the two libraries share the same interface. Further, if you get false as a return value, you can send the SMS with the other library as a backup.


Step 5: Cookie Redirection

If we set a 'signed' cookie after sending the SMS message, we can use it later to prevent multiple messages from beign sent. We need to do it in such a way that when the user navigates away from the signup form and later goes back to try and signup again, we will automatically redirect him to the activate function. Add this in the top of the signup() function:

function index(){
    if( get_cookie('signed') ){
        redirect('signup/activate');
    }
    $this->config->load('countries', true);
    $data['countries'] = $this->config->item('countries');
		
    $this->load->view('signup', $data );
}

This way, if you signup once and you try to access the signup form again, you will get to the same activate function that tells you to enter the activation code. Let's take care of the activation next.


Step 6: The Activation Function

We'll now create the activation process:

function activate(){
    if( !get_cookie('signed') ){
        redirect('signup');
    }
		
    $data['error'] = '';
		
    if( $this->input->post('signup') ){
	    //if sent
        $where =  array('uid'=>get_cookie('signed'),'activation'=>$this->input->post('code') );
        $result = $this->db->where( $where )->count_all_results('users');
        if( $result < 1 ){
             $data['error'] = '<div class="error">The authorization code is not correct!</div>';
        } else {
            delete_cookie('signed');
            $this->db->set( array('active'=>1, 'activation'=>'') )->where('uid', get_cookie('signed') )->update('users');
            redirect('signup/success');
        }		
    }
	
    $this->load->view('activate', $data );
}

Let me explain what is going on here: I do the reverse, if the cookie is not set I redirect to signup. Then, I set the error message to '', because we don't have any error now. If the signup post field has been set (i.e. if the form has been submitted), I look for an entry in the table with the id from the cookie and the activation equal to the code submitted. It's important to never have an id of 0 in the database, as this would make the cookie false, and there would be a redirect loop. This check can be done, but it's better to set it in the database.

I count the rows returned, and if I don't get any, I show an error that the authorization is not correct. As the user can only have a certain activation code, when you enter the wrong code, the database won't find any row and return 0. If we find a row, we delete the cookie, as we don't need it anymore, we set the active column to 1 and the activation to '' and update the table. From this point on, the user is activated and we know for sure that it's his phone, and we can probably send a special offer as an sms. I also redirect the user to the success() function, which is a simple view with this success message:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><br />
  <title>Activate</title>
  <link rel="stylesheet" href="<?php echo base_url(); ?>css/reset.css" type="text/css" />
  <link rel="stylesheet" href="<?php echo base_url(); ?>css/design.css" type="text/css" />
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
  <script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
  <script type="text/javascript" src="<?php echo base_url(); ?>js/jquery.metadata.js"></script>
  <script type="text/javascript">
  $(document).ready( function(){
  $('.ok').hide().fadeIn(800);
  });
  </script>
  </head>
  <body>
  <div id="wrap">
  <h2>Success</h2>
  <div class="ok">Thank you, your account has been activated!</div>
  </div>
  </body>
  </html>

Step 7: The Final Controller Code

This is the final signup controller code:

class Signup extends Controller {

	function Signup(){
		parent::Controller();
	}
	
	function index(){
		if( get_cookie('signed') ){
			redirect('signup/activate');
		}
		$this->config->load('countries', true);
		$data['countries'] = $this->config->item('countries');
		
		$this->load->view('signup', $data );
	}
	
	function process(){
		$this->load->library('form_validation');
		
		if ( $this->form_validation->run() ){
		
			$signup = array();
			$signup['name'] = $this->input->post('name');
			$signup['email'] = $this->input->post('email');
			$signup['country'] = $this->input->post('country');
			$signup['mobile'] = $this->input->post('country').$this->input->post('mobile');
			//generate the unique activation code
			mt_rand();
			$signup['activation'] = rand( 11111, 99999 );
			
			//insert into db
			$this->db->insert('users', $signup );
			
			//send auth sms
			//if in United States
			if( $this->input->post('country') == 1 ){
				$this->load->library('smsmatrix_api');
				$this->smsmatrix_api->send_sms( $signup['mobile'], $signup['activation'] );
			} else {
				$this->load->library('clickatell_api');
				$this->clickatell_api->send_sms( $signup['mobile'], $signup['activation'] );
			}
			
			set_cookie('signed', $this->db->insert_id(), 86500 );
			//redirect
			redirect('signup/activate');					
			
		} else {
			$this->config->load('countries', true);
			$data['countries'] = $this->config->item('countries');
			
			$this->load->view('signup', $data );			
		}	
	}
		
	function check_email_exists( $email ){
		$rs = $this->db->where( 'email', $email )->count_all_results('users');
		$this->form_validation->set_message('check_email_exists', 'We\'re sorry, this email already exists!');
		if( $rs < 1 ){
			return true;
		}
		return false;
	}
	
	function activate(){
		if( !get_cookie('signed') ){
			redirect('signup');
		}
		
		$data['error'] = '';
		
		if( $this->input->post('signup') ){
			//if sent
			$where =  array('uid'=>get_cookie('signed'),'activation'=>$this->input->post('code') );
			$result = $this->db->where( $where )->count_all_results('users');
			if( $result < 1 ){
				$data['error'] = '<div class="error">The authorization code is not correct!</div>';
			} else {
				delete_cookie('signed');
				$this->db->set( array('active'=>1, 'activation'=>'') )->where('uid', get_cookie('signed') )->update('users');
				
				redirect('signup/success');
			}			
		}
		
		$this->load->view('activate', $data );
	}
	
	function success(){
		$this->load->view('success');
	}
}

Conclusion

Thanks for reading this tutorial! As the outcome of this tutorial is small, and testing is expensive, we don't have a preview, but you can run this from the sources provided with your own test accounts. This is only a small part of what can be done with Clickatell and SmsMatrix. There are a lot of things you can try, like sending to multiple phones, mass advertising, e-mailing a voice file to create a voice message, TTS messages and so on. I hope you enjoyed my tutorial, and I hope you use it in your next generation SMS application! Thank you for following my tutorial and write in the comments what you have come up with!

Advertisement