Ecommerce Developer
 
 

Code

Tutorial: How to Create a Secure User Form in PHP

 

Most of the content on a website is free information meant to be seen by the general public. However, some parts of a website, such as administration tools to control content or subscription areas where access to content requires prepayment, should be locked down so that only authorized users will be let in.

This tutorial will explore how to build a secure user form that asks a user for their email address and password in order to authenticate them. If he or she fails to log in correctly, an error message will be shown.

Note, it is assumed that the following code will all run on a website that is secure socket layer (SSL) protected.

The Database

We start by creating a database called 'test', and a table on the database called 'user'.

CREATE DATABASE `test` ;
CREATE TABLE `test`.`user` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 75 ) NOT NULL ,
`password` TEXT NOT NULL ,
UNIQUE (
`username`
)
) ENGINE = MYISAM ;

We're setting the password field as a 'text' field in order to make sure that there is enough room for the password once we have encrypted it. Let's put some data in now:

INSERT INTO `test`.`user` (
`id` ,
`username` ,
`password`
)
VALUES (
NULL , 'seanrowe', MD5( 'somepass' )
);

The Database Model

Next we'll create a PHP class to work with our test database.


<?php
class Model {
/**
* Here we construct a connection to the database using PHP's PDO database class.
Using this class, we are able to prepare SQL
* statements, which guards us against SQL injection attacks.
*/
public static function get_connection() {
$dsn = 'mysql:dbname=test;host=127.0.0.1'; // put your database address where
127.0.0.1 is, unless this is your database address
$user = 'dbuser'; // your username
$password = 'dbpass'; // your password
$dbh = null;
try {
$dbh = new PDO($dsn, $user, $password);
} catch (PDOException $e) {
echo 'Connection failed: ' . $e->getMessage();
}
return $dbh;
}
/**
* Here we check a given username and password to see if it is in the user table. If it
is, we return true; otherwise we return false.
* Notice that the password is md5 encrypted, so we encrypt the given password in
order to check it against what is already in
* the table.
*/
public static function check_login($username, $password) {
$dbh = Model::get_connection();
$sql = "SELECT * FROM `test`.`user` WHERE `test`.`user`.`username` =
:username AND `test`.`user`.`password` = :password";
$sth = $dbh->prepare($sql, array(PDO::ATTR_CURSOR =>
PDO::CURSOR_FWDONLY));
$sth->execute(array(':username' => $username, ':password' =>
md5($password)));
$answer = $sth->fetchAll();
return count($answer) > 0;
}
}
?>

We create a separate class to interact with the database in order to separate our backend code from our frontend code. This is known as the Model View Controller (MVC) architectural pattern, and following it helps to separate the backend database code from the business logic, as well as the presentation logic. Next, we create a controller class that will implement the User class.

The View

The view contains all the html to draw the form. In addition, it contains a hidden div that will display error information in the event that either the user didn't enter in all the information necessary to authenticate them, or they have entered an invalid username or password.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/
strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Login Form</title>
<style type="text/css">
.missing {
color: red;
}
.required:before {
content:"* ";
}
</style>
</head>
<body>
<fieldset>
<legend>Login Form</legend>
<div class="field">
<label for="username" id="username_label">Username</label>
<input type="text" name="username" id="username"/>
</div>
<div class="field">
<label for="password" id="password_label">Password</label>
<input type="password" name="password" id="password"/>
</div>
<input type="button" name="login_button" id="login_button" value="Login"/>
</fieldset>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/
1.3.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#login_button').click(function() {
$.ajax({
type: "POST",
url: "login.php",
data: "username=" + $('#username').val() + "&password=" +
$('#password').val(),
success: function(msg){
msg = eval("(" + msg + ")");
if (msg.missing) {
if (msg.missing.username) {
$('#username_label').addClass('missing');
} else {
$('#username_label').removeClass('missing');
}
if (msg.missing.password) {
$('#password_label').addClass('missing');
} else {
$('#password_label').removeClass('missing');
}
} else {
$('#username_label').removeClass('missing');
$('#password_label').removeClass('missing');
}
if (!msg.missing) {
if (msg.success) {
alert("Login Successful!");
} else {
alert('Login Failed!');
}
}
}
});
});
});
</script>
</body>
</html>

When the user clicks on the 'Login' button, it will send a post request back to login.php, which is our controller that implements the Model. Let's see how this works.

The Controller

The controller file holds all the business logic pertaining to the view, and in this instance it will use the Model class to query the database to see if the given username/password is in the user table.

<?php
require('model.php');
/**
* First, check to make sure that the username and password values were sent over in
the request
*/
if (!isset($_REQUEST['username']) || empty($_REQUEST['username'])) {
echo json_encode(
array('missing' => array('username' => true))
);
return;
}
if (!isset($_REQUEST['password']) || empty($_REQUEST['password'])) {
echo json_encode(
array('missing' => array('password' => true))
);
return;
}
/**
* Next, using the check_login function in the model class, make sure that the username/
password combination exists in the table
*/
if (!Model::check_login($_REQUEST['username'], $_REQUEST['password'])) {
echo json_encode(array('success' => false));
} else {
echo json_encode(array('success' => true));
}
?>

Summary

Using the PDO class to talk to our database, and a bit of AJAX on the frontend, you can build a very simple login form that is both secure and extensible. Following the MVC architectural pattern, your code will look nice and be easy to manage. Instead of just echoing out 'success' or 'failure,' the code could be modified to do any number of tasks, from redirecting a user to an administrative area to taking the user to a section of the site that is only available to registered users.

Related Articles

0 Comments

Rss-sm