Trang chủ‎ > ‎IT‎ > ‎WEB PROGRAMMING‎ > ‎04 - PHP‎ > ‎

Tutorial - Creating A Simple Dynamic Website With PHP

If you have your own static website, you may be getting sick of updating every single page when something in your header changes, a logo, a menu item, or even a single character - just to name a few examples.

This simple tutorial is going to help you step away from the perils of having to do this for every minor change, and leaving you just having to update a single file to affect many different (if not every!) page on your website.

Now let me say that there are a lot of tutorials like this on the internet already, but some of them will only take you to a very basic point and then stop. This one won't, I'm going to, after showing you the very basics, how to make your system much more advanced and dynamic like a real website is. There's no point only learning a bit, if you're essentially just going to have another static website.

So to expand, this is what we will be learning, in order of "difficulty":
  • How to create a dynamic website with header/footer
  • How to make your links prettier + friendlier (With Apache/IIS7)
  • How to make your menu dynamic (Coming soon!)
  • How to secure your system further (Coming soon!)
  • How to make your title dynamic (Coming soon!)
  • If you need more control, how to make your system into a minimal implementation of a 'VC' (MVC without the M) architecture (Coming soon!)

That's quite a lot if you ask me, so now to get started..

How to create a dynamic website with header/footer

Starting out with the very basic stuff, what we're going to accomplish here is splitting our website pages up from 1 file (for now let's use/call it index.htm) into 3 files. This file is going to become header.htmindex.htm (of course with amended contents) and footer.htm.

The first thing you need to do is identify, from the contents of index.htm, which part of your page is the header, which part is the content, and which part is the footer. This shouldn't be too bad as most sites generally have code like this (simplified):
02 <head>
03     <title>My cool website</title>
04 </head>
05 <body>
06     <div id="header">
07         <img src="logo.png" alt="Cool Website Logo" />
08     </div>
09     <div id="content">
10         <p>Awesome content goes here</p>
11     </div>
12     <div id="footer">
13         <p>Copyright 2011 Cool Site.</p>
14     </div>
15 </body>
16 </html>

If it is, congratulations your site is written in a beautiful way and it should be fairly obvious how to split it up, your header file (header.htm) should contain everything from the top down to (and including) <div id="content">. In the same light, everything underneath (not including) <p>Awesome content goes here</p> should go into footer.htm. Finally, the single line <p>Awesome content goes here</p> will hang around in index.htm.

Now the final thing you need to do once you have those pages is move them into a folder you're going to create called templates.

Once they're in templates, you're done with the splitting, and should simply repeat the process for the rest of your pages. Remember, all you need in the files is the content, you don't need to put the header/footer in there any more, so all you'll need to do is delete contents from the other files.

The Dynamic (PHP) Bit
What we're trying to accomplish here is very simple, we're basically going to include the 3 files in order, first the header, then the content, then the footer. It's simple, and can be achieved with code such as the following:

It's the simplest thing on earth, and even without any PHP knowledge you would be able to figure out exactly what it's doing. So okay, let's go ahead and place that code in a file called index.php, in the web root.

Now, when you go to your website's address, you should see your homepage exactly as it was before we made these changes. If you do, that's great, and we're making good progress!

Now comes the good stuff, we of course need to make that dynamic now, so we're going to first discuss how we're going to do that.. Firstly, the parameter that makes our site show a different page is going to be called action, this is a GET parameter, which means that it's going to be passed through the URL. So when you visit your site, instead of going to, for example, http://site/about.htm, you will now to go to http://site/?action=about. Don't worry if that looks "worse", I've included a section to clean these up later on, you can even make them the exact same if you wanted to.

So, first of all we need to grab the GET parameter into our code, so, underneath our line that includes the header template, add the following:
1$action $_GET['action'];

We now have the variable $action available for use to load our template page. But there's a problem, this is untrusted data from the user, if we were to simply go along now and do something such as include("templates/" . $action), we would be in big trouble. See, the user could visit a URL like this: http://site/?action=..../../etc/passwd, and download your password file (on a *nix system).

What we first need to do is sanitise this data. PHP has a function called basename, which we're going to use to ensure any malicious user can't change directory no matter how hard he tried. So, underneath where you're defining $action, add the following:
1$action basename($action);

Basically, what basename is going to do is take, well, the base name of the path. This essentially translates to the filename, without any leading directory, which is exactly what we want!

So, now that we have a sanitised action name to include, let's go ahead and do it. Change index in your code (from templates/index.htm) to be $action, and we're done! Your code should now look a little something like this:
4$action $_GET['action'];
5$action basename($action);

So let's try it out, visit http://site/?action=index, and you should see your homepage again. Now try going to http://site/?action=about (provided you have an about.htm in templates/, otherwise something else), you should see your about page!

If you do, that's perfect, if not, you've done something wrong along the way, so read back over it and see if you can figure it out.

What if there's no ?action=

People visiting your website are not going to know that they need to use ?action=index to view your homepage, so we need to cater for people who visit without a GET parameter. This will be our default case, and by default we will be showing your home page, index.htm.

So, back to your code, you will notice that we don't check if $_GET['action'] exists before we use it, so let's do that using PHP's empty function, which will check if a variable doesn't exist, or if it's empty.

Change your code to this:
04if (!empty($_GET['action'])) {
05    $action $_GET['action']; 
06    $action basename($action); 
07    include("templates/$action.htm"); 

empty() will return true if $_GET['action'] is empty or non-existant, so our dynamic code will only be ran if it does exist, as we're using ! to flip false to true, and vice versa. The code within if ([expression]) is only ran if [expression] evaluates to true, which, based on that code above, will happen when ?action is passed across.

So now that we're only running our code when there is a parameter present, we need to write some code that's going to be ran when it's not present. We will do this in the else block of the if statement, like so:
04if (!empty($_GET['action'])) { 
05    $action $_GET['action'];  
06    $action basename($action);  
07    include("templates/$action.htm");  
08else {
09    include("templates/index.htm");

So now what's happening is that, when there is no ?action sent over in the URL, we will include templates/index.htm, simple! When they do pass over ?action=something, then it will run out first set of code, just as we'd expect. Try that out now by first visiting http://site/, and then http://site/?action=about!

Once again, if everything's working, let's continue on...


Now then, assuming your website doesn't have a page named furballs, visiting this URL is going to cause a nasty surprise to the user as it will throw an error saying files cannot be found.

This is because, according to your code, anything that's passed over should be loaded, so visiting this URL will attempt to load templates/furballs.htm!

We obviously don't want that, so we need to check if the file exists first, we can do this using the aptly named <a href="">file_exists</a> function provided by PHP. All we need to do is pass it a filename, and it will return a boolean value based on whether it exists or not!

So we're now going to amend our code to trick it into using the default if the file doesn't exists. Add an if statement as below, that will amend $action to have the value index when the file doesn't exist:
04if (!empty($_GET['action'])) {
05    $action $_GET['action'];
06    $action basename($action);
07    if (!file_exists("templates/$action.htm")
08        $action "index";
09    include("templates/$action.htm");
10else {
11    include("templates/index.htm");

Yippee! Try visiting http://site/?action=furballs, and you should get to your homepage, if you do, move on!

http://site/?action=header and http://site/?action=footer[

Argh! What happens if we go to these URLs, we'll either get the header or footer on our page twice, that's not good, so we're going add another if () statement to our code that will once again redirect users to the default page if they visit the above.
04if (!empty($_GET['action'])) { 
05    $action $_GET['action']; 
06    $action basename($action); 
07    if (!file_exists("templates/$action.htm")) 
08        $action "index"
09    if ($action == 'header' || $action == 'footer')
10        $action "index";
11    include("templates/$action.htm"); 
13    include("templates/index.htm"); 

Once again, try out your new code! Simply visit http://site/?action=footer and http://site/?action=header, and you should get the same as when you visit http://site/ on it's own!

Tidying it all up
That's it, we've done everything that we need to, but the code just got longer and longer, so we're going to look at how to tidy it up now. Basically what we'll do is add a default value for $action, and always use the dynamic code. The only time that $action is set is when the $_GET parameter meets certain conditions.

Rather than explain it here, I'll just update the code to contain the changes, and comment it to so that you can see what's going on clearly...
04// Set the default name
05$action 'index';
06// Specify some disallowed paths
07$disallowed_paths array('header''footer');
08if (!empty($_GET['action'])) {
09    $tmp_action basename($_GET['action']);
10    // If it's not a disallowed path, and if the file exists, update $action