Creating Your Own CMS Part 1 – Secure Login

Have you ever built a site to realize it is a pain to manage? There are a lot of CMS options out there but some of them cost money, some are hard to learn, some your hosting company might not support, and well sometimes they just don’t have everything thing that you want. So today I am going to start to teach you how to create your own simple CMS. Today I will get into how you can find a design and get your secure login setup. This will be a series of blogs but to be honest I am not sure how advanced I will be going. If I wanted to spill it all and tell you how to build the CMS that my company uses then it might take a few blogs.

Design of Your Own CMS

This may or may not be important to you. But when it comes down to it you will most likely be much more proud of your CMS with a nice design and design is where the usability starts. I could programming some amazing things but without a design I am limiting myself and wasting a lot of time. I have created a few CMS’s from scratch but I found out that when you give me a design for a CMS it not only comes out a lot neater but I can produce it much faster.

Here is the one that I chose as well as a few others to browse through.

I am creating this CMS as I type this so you guys are looking at it first hand. That is also the main reason I am not sure how many advanced parts we will have but I am willing to take requests while I work.

A Few Things To Have Before You Begin the Login

If you haven’t already setup the database then you can refer to one of my recent posts “Getting Started With MySQL DB and PHP with PHPMyAdmin”. Along with the database it is nice to have a database class file and a database connection file. These are two files that you will be using on each project you do so it is nice to have them on hand. The db.php can just go in the htdocs/ and the db.class.php should go in the htdocs/classes/ folder.

People do their file structure differently but for me I have an Ubuntu server with each site in the home folder like: /home/
Within the htdocs/ we will want a few different folders as well.

  • admin/
    • classes/
    • css/
    • images/
    • includes/
    • lib/
    • markitup/
  • cache/
  • classes/
  • css/
  • images/
  • includes/
  • lib/

Most of this layout is pretty self-explanatory. You would have your index and other content files in the htdocs/ and in the htdocs/admin/ would be all of you admin content. Then the rest of the folders are all labeled for exactly what should be going in them. The cache/ folder can be used for several different items depending on the type of website that we are building.

Obviously this is not required nor any sort of standard this is just how I like to layout my sites file system to try to keep things neat.
Here the folder “markitup” contains a jquery markup editor which I actually haven’t used until now. I usually use ckeditor for a full featured easy to use editor.

Secure Login Code

With a secure login we will want to use sessions. You can get into more advanced parts with heavier use in cookies also but for now I am just going to show you a very basic secure login with a timeout on it. First though we need to make sure that when people try to go anywhere on our site that they will get sent to the login if they are not already logged in. Se we should put this in the header.php because that is included on every page in the admin, and we can do it like this.

<!--?php         if(!$_SESSION['llafl_admin'])         { 		$_SESSION['REQUEST_URI'] = $_SERVER['REQUEST_URI']; //store the page they were trying to access 		header('Location: /admin/login.php'); 		exit; 	} ?-->

You can see here I am checking for a session variable which I have named ‘llafl_admin’. It is best to have a distinct session because if not then you run the chance of some other site having the same session variable. Like if we just made the variable ‘admin’, it is so generic it could be anywhere. So since we have a check like this that means that when someone is logged in then they should have a session variable ‘llafl_admin’, which we will do like this.

<!--?php <br ?-->	if($_SESSION['failed']=='yes')
		echo '</pre>
<div id="fail" class="info_div"><span class="ico_cancel">Incorrect username or password!</span></div>
'; // display failed login if need be
<form id="loginform" action="/admin/login.php/" method="post" name="loginform"><label><strong>Username</strong></label><input id="user_login" class="input" type="text" name="username" size="28" />

 <label><strong>Password</strong></label><input id="user_pass" class="input" type="password" name="password" size="28" />

 <strong>Remember Me</strong><input id="remember" class="input noborder" type="checkbox" name="remember" />

 <input id="save" class="submit" type="submit" value="Log In" /></form>

That is a a basic login form and below is the code to handle when it is submitted.

<!--?php 	if($_POST) 	{ 		if(!$_POST['username'] || !$_POST['password']) 			$_SESSION['failed']='yes'; 		else 		{ 			$username = stripslashes($_POST['username']); 			$password = md5($_POST['password']); 			$u_q = $db--->query("SELECT * FROM users WHERE username='$username' AND password='$password' LIMIT 1");
			$u = $db->fetch_assoc($u_q);
				$_SESSION['llafl_admin'] = $u['access_level'];
				$_SESSION['started'] = time();
				foreach($u as $key => $value)
					$_SESSION[$key] = stripslashes($value);
				$last_login = date('c',time());
				$db->query("UPDATE users SET last_login='$last_login' WHERE id='".$_SESSION['id']."' LIMIT 1");  // on successful login update users last login
				header('Location: '.$_SESSION['REQUEST_URI']); //if they successfully log in then send them to the url they requested which is something I have set in the header
				$_SESSION['failed']='yes'; // if they failed to login this will set a session var that will trigger an error message

You can see here this script checks to make sure that both inputs were indeed submitted and if they were then it goes on to check to see if they are in fact part of a legit login. Then if it is successful then the appropriate session variable are set. (You notice we do a stripslashes to sanitize the username and md5 will sanitize the password and make sure that it is not stored human readable in case the database were to be compromised.) And if not then a session variable for ‘failed’ will be set and when the login form reloads it will trigger an error message. There are many more security levels that you can add onto this but this is a very basic and secure login that will work for our purposes.

If you are confused by any of the database aspects then refer back to this post.

Other parts of the tutorial:

Brad Billman

I am a web developer by trade but originally went to school for Information Technology - Network Engineering Technology at Purdue University. Getting into web development as a student web developer I developed a passion for it that left networking seem a bit boring. Even though I finished up my networking degree I stuck with web development lately I have been a WP7 advocate. My Blog.

15 Smart Tools To Help You Build Your Freelance Business

Discover the awesome tools we use in making our clients comfortable and happy in learning new things every day.

Download Now


  1. says

    Would someone with no programming background be able to program like that? While I really want the control that I can get from a custom CMS, I doubt I can learn how top code so soon. I guess all I can do is to find a freelancer to do the programming for me.

    • says

      Hello Matt, really it depends from your own budget and time. If you have time and interest to learn that, it is worth the time, basic knowledge before hiring anybody is always helpful!

      But if you have some money and you want to look to the bigger picture, then definitely you should focus on your core business, then spending time doing everything yourself.

  2. Donny says

    if you could put a zip with the files I modify and then to my taste.


  3. snake says

    first of all congratulations for this post, this worked very well.

    but I have a question where is all this code?

    query(“SELECT * FROM users WHERE username=’$username’ AND password=’$password’ LIMIT 1″);
    $u = $db->fetch_assoc($u_q);
    $_SESSION['llafl_admin'] = $u['access_level'];
    $_SESSION['started'] = time();
    foreach($u as $key => $value)
    $_SESSION[$key] = stripslashes($value);
    $last_login = date(‘c’,time());
    $db->query(“UPDATE users SET last_login=’$last_login’ WHERE id='”.$_SESSION['id'].”‘ LIMIT 1″); // on successful login update users last login
    header(‘Location: ‘.$_SESSION['REQUEST_URI']); //if they successfully log in then send them to the url they requested which is something I have set in the header
    $_SESSION['failed']=’yes'; // if they failed to login this will set a session var that will trigger an error message

    is that I’m Spanish and I’m doing with a translator and some things do not quite understand.

    Sorry for the inconvenience

  4. Muslin says

    that’s a great tutor, just subscribe it for my own college reference. i’m in informatic system degre right now and want to mastering about php.

    may i copy this?

    • says

      Horrible code here. You shouldn’t do it this way because of sql injection. All I need to do is send a specially crafted username and I can execute sql on your mysql service.

      Here is your bad code.

      $username = stripslashes($_POST['username']);
      $password = md5($_POST['password']);

      $u_q = $db->query(“SELECT * FROM users WHERE username=’$username’ AND password=’$password’ LIMIT 1″);

      All I need to do is put in this for my username:
      ‘; DROP TABLE users; —

      This will delete your users table and break your website.

      The server will make the $db->query string look like this:
      “SELECT * FROM users WHERE username=”; DROP TABLE users; –‘ AND password=’$password’ LIMIT 1″

      The — tells the mysql server to ignore the rest of the sql statement. This stop errors from happening.

      • says

        Well, yes. But in defense of Brad Billman, there are certain methodologies that allows you to make things work first before applying security. Especially in cases where a prototype is needed for a presentation. I think this is applicable in coding too, what Hemingway said: “Write drunk; edit sober.”

      • Brad says

        Yeah if you read the comments you will see I corrected my mistype. I can’t actually edit the post not being a WP admin. And good job for making sure to reinforce the point that SQL injection is an easy and catastrophic way to take down a site that is not properly secured. Good post!

        • Andrew says

          And let’s not forget at a good security measure would be to create a special MySQL user for the application itself without high-level permissions to ‘drop tables’. When I build applications, I only allow the application to ‘select’. If it must ‘insert’ or ‘update’, I have it use a different MySQL username to remove as much surface area of the application. Like Rean said, tutorials are meant to guide you, not build the application for you. If you are building an application that must be very secure, it is YOUR responsibility as the developer to know how to implement it, learn whatever it takes or hire a specialist.

  5. Oskar says

    I get this message:

    Notice: Undefined variable: _SESSION in C:\xampp\htdocs\admin\login.php on line 5

  6. says

    I can certainly see the benefits of creating your own CMS. We use our own, but there are always things that need updating, and I do sometimes think we’re just playing catchup to the open source CMS’s that already have these features in place. But you will never know everything about an open source CMS, you certainly will about your own!
    I guess it depends on how much time you have!
    Great post though.
    Thanks Brad

  7. M says

    I think building your own CMS is not a good idea – for both: the client and yourself. Why should you do the work, which is already done? Why spent time in creating a very simple cms instead of learning a well built open source CMS? What about all the nice features (e.g. news, sitemap,…) you would have to build by your own?

    My suggestion is to start learning an open source CMS like TYPO3, WordPress,… and contribute the time you save to the community :)

    • Brad Billman says

      Well M. Building your own CMS is not only a great learning experience but if you are making your own sites you would have no limits to your features like if you use other’s code. Also, if you care to get a job doing web development you will often find that you have to work with CMS code that was built by someone else so it is great to have a good understanding of the inter-workings. And last but not least, why do you care about why someone else wants to build a CMS? If you want to use other people’s work then do it and stop trying to knock anyone else.

      • platnm says

        I agree. I learned how to develop web sites back in elementary school and as I got older I never kept up with the new technology. So now, CMS Systems like Joomla, Drupal, and WordPress make me feel like I can’t customize my website the way I want. Not all websites that are made are very complicated. Sometimes you just need a simple way for your customer to edit certain areas of their website. I could learn how each of the CMS codes work, but then I wouldn’t really learn much. I think by doing this I can further expand and learn about the actual code.

  8. Oliver says

    Argh! This is not a good tutorial.


    This is a bad idea. If you use a recent of php it’s not a big thing, but if you use older version, you may run into deep trouble as someone with manipulated input, that may send cookies.

    $username = stripslashes($_POST['username']);

    Very very bad idea. Have you ever heard about SQL Injections?

    $password = md5($_POST['password']);

    Bad idea! Use the email of the user and your own salt to block rainbow table attacks and to prevent attacks against your database, if it is leaked anyway. Maybe something like this sha($_POST['password'].$_POST['email'].YOUROWNSALT) is much much better.

    $u_q = $db->query("SELECT * FROM users WHERE username='$username' AND password='$password' LIMIT 1");

    Bad idea! Use Select … where username …. and check if the password is the password from user input.

    • Brad Billman says

      Love the excitement and thank you for letting me know this is a bad tutorial but plain and simple. This is not a tutorial for building a CMS to a bank. This is for beginners and by your suggestions, I can assume you have done some PHP. And a note for you. If you have any real input on the subject then instead of trying to knock people to make yourself feel better, instead add to it or suggest otherthings. Obviously any decent PHP developer knows that md5 is the best solution and/or that you can add salt to make it more secure but this tutorial is for BEGINNERS. Ok then have a good one.

      • jim says

        You are teaching beginners horrible coding practices. I would suggest deleting this article. Use salts and prepared statements. Dont teach beginners bad practices! They pass it on like you just did.

  9. Rahul says

    very complicated haha
    i was not that good dealing with these things , but i have recently developed my skills in this field now i could understand and make some tricks which make me feel better, still as you said , it is a pain to manage !! :)
    Thank You

  10. Brad Billman says

    Thanks for all the input and opinions. There is a session_start() I realize I did not make it clear that it is with the db stuff I referred to. The session_start would be the least of the worries if the db.php didn’t exist because you would get errors from that obviously.

    Yes there are definitely different things that you can do to make the passwords more secure but that isn’t exactly the point of this.

    If someone had a small content site or even blog site creating a small CMS like this is great practice, gives a better understanding of PHP and CMS inner workings, and gives you more flexibility than something like Drupal because it can be implemented on the front end however you like.

    As far as the kernel and yada yada I don’t know what you are getting at for a beginners CMS sorry.

    And seriously about frameworks. Why would you want someone to learn a PHP framework before learning PHP?

  11. Brad Billman says

    The $username = stripslashes($_POST['username']); should be replaced with
    $username = $db->escape($_POST['username']);

    Sorry for that typo

    You always escape when inserting to the database and stripslashes when you are pulling from the database.

  12. Gregory says

    Maybe this is not the purpose of the post,
    bu if you will leave the line:
    $username = stripslashes($_POST['username']);
    you will be cracked very soon. Try to replace the line with some “prepare” statement, or escape the login with functions like mysql_real_escape_string.
    Security is very important issue, especially in CMS systems.

  13. Vinicius Camara says

    Great your code and explanations.
    Do you think about write a book?
    Perfect content for that.
    Good lucky!

  14. Cosmin Negoita says

    Nice and I appreciate your effort, but seriously, you could cover more in one article…

  15. Ignas says


    Are you really want to start building CMS from the secure login? You need to define firstly how the modules will work together, design the kernel, design libs, template engine usage. At least to start using logins you need to have the user accounts with the roles and then use this users database to let people login in the admin side or not. So you will have user system in hand together.

    Of course this is good that you showing for the beginners the ways how to build the secure login, but to start series about the CMS with the topic like this… Don’t think this is good idea. But it is just my opinion, so good luck and will see what’s next :)

  16. Dylan says

    Session variables are unique to a site, since they are referenced by a value stored in cookies. The only session variable name collision you need to worry about is collision with other session variables from the same domain name.

    You should check the length of the submitted username and password, not just the value. If the username or password is the number zero, that if() condition will falsely fail.

    You should only stripslashes if slashes were added. You can tell if they’ve been added with get_magic_quotes_gpc(). You should also strip slashes from the password before md5()ing it – some users have quotes in their password.

    You should also escape the username to make it safe for database queries.

    You shouldn’t need to stripslashes() content out of the database. It shouldn’t have extraneous slashes in it to begin with.

  17. says

    First, this code will not likely to work, as one needs session_start() somewhere :)

    There are NO motives to create a fresh new CMS for newbie, that can not code login access themselves. If you can’t use CMS, use framework that provides adequate code structure and lots of useful stuff ( code igniter, cakephp, symphony comes in mind). Using own CMS means that you will have to re-do things that are created, coded (often) better and are freely available. Also, it is a headache if someone else is hired to modify your code. Many of bigger companies will refuse to work with freelancers that work on their own CMS’es. I would do that too now.

    Second, excuses that CMS’es are costly or do not do something so one needs to create new one are poor ones. As a former programmer I can tell that I would never hire a programmer that tells such things myself, though being guilty on very same things in the past. I have an excuse that it was 2006 or so. What is yours? :)

    There are 2 good reasons to create CMS (and only based on some framework): FUN and requirements for performance for processing specific, complex data. In last case one can code specific parts better.

    My suggestion would be mastering at least 1 or 2 CMS’es instead of focusing on creating one :)

  18. says

    store passwords with md5 is ok but some users choose passwords like ‘abc’ or ‘qwerty’ or something similar poor.
    The md5 hash gets much more “readable”.

    I always join a seed within the encryption:

    $seed = ‘Somethingwithweirdchars';
    $password = md5($_POST['password'].$seed);

    • Brad Billman says

      Users are not even going to be entering user/pass anyway it is your CMS you can control all of that. But yes salting is good.

  19. says

    Nice, I think everyone needs to understand coding this way before progressing to MVC and/or a framework which I’m sure you’ll agree saves a huge amount of work in the long run.