Host Matrix Forums Welcome to Host Matrix! To get started, register now!

Go Back   Host Matrix Forums > Tutorials & Articles > PHP Tutorials

Reply
 
Thread Tools Display Modes
Old 07-31-2009, 08:12 PM   #1
Mike
 
Mike's Avatar
 
Join Date: May 2008
Posts: 482
Mike Contributing Member (Qualifies for Package 2)Mike Contributing Member (Qualifies for Package 2)
Lightbulb Creating a Secure PHP Membership System using MySQL

Hello, Hostmatrix! I've decided to write my first "real" tutorial instead of a snippet this time for all of you to enjoy and hopefully learn from; hopefully you will learn something, even if you are experienced with PHP. So I will be teaching you how to make a user system, being that it is a popular topic for people to want to learn about. But not just any user system! A secure user system!

First, what you will need is some PHP hosting that supports MySQL databases. You can check out our hosting packages if you meet the requirements, as our hosting supports all of the features that will be used in this tutorial.

Now that we have all of this out of the way, we will now start the tutorial. Each "heading" will just be bolded so that you can distinguish the parts from each other. I will also put filenames in italics. Finally, things that you definitley need to change in the code are bolded in the code boxes. Simple and effective, right? Note that this tutorial will be showing through cPanel, so it may be different with set up with your provider if you don't use HM, though it shouldn't be hard to figure out!

Setting up the Databases

This tutorial will have a lot of MySQL involved, so we need to make sure we can set up a database and keep consistant with it. So first we will need to set up a database. Open cPanel and click on the "MySQL Databases" button. Scroll down until you see the following:



There, enter "usys", which will become "cpanelusername_usys" once you click "Create Database". Then, you will need to create a MySQL user on your account in this form (after creating the database):



Create the username and password you wish your database to have and click submit. Keep these safe, as you don't want malicious users figuring out your database information and dropping your tables! Now, all we have to do is add the MySQL user to the database and we will be ready to use it. Scroll to the following form:



We want to keep it checked to "ALL" because we want to be able to use all of the functions that MySQL has to offer with this database

Well, now we are ready to actually put something into the database, instead of having a useless piece of data stored in your account! Open phpMyAdmin by going to the link near the bottom of the MySQL page and click on the SQL icon in the sidebar. We are going to write some code so that MySQL will create the database the way we want! In the code box, we will put:

Code:
CREATE TABLE `cpanelusername_usys`.`users` (
    `id` INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
    `username` VARCHAR( 16 ) NOT NULL ,
    `password` VARCHAR( 32 ) NOT NULL ,
    `email` VARCHAR( 255 ) NOT NULL
) ENGINE = MYISAM
The first line tells MySQL that you want to create the table 'users' on the database 'cpanelusername_usys' (replace cpanelusername with your cPanel username). The second line creates an integer field 10 characters long, which increments automatically with each new value. The other fields it creates are strings of various lengths for storing things such as usernames, email addresses and more. The final line just tells which engine to use and closes the SQL query.

A Note on Security

Throughout the years, people have found ways to manipulate data sent from browsers to servers, often using methods known as "SQL Injection", which basically allows them to enter malicious stuff into the form and cause databases to lose information or even fail altogether! Therefore, it is important that we create a way to secure the strings passed without too much manipulation. There are many ways to do this:

PHP Code:
addslashes($string);
stripslashes($string); 
The addslashes() function adds slashes to escape quotations, apostrophes, and other special characters, which is a simple way to protect strings.

PHP Code:
mysql_real_escape_string($string); 
If you are connected to MySQL, you can use this function, which will escape a lot of stuff too as to help secure the strings. Personally, I just create a function that uses a couple of the methods:

PHP Code:
function cleanString($string){
    
htmlentities(mysql_real_escape_string($string));
    return 
$string;

As I have come to understand, htmlentities() will return a code (like the code for ♥ ) of each character, which will, when shown anywhere, show up as the text. However, it doesn't execute as malicious code when it passes through, making this another reliable way to clean the strings. This function will be used throughout the tutorial.

Handling the Sessions

A simple way that can be used to handle sessions consistantly throughout pages is to use an included file containing functions and session checks. This will cut down on coding a LOT, as you won't be rewriting over and over and over again.

handler.php
PHP Code:
<?php
    session_start
();
    
mysql_connect("localhost""[b]cpanelusername[/b]_[b]sqlusername[/b]""[b]sqlpassword[/b]");
    
mysql_select_db("[b]cpanelusername[/b]_usys");
    function 
cleanString($string){
        
htmlentities(mysql_real_escape_string($string));
        return 
$string;
    }
    if(!
$_SESSION['username'] || !$_SESSION['password']){
        
$loggedIn False;
    } else {
        
$loggedIn True;
    }
?>
This file uses a fairly simple yet effective way to check if you are logged in. Once you include this file, you can also use the $loggedIn variable to check if somebody is logged in from whatever page includes it.

The cleanString function was explained in the last section. The other part of the code uses the session variables array. The exclamation before means "not", and the double-bar means "or", so the code is basically checking: "If the username session is not set or the password session is not set, then the user is not logged in, otherwise the user is logged in".

Registering New Users
Now that we have a place to store all of the user information in a secure way, and a way to check if they have already logged in, it is time to let them register! However you want to, create a form with the following fields (with the name attribute identified as such in the parenthesis):
  • Username (username)
  • Password (password)
  • Confirm Password (cpassword)
  • Email (email)
  • Confirm Email (cemail)
Make sure the form action is set to process_registration.php, which we will now create in the same directory. Also make sure that the form method is "POST", as this is how we will work with the variables sent from the form.

The first thing we want to do is get the data sent through the form from the POST array. So the first thing we will do is start our script with this.

process_registration.php
PHP Code:
<?php
    
require_once 'handler.php';
    
$username cleanString($_POST['username']);
    
$password $_POST['password'];
    
$cpassword $_POST['cpassword'];
    
$email cleanString($_POST['email']);
    
$cemail cleanString($_POST['cemail']);
    
$errors = array();
The above code just starts the PHP script with the first line, then it make sure that the handler.php file loaded. By using the require_once() function for this, if it doesn't load then the script won't run! As well, it won't be included if you put the require_once() in there again for the same file. All of the following lines get the data from the POST array of the form, with each of the parameters from the form (which we defined with the "name" attribute!), while using our cleanString function to make sure it is an okay input. Finally, we add an array to hold all of the errors that the form encounters. Now we are going to run some checks on each of these to make sure everything is nice and spiffy before we go and add their details to our database.

First we will check to see if the username is already in use:

PHP Code:
    $sql mysql_query("SELECT * FROM users WHERE username = '$username'");
    if(
mysql_num_rows($sql) != 0){
        
$errors[] = "That username is already in use.";
    } 
That will run the MySQL query in the $sql variable, and then will check the number of entries in the database with the parameters "username = '$username'". Basically, if there is not 0 entries, the username has been used (remember that "!=" means "is not equal to"!). Now we will check the passwords to see if they match. While we are at it, we will check to see if the email addresses match, as the code is very VERY similar

PHP Code:
    if($password != $cpassword){
        
$errors[] = "Your passwords do not match.";
    }
    if(
$email != $cemail){
        
$errors[] = "Your email addresses do not match.";
    } 
The code is basically the same for all of them, but uses different pairs of variables. All each of the blocks does is check if the two variables are the same. Nothing too major here. Next we will check to see if the password is long enough.

PHP Code:
    if(strlen($password) > 16 || strlen($password) < 6){
        
$errors[] = "Your password must be between 6 and 16 characters. All characters are allowed.";
    } 
What is done here is having the script get the length of the password. If the password is longer than 16 characters or shorter than 6 characters, the user will need to go back and try again. Finally, we will check if the email address is a valid one! To do this, we will use regular expressions.

PHP Code:
    if(!preg_match("/^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}$/i"$email)){
        
$errors[] = "You need to enter a valid e-mail address.";            
    } 
I'm not going to go in-depth on regular expressions as I am not good at them, but this will check to see if the email address is valid. If you want to know more about RegEx there are many good guides online.

Now that we have gone through all of the possible errors (though you could add more if you like), we are going to either output the errors (if there are errors), or add the user to our database. First we will output errors if there are any.

PHP Code:
    if(count($errors) > 0){
        echo 
'There were some problems with submitting your registration:<br /><ul>';
        foreach(
$errors as $error){
            echo 
'<li>' $error '</li>';
        }
        echo 
'</ul>';
    } 
First, it tells the user that there were problems with the form. The "foreach" loop is a loop designed for arrays, which we use here to loop through the error array to display the errors in a list. Finally, we just end the list. Now, if there were no errors, we would be adding the user to the database.

PHP Code:
    else{
        
mysql_query("INSERT INTO [b]cpanelusername[/b]_usys.users (username, password, email) VALUES ('$username', '" md5($password) . "', '$email')");
        echo 
'You have successfully registered. You can now log in.';
    }
?> 
That makes a query to MySQL to add the username, password, and email values to the users table in our database. You may wonder why the id isn't there? Well because that is an "auto_increment" field, as it is added it will increase by one and create a unique ID for each user! This also finishes up the registration script. Time to let the users log in!

Creating the Log In

Now that we have our user registered, they need to be able to use the details they created to log in! This script is a lot more simple than the last one, so it won't be as hard to work with. Plus, most everything used in this section has been taught in the last section! That will also make this section shorter. First, we have to, of course, make a form so that our users can log in! This form needs:
  • Username (username)
  • Password (password)
Yes, just those two fields! Make sure they are named as such for simplicity in following the tutorial. Since we have a form made, point it to send the action to process_login.php, method POST.

process_login.php
PHP Code:
<?php
    
require_once 'handler.php';
    
$username cleanString($_POST['username']);
    
$password md5($_POST['password']);
This should look familiar from the last section, it is how we add in everything we need to work with. However, we use a small alteration this time around. As we get the password variable, we are going to hash it using md5, as that is how it is stored in the database. Next we will check the details against those stored in the database.
PHP Code:
    if(empty($username) || empty($password)){
        echo 
'You must enter a username and password!';
    } 
This will check for the fields to be empty. If they are, then oh no! They need to go back and fill it out!

PHP Code:
    else{
        
$sql mysql_query("SELECT * FROM users WHERE username='$username'");
        if(
mysql_num_rows($sql) < 1){
            echo 
'That username does not exist.';
        } 
That will check if the username exists by checking the table for rows with that username. If it doesn't find a single one, then that username must not exist! Now we will check their password:

PHP Code:
        else{
            
$sql2 mysql_query("SELECT * FROM users WHERE username='$username' AND password='$password'");
            if(
mysql_num_rows($sql2) < 1){
                echo 
'Your password is incorrect.';
            } 
That uses a similar manner to check for the password, however it also checks the username. The else is there because if the username is incorrect, we don't want to check a password of an invalid username! Finally, now that we have a few simple checks, we can log the user in!

PHP Code:
            else{
                
$_SESSION['username'] = $username;
                
$_SESSION['password'] = $password;
            }
        }
    }
?> 
Since we are using sessions, we will use the session array variables for username and password to store if they are logged in. This will keep the session open as long as they keep their browser open, otherwise it is likely that they can get logged out. That wraps up the login! Wow, wasn't that simple?

Logging Out

Now that the user has the ability to log in, they should be able to log out. This will probably be one of the most simple features to implement.

logout.php
PHP Code:
<?php
    
require_once 'handler.php';
    unset(
$_SESSION['username']);
    unset(
$_SESSION['password']);
    echo 
'You have successfully logged out. Thank you!';
?>
All that this script does is empty the session variables, which, as the handler would take it, send a "logged out user" signal.

Making a Page Members-Only

This is a feature that a lot of people want, because it is the main reason they make a membership system. The way the handler.php file works allows you to do this in a very simple manner.

PHP Code:
<?php
    
require_once 'handler.php';
    if(
$loggedIn == False){
        
header("Location: [b]http://yoursite.hostmatrix.org/login.php[/b]");
        die();
    }
?>
That snippet should go on the top of any page you want to be members-only. What it does is check the loggedIn variable from the handler.php file, which checks the session variables for being logged in. If it determines the user is not logged in, it will create a redirect using the header function. This allows you to change header information, and using "Location: " will allow you to redirect the page to the login page.

Note that if you want to use this, the extension on the file has to be/must be changed to .php, as .htm, .html, and similar will not read the PHP.

Closing Words

Thank you for following this tutorial. I've spent around 3 hours or so working on it, and that is with the code coming mostly from memory, so there may be typos. Also, if there are any features you aren't sure about, or want some help, just post. I am trying to come up with more sections/pages to walkthrough, or even new tutorial ideas, so if you have any ideas, please let me know!

Also, I will be submitting this tutorial to various tutorial sites (such as Pixel2Life, Tutorialized) to help boost HM traffic, so if you know of any more, feel free to let me know where else to submit it to!
__________________


korchaDev. Coming soon.

Last edited by Mike; 09-20-2009 at 04:32 PM.
Mike is offline   Reply With Quote
Old 07-31-2009, 09:52 PM   #2
meow
MEOWderator
 
meow's Avatar
 
Join Date: Oct 2004
Location: Planet Coke
Posts: 557
meow Proving their worth (Qualifies for Package 1)
nice job Mike
sigh cant rep u yet D:
__________________
xoxo, meow [ meoworks.com | tastin-hk.com ]

[ HM Rules | Hosting Format | Packages | TOS | FAQ ]
meow is offline   Reply With Quote
Old 08-01-2009, 12:46 AM   #3
Mike
 
Mike's Avatar
 
Join Date: May 2008
Posts: 482
Mike Contributing Member (Qualifies for Package 2)Mike Contributing Member (Qualifies for Package 2)
Its okay Meow it's not the rep I'm after, I wrote it to help people and help get HM some more traffic. Submitted to Good-Tutorials, Tutorialized and Pixel2Life, and waiting for a reply.
__________________


korchaDev. Coming soon.
Mike is offline   Reply With Quote
Old 08-01-2009, 01:05 AM   #4
Tim
?!?!?!?!?!?!
 
Tim's Avatar
 
Join Date: Dec 2004
Location: New Jersey, USA
Posts: 998
Tim Contributing Member (Qualifies for Package 2)Tim Contributing Member (Qualifies for Package 2)
Send a message via MSN to Tim
High-five!

On a side note, why limit the password to 16 characters? And, the htmlentities code will mess up the password length check. For example, if you type in "&lol;" as your password, this would be converted into "&amp;lol;" and be the right amount of characters, although it is not.
__________________
Tim is offline   Reply With Quote
Old 08-01-2009, 01:17 AM   #5
Mike
 
Mike's Avatar
 
Join Date: May 2008
Posts: 482
Mike Contributing Member (Qualifies for Package 2)Mike Contributing Member (Qualifies for Package 2)
Ah, I never took that into account. Plus honestly I don't need to clean that one cause it's just going to be md5'd before hitting the database. Changing now. Thanks Tim
__________________


korchaDev. Coming soon.
Mike is offline   Reply With Quote
Old 08-01-2009, 01:23 AM   #6
Tim
?!?!?!?!?!?!
 
Tim's Avatar
 
Join Date: Dec 2004
Location: New Jersey, USA
Posts: 998
Tim Contributing Member (Qualifies for Package 2)Tim Contributing Member (Qualifies for Package 2)
Send a message via MSN to Tim
Good. On another side note, the some parts of your [code] are showing literal [b]s which is probably not what you intended.

And,
PHP Code:
    $password md5(cleanString($_POST['password'])); 
-> md5()
And,
PHP Code:
          mysql_query("INSERT INTO [b]cpanelusername[/b]_usys.users (username, password, email) VALUES ('$username', md5($password), '$email')"); 
should be
PHP Code:
        mysql_query("INSERT INTO [b]cpanelusername[/b]_usys.users (username, password, email) VALUES ('$username', '" md5($password) . "', '$email')"); 
Or else it is not injection-safe (you were using mysql MD5 instead of php MD5).
__________________
Tim is offline   Reply With Quote
Old 08-01-2009, 01:25 AM   #7
Mike
 
Mike's Avatar
 
Join Date: May 2008
Posts: 482
Mike Contributing Member (Qualifies for Package 2)Mike Contributing Member (Qualifies for Package 2)
Alright, got it. Can you explain more the mysql md5 thing? Isn't it the same?
__________________


korchaDev. Coming soon.
Mike is offline   Reply With Quote
Old 08-01-2009, 01:31 AM   #8
Tim
?!?!?!?!?!?!
 
Tim's Avatar
 
Join Date: Dec 2004
Location: New Jersey, USA
Posts: 998
Tim Contributing Member (Qualifies for Package 2)Tim Contributing Member (Qualifies for Package 2)
Send a message via MSN to Tim
Well, it does the same thing with a valid string. But, if some crazy attacker wants to do an SQL inject... let me show you for example.
Your original query:
Code:
INSERT INTO cpanelusername_usys.users (username, password, email) VALUES ('$username', md5($password), '$email')
Hacker password: '); DROP TABLE users;#. Result:
Code:
INSERT INTO cpanelusername_usys.users (username, password, email) VALUES ('$username', md5(),''); DROP TABLE users;#), '$email')
In other words, we can close the MD5, end the query, and do major damage and then comment off the rest to make it valid. Whereas, if you do the PHP MD5, PHP will just MD5 the whole string and there is no threat
__________________
Tim is offline   Reply With Quote
Old 08-01-2009, 04:29 AM   #9
Mike
 
Mike's Avatar
 
Join Date: May 2008
Posts: 482
Mike Contributing Member (Qualifies for Package 2)Mike Contributing Member (Qualifies for Package 2)
Ahh I see what you mean. I actually intended to make it that way, I guess I just missed the quotes and dots. Thanks Tim, I will correct that when I get to my computer.
__________________


korchaDev. Coming soon.
Mike is offline   Reply With Quote
Old 08-01-2009, 04:30 PM   #10
flippys
 
flippys's Avatar
 
Join Date: May 2008
Location: Right here
Posts: 272
flippys Proving their worth (Qualifies for Package 1)
Good job, nice tutorial
__________________
Goodbye, may the forces of evil be confused on the way to your house.
flippys is offline   Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Cron Jobs + Php Tim PHP Tutorials 4 10-02-2009 04:58 AM
Start Here: A Beginner's Tutorial to Coding PHP Eion PHP Tutorials 3 07-17-2009 05:32 AM
Check this out - Free PHP Security Videos Arne1983 PHP 0 03-14-2009 04:16 PM
Directory Scripts List platonix PHP 1 02-28-2009 10:02 AM
PHP and MySQL subqueries RealmRPGer PHP 2 03-08-2005 10:27 AM


All times are GMT. The time now is 10:23 AM.

Latest Threads

Sponsors
"Sagecroft Tech"
Coolest Gadgets
Self Made Minds
Game Addicts
SoftSift

Useful Links
Backup Forums
The FAQ
History

 
Host Matrix Forums

Powered by vBulletin® Version 3.7.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Copyright hostmatrix.org 2004- 2008