Create an SMS Signup Form: Part 1

Create an SMS Signup Form: Part 1

This entry is part 1 of 2 in the series Create an SMS Signup Form

SMS is a worldwide technology used by almost everyone with a cell phone. Despite having a much greater reach than the smartphone market, SMS programming receives far less covereage and often remains uncapitalized. In this multipart tutorial, I will show you how to create a web site signup form that allows users to enter a mobile number. I will then show you how to use PHP for server-side phone number verification to check that the mobile number the user has entered is actually his mobile phone. Along the way, we will use jQuery to perform client-side validation and CodeIgniter as our development framework.

Step 1: Planning

Let’s begin with an overview of the solution. The user will access a signup form, select a country, and enter a mobile phone number. After submitting the signup form, the user will need to enter a verification code sent to the mobile phone number entered in order to active the new account. If the user closes the page before entering the verification code and later acceses the signup form again, the phone code form will still be displayed. Okay, let’s begin!

Step 2: Download CodeIgniter

Download CodeIgniter from www.codeigniter.com. Next, extract the folder and copy it to the webroot of your web server (you must have access to a web server that can parse PHP in order to complete this tutorial). Copying to your webroot is optional, but doing so will help us better navigate through the source files.

In the application dir, navigate to the config directory and open config.php. This is the main configuration, where we need to set some of the settings, like in the code below:

$config['base_url']      =   "http://localhost/sending_sms/";
...
$config['index_page']    =   "index.php";
...
$config['uri_protocol']	 =   "AUTO";

Next, open database.php in the same config folder and complete the following assignments:

db['default']['hostname']  = "localhost";
$db['default']['username'] = "root";
$db['default']['password'] = "__password__";
$db['default']['database'] = "sms_users";

Finally, open up autoload.php in the config folder and let’s add some libraries and helpers that we’ll need:

$autoload['libraries'] = array('database');
...
$autoload['helper'] = array('url', 'form', 'cookie');

Step 3: Signup Controller

Let’s create the signup controller. Create a file called signup.php in the application/controllers folder and let’s begin coding the main signup functionality:

class Signup extends Controller {
	function Signup(){
		parent::Controller();
	}
	function index(){
		$this->load->view('signup' );
	}
}

I have created the Signup class, you’ll notice it has the same name as the file, and that it extends Controller. I created the index() function that will handle the display of the signup form. We call it index because this is the default function that is called when accesing with the default url, without any segments. We’ll also have to configure the default controller ( signup ) in config/routes.php:

$route['default_controller'] = "signup";

If you test the app now, you’ll get an error telling you ‘Unable to load the requested file: signup.php’. This is because we haven’t created the signup view. Let’s do this now.

Step 4: Signup View

Create a new file signup.php in the apllication/views folder and enter the following markup:

<!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" />
  <title>Signup</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" />
  </head>
  <body>
  <div id="wrap">
  <h2>Signup form</h2>
  <?php echo validation_errors('<div class="error">', '</div>'); ?>
  <?php echo form_open('signup/process', array('id'=>'form') ); ?>
  <?php echo form_label('Name:', 'name'); ?>
  <?php echo form_input( array('name'=>'name', 'id'=>'name', 'class'=>'required', 'value'=>set_value('name') ) ); ?>
  <?php echo form_label('Email:', 'email'); ?>
  <?php echo form_input( array('name'=>'email', 'id'=>'email', 'class'=>'required email', 'value'=>set_value('email') ) ); ?>
  <?php echo form_label('Country:', 'country'); ?>
  <?php echo form_dropdown('country', $countries, '','id="country" class="required"' ); ?>
  <?php echo form_label('Mobile phone:', 'mobile'); ?>
  <div><?php echo form_input( array('name'=>'prefix', 'id'=>'prefix', 'value'=>set_value('prefix') ) ); ?>
  <?php echo form_input( array('name'=>'mobile', 'id'=>'mobile', 'class'=>'required digits', 'value'=>set_value('mobile') ) ); ?>
  </div>
  <div align="center"><?php echo form_submit('register', 'Register', 'class="submit"' ); ?></div>
  </div>
  </body>
  </html>

Let me explain some of the markup. I have added in the head a reset.css file with the usual meyerweb reset CSS rules and a design.css file, which we will code later. I’ve put these two in a folder in the root called ‘css’. I use base_url() to get the root in the view file.
I used the form helper to create the form opening, while giving the id of the form ‘form’, I created a couple of labels and inputs using the same form helper. You’ll notice I pass an array as the second parameter of the form_input() function with id or class keys. For more information on using the form helper, read the CodeIgniter documentation. I used form_dropdown() to create a select box, which gets passed an array of options named $countries. We don’t have this array yet, but we’ll also make it a bit later.

Step 5: Signup CSS

Create the file design.css in the css directory and put in the apllication/views folder and enter the following css rules:

body {
	background-color: #CFCFCF;
	padding: 0px;
	margin: 0px;
	font-size: 12px;
	font-family: Helvetica, Verdana, Arial, sans-serif;
}
#wrap {
	width: 400px;
	margin-left: auto;
	margin-right: auto;
	margin-top: 40px;
	background-color: #ECECEC;
	border: solid 1px #FCFCFC;
	padding: 10px;
}
h2 {
	margin-bottom: 10px;
	font-size: 18px;
}
label {
	display: block;
}
input, select {
	width: 380px;
	padding: 5px;
	margin-bottom: 10px;
}
select {
	width: 390px;
}
#prefix {
	width: 50px;
	margin-right: 10px;
   	margin-bottom: 0px;
	display:inline;
}
#mobile {
	width: 305px;
	display:inline;
}
input.submit {
	background-color: #E0E0E0;
	border: solid 1px #C5C5C5;
	width: 140px;
	font-weight: bold;
	margin-top: 10px;
}
input.error, select.error {
	margin-bottom: 0px;
	border: solid 1px #FFCCCC;
}
div.error {
	padding: 5px;
	background-color: #ffeeee;
	border: solid 1px #FFCCCC;
	color: #ff0000;
}
div.ok {
	padding: 5px;
	background-color: #CCFFCC;
	border: solid 1px #44CC44;
	color:#336633;
	margin-bottom: 10px;
}

I created the wrap div style, centering it by setting margin-left and margin-right to auto. I then styled the inputs, making sure they are consistent across all browsers, and then created 3 error classes: .error, .ok, and input.error. We’ll use this with the jQuery validation plugin. I also used 5px padding where I felt necessary for styling.

Step 6: Countries and Prefixes

If you test now, you’ll get a notice saying ‘undefined variable countries’ and ‘invalid argument supplied for foreach()’. How do we add the countries? Well, we could embed them directly on the select, but we’ll use a configuration file instead. This ensures that we can change any country code easily and quickly. I copied the table with country codes from countrycode.org in a new file and used a clever bit of jQuery to process all the contents in a single string, giving me the final configuration file. I won’t go into the details. If you want to know, leave a comment. Create a new file called ‘countries.php’ in the application/config folder and add the countries in the #config array using the following model:

$config = array();
$config[''] = '';
$config['93'] = 'Afghanistan';
$config['355'] = 'Albania';
$config['213'] = 'Algeria';
...
$config['967'] = 'Yemen';
$config['260'] = 'Zambia';
$config['263'] = 'Zimbabwe';

I used the prefix codes as keys in the array. How do we access this in the view? We’ll load this particular configuration file in the controller function index() we created earlier:

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

I used ‘$this->config->load()’ to load the config. You’ll notice I also passed true as the second parameter. This makes a separate entry called ‘countries’ in the global configuration. If we don’t pass true, the config settings ( the array from the config ) is added to the global configuration array. After that we just assign the config item to $data['countries'], which is then recognised by the view as $countries. I also pass the $data array to the view as the second parameter. If you test the page now, you’ll get all the countries in the select box! Great right?

Step 7: Validation with jQuery

It’s time to do some jQuery. We’ll use jquery Validation plugin for this. This plugin is already in Microsoft’s CDN so we’ll get it from there, as well as jQuery from Google’s CDN. We also need the metadata plugin in order to write the classes directly in the html:

<!-- html head -->
<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(){ $('#form').validate( {'errorElement': 'div' } ); }); </script> <!-- html head -->

The validation plugin works by suppling a class name to the input: required for requiring non-empty values, email for validation of an email adress, digits for numeric inputs, and more which I won’t get into. You’ll notice I hard coded the classes in the inputs, just look at the html at the begining. If you test now, you’ll see that you get an error div after the input with a class of .error which I coded in the css. I also coded the input.error class, as the input that is not valid is assigned an .error class, too. This validates the form, if the user has JavaScript enabled.

Step 8: Changing the Phone Prefix Based on the Country Select

We’ll now use a clever event to change the prefix input’s value when the user selects a country. This is done only for visual purposes, as in the backend we’ll get the prefix from the country value, but this shows the user how to enter his phone. Let’s do this now:

<script type="text/javascript">
$(document).ready( function(){
	$('#form').validate( {'errorElement': 'div' } );
    //change the prefix based on the country select
	$('#country').change( function(){
    	$('#prefix').val( $('#country option:selected').val() );
	});
});
</script>

Ok, so I created a function to the change event of the select, and assigned the selected option’s value to the prefix input value. Not a big deal, but it makes our signup form really easy.

This is all we need for the signup view. Let’s create the activation function and view.

Step 9: Activation Code View

This is the page that the user will see after succesfully signing up. There will be a message telling him to check his mobile as we have sent him a code that he has to enter. In the signup.php controller, create a new function called activate():

function activate(){
    $data = array();
    $data['error'] = '';
    $this->load->view('activate', $data );
}

In case the activation is incorrect, I have defined an error variable for use in the view. This page will be accessed after we succesfully enter the user details and send the SMS. We’ll also create a new file called activate.php in the application/views folder and enter the following markup:

<!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" />
  <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);
  	$('#form').validate( {'errorElement': 'div' } );
  });
  </script>
  </head>
  <body>
<div id="wrap">
  <h2>Confirm mobile phone</h2>
  <div class="ok">Your account has been created. A sms has been sent to your mobile with a 5 digit activation code. Please enter the code to complete signup:</div>
  <?php echo $error; ?>
  <?php echo form_open('signup/activate', array('id'=>'form') ); ?>
  <?php echo form_label('Code:', 'code'); ?>
  <?php echo form_input( array('name'=>'code', 'id'=>'code', 'class'=>'required digits', 'value'=>set_value('code') ) ); ?>
<div align="center"><?php echo form_submit('signup', 'Complete signup', 'class="submit"' ); ?></div>
  <hr />
  If you haven't received the sms, please <a href="#">click here</a> to send it again
</div>
</body>
</html>

The markup is pretty simple here. I have included the same jQuery and validation plugin. Inside the document.ready event, I called jquery.validate() like in the first page. We’ll use validate for validating the authorization code. I also fade in the message div, to show a success message. I also put a class name of ‘required’ and ‘digits’ to resttrict the input field to numbers and nonempty values. There is also a message with an option for the user to resend the activation code, but I won’t go into this functionality, as it is pretty similar to the basic signup.

Step 10: process() Background Function

Let’s create the function that will process and insert the data in the database. We’ll also use the validation library. It’s important to have validation on the server, as some people can turn off JavaScript and so the validation won’t work. This is a fallback that assures us we won’t have any invalid data in the table. The function process is below:

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
        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 );
    }
}

Well, that is a lot of code! Let’s go through all the major parts:

We first load the form validation library. After that we use form validation’s run() function to check for the correct values. If all the inputs pass, we make an array with all the post data using $this->input->post(‘input_name’) and insert the data into a table called users, which we’ll make in a moment. One thing to note here is that I also generate the auth code. I use mt_rand() to seed the random generator and generate a unique 5 cypher number. We do this by running rand() to generate a number between 11111 and 99999. This always gives us a number of 5 cyphers in length. I didn’t use 10000 because we can get a number that repeats its cyphers, like 10002, which doesn’t look too random. I also set a cookie called ‘signed’ with the value of the insert id from the actual insertion in the database and then redirect the user to the activation function. If some fields are invalid, we load the countries again and load the signup view. If you look at the signup view from the begining you’ll see that I use set_value() to get the used value from the last signup. So if there is an invalid field, the rest of the fields will be filled with the last data. But there is one line we need to update in the signup view:

<?php echo form_dropdown('country', $countries, @$_POST['country'],'id="country" class="required"' ); ?>

I have replaced the third parameter with $_POST['country'], making sure it doesn’t show a notice with @. This will set the select option to the one that was selected before the submit. If we don’t have a country in the post data, we won’t select anything, as is the case at the begining of the signup.

Step 11: Validation Rules

Ok, I bet you’ll ask: How does the server knows what is the right format for the server-side validation ? Well, we have to create the rules for the validation. Fortunately, CodeIgniter allows you to write them in a config file called form_validation.php in the application/config folder. Create the file if it doesn’t exist already and enter the following:

$config = array(
	array('field'=>'name',
		  'label'=>'Name',
		  'rules'=>'required'),
	array('field'=>'email',
		  'label'=>'Email',
		  'rules'=>'required|valid_email|callback_check_email_exists'),
	array('field'=>'country',
		  'label'=>'Country',
		  'rules'=>'required'),
	array('field'=>'mobile',
		  'label'=>'Mobile phone',
		  'rules'=>'required|numeric')
);

I use this multidimensional array to set the corresponding rules for the validation. For example, for the name field, I use the key ‘field’ to set the rules for the name field, the ‘label’ key for setting the name of the field in the error message ( if it shows ) and the ‘rules’ key to set the rules. I separate the rules with a pipe characther (i.e. ‘|’). For more information on the available rules check the form validation documentation in the user guide. I also create a user defined callback ( callback_check_email_exists ) to check if the email exists. Adding callback_ to the rule name searches for a function in the controller and calls it. This function will check for the existence of the same email adress in the database, and the source is:

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;
}

This is a simple function which accepts an argument ( the value being checked ) and returns true or false depending on the format. We check if there is a result with the e-mail adress in the table, and if there is, we return false. We have to return true if we want to validate and false for invalid, so the function name is a bit akward.

Step 12: MySQL Table

Don't even think to test the actvation now! You'll get a nasty error because we haven't created the table ! Well, you can just download the source code and import the users table from the users.sql file or create it with the following commands:

CREATE TABLE `users`
( `uid` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`name` TEXT NOT NULL,
`email` TEXT NOT NULL,
`country` INT NOT NULL,
`mobile` TEXT NOT NULL,
`activation` TEXT NOT NULL,
`active` INT NOT NULL,
PRIMARY KEY (`uid`) );

Run this code in phpMyAdmin and you'll have the table created.

If you test the code now, you'll get all the validation correct. You can just disable JavaScript to try the server validation. You won't get in with invalid data! I warned you!

End of part 1

This is the end of the first part. Next time, in part two of this series, we will cover actually sending SMS using a third party SMS gateway service. I hope you enjoyed my tutorial and thank you for staying to check it all out!

Series NavigationCreate an SMS Signup Form: Part 2»

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.ecustom.ca/ Damon Bridges

    Very cool thanks! And it combines two of my favourite web frameworks, jQuery and CodeIgniter!

    Can’t wait for part two!

  • http://ilopezdeaudikana.com mutiu

    very well explained… this will be very useful.

    thank you.

  • Sanjay

    I am waiting for part two please publish it as soon as possible. thanks

  • Cricket La Chica

    Very interesting. Thank you for this! I’m excited for Part 2 as well. :-)

  • http://thedevelopertuts.com Bratu Sebastian
    Author

    Thank you for the nice comments. After part two, you’ll be able to make signup forms and know for sure people’s telephone, this is great for sales purposes as well, unless exaggerated, but for clients is great.

  • noname or nameless how you want it..

    Why aren’t there any demo’s?

  • http://www.thomassale.com Silver Charms

    Thank you for the nice comments!

  • http://www.okadadesign.no/blog shinokada

    It might be a good idea to create a model for function process() or part of function process() since it is related to db.

  • http://gamecopywizard.info/ Game Copy Wizard

    I enjoy the efforts you have put in this, appreciate it for all the great blog posts.

  • KJ

    Hello~ I am trying to create the sign up function by your tutorials…..
    after I completed step 5…I was testing as you said in the beginning of step 6 …but it’s not shown “undefined variable countries’ and ‘invalid argument supplied for foreach()’” as you said…

    it’s shown this on my page

    class Signup extends Controller { function Signup(){ parent::Controller(); } function index(){ $this->load->view(‘signup’); } }
    A PHP Error was encountered

    Severity: Warning

    Message: Cannot modify header information – headers already sent by (output started at /Applications/MAMP/htdocs/sending_sms/application/controllers/signup.php:11)

    Filename: core/Common.php

    Line Number: 413

    any idea about this?

    appreciate your help…

    KJ

  • http://www.totalittech.com/english.html computer repair

    There is noticeably a bunch to know about this. I assume you made some nice points in features also.

  • http://www.adeptmarketingsolutions.com marketing brighton, mi

    It’s best to participate in a contest for the most effective blogs on the web. I will suggest this site!

  • http://www.drainage-experts-yorkshire.co.uk blocked drain bradford

    Merely a smiling visitant here to share the love (:, btw outstanding style.

  • http://www.ludiccrew.org/technik/navigationsgerate/ Erkennungsmarken

    I simply wished to say thanks yet again. I do not know what I could possibly have done without the recommendations documented by you regarding this area of interest. It seemed to be a alarming difficulty in my view, however , seeing the expert technique you managed the issue took me to jump over delight. Now i am grateful for your work and hope you know what a great job you were putting in educating many others with the aid of a web site. Most probably you haven’t come across all of us.

  • Drupalfan

    Your code is excellent and teaches a lot on how to code on php and produce wonderful scripts like sms login.. bt can you guide me with execution of the sms signup form as im having difficulties in accessing my page(error: you do not have permission to access this file) even in the administrator login

    • http://thedevelopertuts.com Bratu Sebastian
      Author

      Sorry Drupalfan, I cannot help you with the issues, it’s probably from the framework you’re using. I don’t have the time, but thanks for your kind comment. Hope you fix it.

  • http://mzoori.com Brian

    hi,
    am trying to implement your tutorial. Where do we save the component created in step 8?

    Thanks again for the awesome tutorial.

  • http://www.microfiberpouch.com microfiber cleaning cloth

    There is noticeably a bundle to comprehend this. I suppose you抳e made certain nice points in functions also.

  • http://none manu

    thanks

  • http://mikemurray214.hubpages.com/hub/WineTypes Hilton Kickel

    Its like you read my mind! You appear to know a lot approximately this, like you wrote the e book in it or something. I feel that you could do with some % to drive the message house a bit, but instead of that, this is magnificent blog. An excellent read. I will certainly be back.

  • https://www.facebook.com/Alsharkawi.Heba Sodain

    AWESOME.

  • http://www.mag-projekt.de/ MAG Projekt GmbH

    Oh my god, here is a lot of explanations but I still have problems with finding solutions. I work for a software company that is connected to the internet or web hosting. Parts are in PHP but we never managed to connect Java and PHP. My boyfriend said he would break her engagement with me if this does not end up in a few days. I could not go home I promised my boss. Help me please.