Building a content management system from scratch

A few people have asked me for links for tutorials on making a cms or have asked me to write one, so I’ve put together a tutorial on making a cms from the very beginning. The cms will be really simple all it will consist of is pages that are completely database driven that you can edit existing pages and create new pages.

To get a better idea of what I’m taking about have a look at the demo to login to the admin you’ll need the following details:

Username: admin
Password: admin

To access the admin section go to http://www.daveismyname.com/simple-cms/admin

Download Files

Before I do anything I like to put the structure together the following image shows all the files and folders. Notice the image folder is empty, to keep things simple I’ve not included any images as you’ll be using your own images anyway. Also setup.php is not part of the system but a file containing the MySQL tables and sample data to get you started, simply copy and paste the code into your database using a database management tool such as phpmyadmin.

Once I’ve set the structure it’s time to create the config file every page calls this file so it makes sense to create this first.

includes/config.php

First I turn on output buffering to enable the use of headers anywhere on the page and turn on sessions then provide the database connection details along with a connection, I use the error suppressor @ when connecting to the database then provide a custom error message in the event the connection attempt fails.

Next I create some constants that will be used throughout the cms, DIR points to the address of the cms and DIRADMIN points to the admin part of the cms. I’ve also created a constant called included as a security measure so I can restrict access to files directly. You’ll see this in action at the top of functions.php in a moment. Lastly I include functions.php as again this file will be needed throughout the project.

includes/functions.php

The first thing I do in this file is make sure it’s been included otherwise throw an error by checking if the constant from includes/config.php has been defined.

Then I list all the functions the cms will use, namely:

login = logs the user in
logged_in = returns true of false if logged in or not
login_required = checks if logged in if not redirects to login page
logout = logs the user out
messages = show any notifications
errors = shows any errors

login requires 2 parameters, username and password, if then strips any tags and make them safe for database interaction using strip tags followed by mysql_real_escape_string. I encrypt passwords using an algorithm called md5 this is a one-way encryption.

Then the function checks the username and password in the members table if there is a match then set a session which can be used for other functions to check if a user is logged in.

If there wasn’t a match then show an error message.

logged_in simply checks if the session authorized is equal to true, if so return true otherwise return false

login_required checks the outcome of logged_in (true or false) and if logged in returns true otherwise redirects user to login

logout simply unsets the session and redirects the user

messages shows any messages stored in a session, once show clears the session

errors loops through all errors passed to it from an array and shows them to the user

index.php

This file controls everything on the front-end of the website. First include the config file then start the normal html for the title tag in the header of the html call the SITETITLE constant, then include the css file. I always use full paths so I include the DIR constant which stores the sites path then I can adjust the path as I need to. The great thing about doing things this way if I move the site I only need to update the config file.

For the navigation I manually place the home link ad this will always be first and always be present, then loop through all pages in the pages table that has a value of isRoot equal to 1 meaning it’s not the home page and loop through all the records and create links for each page:

For the pages content first check if a super global GET called p has been set if it has then a page has been requested in which case take the requested id and query the database with it and pull back the required page content, otherwise pull the record that has an pageID of 1. Next create an object of the result and print the page’s content.

In it’s simplest for that’s all there is to the front end of the CMS, I told you it was very basic :) in the footer I’ve opted to put the site’s title by using the constant SITETITLE and give the current year using the date function.

So that’s the front end revealed now it’s time to build the back-end to allow you to login and make changes.

admin/login.php

This page has it’s own page markup so I can give it a different look to everywhere else, at the top of the file include the config as usual and then check if the user is already logged in, if they are redirect them

To login there needs to be a form for the user to fill out, the form only needs two fields the username and password. Above the form call the messages function to show any messages such as a failed login attempt.

If the form has been submitted then send the username and password to the login function:

admin/index.php

This page will lists all pages, allowing you to edit or delete as well as add new pages. Normally a cms admin panel would have far more options but I’ve chosen to have pages and nothing else to keep it as simple as possible.

Start off by including the config file and then forcing the user to login by calling the function login_required() if the user is not logged in they will b redirect to the login page, next check if a request to log out has been called and calling the logout function if needed.

Another important step check if a request to delete a page has been issued by checking if $_GET['delpage'] has been set if it has then process the pageID and delete the page set a message session then reload the page. Deleting a page will only happen when a javascript call has been made and a popup confirmation appears and yes is clicked on.

Next list the normal html, title, css files etc inside the head tags we need to place a javascript function to delete a page it will accept two parameters the pageID and title, the function when called create a popup conformation box with two options yes or no is yes is clicked then the window.location.href is activated. if no is clicked the box closes and nothing happens.

For the navigation I have three static links, a link for the main admin, a link to view the front-end and logout, notice the path for logout is the siteadmin path followed by ?logout this is used to call the logout function.

Next create a table that will list all pages from the pages table, notice we’re checking the pageID for a ’1′ if found remove the delete link to make sure you can’t delete the home page by mistake (it does happen). The edit link uses the DIRADMIN constant followed by editpage.php?id the next bit passes the pageID to the link which will be used when editing a page so the link know’s which page you’re requesting.

The delete link uses a javascript call to call the javascript function we call earlier it requires the page id and title.

After the form I’ve set a link to create new pages

admin/addpage.php

This page is used to create a new page, it’s very simple there’s a form that needs a title and the content you’re would like, the content textarea is a plain box so any html markup will need to be entered there, to make life easier it’s recommended to use an editor my editor of choice is tinyMCE http://tinymce.moxiecode.com it’s simple to use and very powerful, for the sake of simplicity I’ve not used an editor in the tutorial but including tinyMCE is just a case of including the files and placing a piece of javascript in the header of the file.

Here’s the form I’ll be using notice the title input has a name of pageTitle this is important as the name will become a php variable so the data can be captured when submitted and put into the database, the same goes for pageCont.

Processing the form is very simple check if the form has been submitted and if it has then get the data from the form, make it safe for database entry then using mysql_query insert a new record in the database. Finally add a message to a session and redirect to the main admin page.

admin/editpage.php

This page is very similar to the add page, with a few additions the first of which is a check to make sure a pageID has been passed to this page if not redirect the user

To update the content we’ll need a form with the pages content there for us to edit to do this we query the database and pass the requested page id and create an object to we can then fill the form with the values from the database.

Processing the updated form is almost the same as adding a new one the only difference is there’s a hidden input in the form called pageID which is the id of the page and the mysql_query instead of inserting data it will update it so we need to update accordingly:

That’s all the files for the cms it’s very simple but will give you a starting point on making your own cms, there are many things that can be improved upon, for clarity here’s all the files listed, there are also avalible to Download Files.

includes/config.php

includes/functions.php

admin/login.php

admin/index.php

admin/addpage.php

admin/editpage.php

index.php

setup.php

I hope you’ve found this tutorial useful any comments, suggestions are always welcomed.

 

  • http://twitter.com/rpdtweet Richard Dickinson

    Hi Dave
    Many thanks for this interesting post & demo.
    I haven’t actually tried (used) your code yet but
    I appreciate your effort with it and thanks for making a zip file available
    (if after trying your code I get stuck, I’ll let you know!). Best wishes :-)

  • ANUPAM CHAKRABARTI

    its no point of wasting time on this article if the sql database and table codes are not included.pls send a link for downloading the sql codes.

    • http://www.daveismyname.com David Carr

      They are included there all in setup.php

  • Ian

    Hi,

    I cannot login to the admin area.

    I downloaded the zip file from github yesterday 3/31/13 and I am getting notices when I try to login to the admin area

    Notice: Undefined index: authorized in X:xampphtdocssimple-cmsincludesfunctions.php on line 43
    Notice: Undefined index: submit in X:xampphtdocssimple-cmsadminlogin.php on line 26
    Notice: Undefined index: success in X:xampphtdocssimple-cmsincludesfunctions.php on line 68

    I am using the user id and password I created for the database (includesconfig.php lines 15 and 16.)

    thanks

    • http://www.daveismyname.com David Carr

      I’ve just tried the login is working fine, or do you mean your local copy?

      apologies about the notices I always turn them off, in your config file add:

      error_reporting(E_ALL ^ E_NOTICE);

      to when adding another user account make sure the password is hashed with md5 its worth mentioning this is an old tutorial and md5 cannot be relied on for secure password any more its too easy to break.

      • Ian

        Thanks David, that got rid of the errors.

        Yes, I am using a local copy on xampp but I still cannot log in. Should there be another log in id beside the dbuser/dbpass ?

        As this is an old tutorial and not secure, do you have a newer more secure version?

        Having looked all over the net, this has been the best I have found.

        thanks
        Ian

        • http://www.daveismyname.com David Carr

          the dbuser and dbpass is for the database username and password you’ll need those to connect to the database, the admin areas login is an account login the default should be admin for both username and password,

          I don’t have a newer one sorry I will look into writing one though for now use md5 just so you can see it working then you can change the hashing later.

          • Ian

            Thanks David, all working fine now. Time to get into learning PHP.
            appreciate your help and quick response.

            Ian

          • http://www.daveismyname.com David Carr

            your welcome, if your on facebook I’m part of a group that help others learn php worth joining https://www.facebook.com/groups/pdvlin/

          • Ian

            thank you for the invite. See you there.

  • http://twitter.com/sungsoonz SEONG

    Hi David,

    I truly appreciate your effort put into this tutorial.
    Code is clean, simple and your instructions are easy to follow.

    One thing I didn’t quite understand was this line “super global GET called p has been set if it has then a page has been requested”.

    You must be referring it to this $_GET['p'] but where did ‘p’ come from?
    Are you referring it to paragraph html tag? If then, I don’t see what it’s got to do with page request…Can you please explain this?

    Again, great tutorial, thank you so much.

    • http://www.daveismyname.com David Carr

      thanks Seong,

      the p comes from the page link when you create a link such as index.php?p=2

      the p becomes a variable using a GET request any word after ?= can become a variable with its value assigned in the =

      so to use the p you would use $_GET['p']

      hope this has been clear if not please let me know and I’ll try to explain it more.

      • http://twitter.com/sungsoonz Seong Lee

        I see where it’s coming from now. Thank you so much.

  • http://www.facebook.com/gshelvankar Geeky Gaj

    Thanks for the tutorial David,

    I tried using the password ’21232f297a57a5a743894a0e4a801fc3′ as mentioned in the tut, but the login.php throws an error: Sorry, wrong username or password. I changed the password in MySQL to ‘admin’ and then back to the default one again but it didnt work either.

    Just starting to learn to incorporate PHP in my HTML5 websites so kind of fresh off the block here.

    Cheers.

    • http://www.daveismyname.com David Carr

      that’s the MD5 version in the login form you would use admin that’s MD5′d to become the above string, if you want to change the password make sure you either use MD5 in PHP like this:

      $pass = md5($pass);

      or in phpmyadmin in the function column select MD5