Creating a PHP CMS – Part 7

This post is part of a series about creating a PHP CMS. Click here to start from the beginning.

Today we will be creating a very simple login system used to restrict access to the administration panel. Site security is such a large topic, I could write an entire series on security alone. We will be creating a login form to check if a user exists, and if the user does exist, it logs them in. We will not be creating a registration form, or a forgotten password form. I may cover these topics in another blog post.

If you would just like to download the finished source code, you can Click here to get it.

Creating a User

The first thing we will be doing is creating a user. To create a user, we first need a database table for storing users. Run the following SQL on your database.

CREATE TABLE users (
    id INTEGER AUTO_INCREMENT,
    username VARCHAR(30),
    password VARCHAR(41),
    PRIMARY KEY (id)
);

This creates a table for storing users, with an ID, username and password. The username can be up to 30 characters long. The password needs to be quite long, because we will be encrypting our passwords. If you are storing passwords, they should always be encrypted, instead of being stored in plain text. This is because if someone manages to get access to the database, they can see all of the passwords if they are stored in plain text.

We will be encrypting our passwords using md5 for now, but after I wrote the login system, I read that sha1 is more secure. I will be using md5 in this tutorial, but easily apply the same ideas to sha1 encryption.

Now we can create a user, using some SQL. I will call the user 'admin', and the password will be 'password'. Using this md5 Hash Generator, the md5 version of the word 'password' is

5f4dcc3b5aa765d61d8327deb882cf99

Now we will create a MySQL query to insert the user into the database.

INSERT INTO users (username, password) VALUES (
    'admin',
    'password'
);

Be sure to replace 'password' with the md5 hash of your password.

The Login Form

Create a new file in the admin directory called login.php. Paste in the following code.

<form method="post" action="">
    <p>
        <label for="name">Username: </label>
        <input type="text" name="username" />
    </p>
 
    <p>
        <label for="password">Password: </label>
        <input type="password" name="password" />
    </p>
 
    <p>
        <input type="submit" id="submit" value="Login" name="submit" />
    </p>
</form>

This is just a simple login form. The 'password' field is using the type of password so that any input is hidden. You can also see that the action attribute of the form is empty. This is because we will be validating the user on the same page.

The Login Functions

In functions.php, we will be creating a few new functions. The first one we will create is called verifyUser. In between the parentheses, add two variables, called $name and $pass. These are the arguments we will accept when calling this function. Inside the function, insert the following code.

// Escape strings
$username = mysql_real_escape_string($name);
$password = mysql_real_escape_string($pass);
 
$result = mysql_query("SELECT * FROM users WHERE username='$username' AND password='$password' LIMIT 1");
 
if (mysql_fetch_array($result)) {
    return true;
} else {
    return false;
}

First, we escape the strings. This is important because any user can get to the login form, not just administrators. Next, we select the row from the 'users' table where both the username and password given are the same as those in the database. LIMIT 1 makes sure that only one row is returned.

Next, we have an if statement. The condition is mysql_fetch_array($result). This means that if there were rows to create an array, the condition is true. If no rows were returned, it returns false. Inside the conditional block, we have return true. This means that when we call this function, if the user exists, we get 'true'. If not, we get 'false'.

The next function we will create is called validateUser. Add the variables $name and $pass in between the parentheses again. Inside the function, enter this code.

$check = verifyUser($name, md5($pass));
 
if ($check) {
    $_SESSION['status'] = 'authorized';
 
    header('location: index.php');
} else {
    return 'Please enter a correct username and password';
}

This stores the result of verifyUser in the $check variable. The arguments used are the username and an md5 hashed version of the password. For example, if the user is verified correctly, $check will have a value of 'true'. Next we have an if statement. The condition is $check, so it will continue if verifyUser returned 'true'.

We have a new variable called $_SESSIONS. This is an array used for storing session information. We are using a session called 'status', and giving it a value of 'authorized'.

Next, we call the header function. The argument is 'location: index.php'. This redirects the user to the file 'index.php' when the user has been verified.

In our else block, we simply return a helpful error message.

For the next step, go to login.php and add a PHP block at the top of the file. First, include functions.php and call the connect function. After connecting to the database, call a function called session_start(). This initializes our session data.

Next, add in this code.

if ($_POST['username'] && $_POST['password']) {
    $result = validateUser($_POST['username'], $_POST['password']);
}

This checks if the user has submitted the form by checking if $_POST['username'] and $_POST['password'] are true. Next we call the validateUser function.

Now go to login.php in your browser and enter the login information that you set. If everything went fine, you should be redirected to index.php. Now try entering incorrect login credentials. You should be back at login.php.

Now we need a function to log the user out. In functions.php, create a new function called logout. Paste in this code inside the function.

if (isset($_SESSION['status'])) {
    unset($_SESSION['status']);
 
    // Remove the cookie
    if (isset($_COOKIE[session_name()])) {
        setcookie(session_name(), '', time() - 1000);
        session_destroy();
    }
}

if (isset($_SESSION['status'])) checks if the user is logged in. If they are, then unset the $_SESSION['status'] variable. Next, we check if a cookie exists with the name of the current session. If the cookie exists, we remove it using setcookie. To remove a cookie, we set an expiration date before the current time. In this case, we set it to 1000 seconds earlier. Next, we use session_destroy(), which destroys our session data.

Now add the following code in login.php, inside the PHP block.

if ($_GET['status'] == 'logout') {
    logout();
}

This checks if the URL contains 'status=logout', and if it is, it calls the logout function. In index.php, add a link to 'login.php?status=logout'. Now try logging out and logging back in to make sure everything works.

However, we haven't restricted access to index.php. We will create a new function called checkMember to restrict access. This function will be very simple.

function checkMember() {
    session_start();
 
    if($_SESSION['status'] != 'authorized') {
        header('location: login.php');
    }
}

First we initialize the session data with session_start. Then, we check if $_SESSION['status'] is not equal to 'authorized', like we set in the validateUser function. This means that the user is not logged in. If they are not logged in, we redirect them to login.php.

In all of the files in the admin directory, except for login.php, call the checkMember function after connecting to the database. Now make sure you are logged out, and try accessing the pages in the admin directory without logging in. If everything went well, you should be redirected to login.php.

That's it for this series. If you've been following the series, you've learned how to connect to a database with PHP, create, read, update and delete pages, and how to secure pages of a site. I hope to write some blog posts expanding on these topics in the future.

Click here to download the finished source code. I've added a few more things, such as a few messages, and a method of checking if a page exists. You can check out the source code to see how I did that.

One thing that I did not discuss is styling. I've recently started trying out the CodeIgniter framework, and I am working on a simple themeing system for it in my spare time.

As always, if you have any questions about today's post, be sure to leave a comment!

Stay Updated

Did you enjoy this post? Don't miss a single post by getting free updates!

27 Comments

  1. August 25, 2009

    It's better header('location: http://fwebde.com/index.php'); than header('index.php');

  2. August 25, 2009

    I have submit a reply, but the Aksimet had blocked it. Please check, thanks!

  3. August 25, 2009

    Hua Chen: I used a relative path because it is redirecting to index.php in the admin directory. I think that a relative path helps to make it more portable across multiple sites.

    If you want to use a full URL, you could use header('location: ' . BASE_URL . '/admin/index.php');

  4. deluxe
    September 9, 2009

    Certainly not working after running discarded error:
    Warning: mysql_connect () [function.mysql-connect]: Access denied for user 'xxx' @ 'xxx' (using password: YES) in / home / free / xx.cz / p / xxxx / root / www / m / functions.php on line 8
    Could not connect. Access denied for user 'xxxx' @ 'xxxx' (using password: YES)
    .... And what should I start? ... Instructions should be cool:) Thanks

  5. September 9, 2009

    deluxe: It looks like a problem with your database connection, mainly with your MySQL user details. Make sure the username and password are correct, and also make sure your user has the correct priviliges for your database.

  6. deluxe
    September 9, 2009

    Everything I did as I was, I do not know where it can be a mistake, I checked the password, the host name and it is properly completed and everything is ok .... must have been some mistake because I tried to hosting the second and The same error .. you'll know whether only works for me is wrong? Thank you for the answer

  7. September 9, 2009

    deluxe: Try creating a new user and using that to connect to the database. Other than that, I don't know what else you could do.

  8. September 14, 2009

    Is there a reason why you chose to digest the passwords in the php code, rather than using the encryption functions in the mysql queries?

  9. September 14, 2009

    @Karl Agius: I'm not sure. The PHP method is just what I learned to do. I guess it would work using MySQL, too.

    Maybe you could use both, and get some sort of 'double encryption' thing going on for extra security.

  10. September 14, 2009

    Double encryption is more overhead and trouble than it's worth, in my opinion, better stick one way or the other. Both work fine, was just curious if there was any benefit to using one over the other. Your way would be less dependent on the db, for example.

  11. September 15, 2009

    @Karl Agius: Interesting. Maybe sometime I (or someone) should test those and see which method takes more time, more CPU usage, memory, etc.

  12. bigbanne2004
    October 6, 2009

    HI
    I couldn’t manage to login, I receive this error “Please enter a correct username and password”. I change the user and password but nothing. Can you help me?

  13. October 6, 2009

    @bigbanne2004: Make sure that you are inserting the MD5 hash of your password into the database. Delete the record from the database, and try again.

  14. bigbanne2004
    October 7, 2009

    Thank you, I change in database the word password with md5 version of this word

  15. January 9, 2010

    Good work!

    One thing to consider: even for beginners, you want to keep security in mind. I'd strongly recommend using prepared SQL statements to avoid potential risks (something like PDO [http://php.net/pdo] or MySQLi [http://php.net/mysqli]).

    Also, consider using htmlentities($user_input, ENT_QUOTES); to guard yourself against mischievous users.

    I know it's complex and might seem out of the scope of a beginner-level article, but good habits are really important to form early.

    Thanks for taking the time to put this together!

    • January 9, 2010

      Thanks for your comments. Those are some good things to remember. Security is a very important consideration.

  16. Amber
    January 14, 2010

    Hi,
    Just wanted to say thanks for the tutorial, I have been looking for a simple tutorial for a while now and being totally new to PHP i thought this was very helpful.

    Thanks :)

  17. Chris
    January 15, 2010

    Nice tutorial i have learned a lot. But i have a small problem. When i type the username and password and then login it redirects me back to the login form. Please note that i have changed the "password" with the md5 hash of this passworrd but the problem still exists. Any solutions ?

    • January 15, 2010

      Interesting problem. When you're redirected back to the login form, does it say "Please enter a correct username and password", or is it just the same as before?

      • Chris
        January 17, 2010

        the same as before. I will try to find the solutions and will post it here :)

        • January 17, 2010

          Hmm. Check out your validateUser() function, and how it's used in login.php and make sure everything is correct.

          Also, after you try logging in, try taking your browser directly to admin/index.php, as it could be a problem with redirecting.

          Also after attempting to login, check your browser's cookies, to see if the cookies are at least created.

  18. Daniel
    January 27, 2010

    Nice job. But take a look at this tutorial is written in German, but check it out.

    http://blog.stevieswebsite.de/eigenes-cms-erstellen/

    • January 27, 2010

      My knowledge of German is quite limited, but that does look like another useful, comprehensive tutorial.

Trackbacks/Pingbacks

Leave a comment