Programming your own PHP framework, Part 1

building your own framework

The below article was authored by Terry Smith. Terry is an aspiring entrepreneur and PHP code ninja working for b5media. He spends his “weekends” and “free time” working on all sorts of crazy ideas and one day wants to rule the world (or a small part of it)! This is first part of the tutorial post. Second part can be found here.

I’ve always been torn about posting code on this site, since I’ve historically (if I can use that word) wanted to keep it about business ideas.  However, since I’ve started working for b5media, I’ve had a lot less time to work on my own projects; therefore I think I’ll start talking about some code.

These posts are geared towards people who know programming (specifically to people who code in PHP, but if you can read the code, you can port it to most other languages).

As with most engineers, I like to re-create tools I use on a regular basis.  Some I’ve tried and failed at for various reasons (3D game engine), but one of the ones I’ve always wanted to try is a PHP framework of my own.  So last weekend, I sat down and wrote a basic framework that I would enjoy using.  This series of articles will talik about how I did that.  So, without further ado:

There are several components of a web framework: URL rewriting, database abstraction, an MVC framework, a templating system and plug-ins.  All of these are optional and you can pick and choose which you want to include in your framework and how you want to include them.

In this first article, I will cover URL rewriting.

The most important thing here is to remember that you can style your URLs in almost any way you choose.  In my case, I have elected to combine some of the existing frameworks’ systems and structure my URL in the form

domain.com/controller/module?var1=value&var2=value

This solves one of my personal pet peeves with existing frameworks.  Many of them are an either or (technically an exclusive or) system.. your GET variables are either all in the query, for example:

domain.com/index.php?controller=test&module=function&var1=value&var2=value

or they are all in a directory format

domain.com/controller/module/var1/value/var2/value

Most frameworks do a poor job of mixing and matching.

Step 1: .htaccess/mod_rewrite

Note: As you can see, I am gearing this tutorial towards what I know (Apache + PHP).  However, I have made the code as easy to read and understand as possible so that you can port it to other languages, web servers, etc.

The first step is to configure Apache to allow for our rewriting.  This is done through mod-rewrite, which on Apache 2+ can be enabled by going into the apache2/mods-enabled directory (on Debian systems usually located in /etc/apache2/mods-enabled) and create a symlink to the file ../mods-available/rewrite.load with the following command:

ln -s ../mods-available/rewrite.load

Now you can re-load Apache, and mod_rewrite should be enabled.  The second part of this step is to create an index.php file in your web directory and route all traffic through it.  To do this, create a .htaccess file in your web directory with the following inside:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ /index.php [L]
</IfModule>

This will route all traffic for non-existent pages and directories to index.php where we can parse the URL and route it appropriately. If you are having trouble getting this to work, ensure that you have the AllowOverride variable in your Apache configuration set to “All”.

Step 2: Parsing the URL

Open up your index.php file in your favourite editor (I still use vim).  Interestingly enough, the first step to deconstructing the URL is constructing it.  Since there is no since variable (that I’m aware of) to get the full URL, we need to put all of the info variables together first.  We can do that like so:

$path = parse_url(
  (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' .  // Scheme      
  $_SERVER['PHP_AUTH_USER'] . ':' .                        // User      
  $_SERVER['PHP_AUTH_PW'] . '@' .                          // Password      
  $_SERVER['HTTP_HOST'] .                                  // Hostname      
  $_SERVER['REQUEST_URI']                                // Path and query string
);

Here, we’re using PHP’s parse_url function to break apart the full URL into parts that PHP can handle a little better.  Specifically, we can now break apart the file request:

$temp = explode("/", substr($path['path'], 1));
$controller = strtolower((@$temp[0]) ? $temp[0] : "welcome");
$module = strtolower((@$temp[1]) ? $temp[1] : "index");

In this case, I’m only allowing two parts to the URL: the controller and the module.  You could expand this to include any number of parts.  I am also setting the default controller and module so that a request to domain.com/ or domain.com/controller will still have a place to go.  I finally convert the controller and module to lowercase so that I can identify the file name there the controller lives (more on this in the MVC part of this series).

Finally, I can route this to a class/function.  In my case, I am going to send it to a class called {$controller}Controller and a function called ($module}Handler.  We do want to make sure that it’s a class we’ve defined in our directory structure as well, to protect again any vulnerabilties (so users can call any class/function)  So I want to make sure that those exist:

if(!file_exists(CONTROLLER_DIR . "{$controller}Controller.php")) {      
     $controller = "Error";
     $module = "index";
}
if(!method_exists("{$controller}Controller", "{$module}Handler")) {
     $controller = "error";
     $module = "index";
}

If it doesn’t exist, we re-direct this user to errorController class and the indexHandler function.  This class/function would ship by default with the framework and could be customized later.  Provided that it passes that test, we can finally send it off to the appropriate place:

$class = $controller . "Controller";
$controller = new $class;
$method = "{$module}Handler";
$controller->$method();

In this case, I am using PHP’s __autoload function to load in the appropriate files/classes (again, more on this in the MVC part).

Step 3: Explore

That’s it!  You have a basic URL re-writing framework.  There is obviously a lot more to come, but this should give you a taste of the flexibility a PHP framework can give you (especially one you’ve designed).

Feel free to explore all of the other options for structuring URLs your own way.  In the next part, we’ll cover the MVC framework so we can put this to good use.

Note: I by no means consider myself an expert in PHP.  I view these articles as equal parts instruction for those of you in the dark and learning opportunity for me.  Feel free to comment or critique, especially if you can make it faster/cleaner/more secure!

If you liked this post so far, here is the second part.

5 Responses

  • There are plenty of php frameworks available and they are of very good standards,then what is a need of writing onw php framework.
    can u mention any reason of writing own php framework?

    • sure, there are many php frameworks available out there. and to be fair it would be hard to create your own framework which is better then others out there as many great folks are contributing to the existing ones.

      but if you take this new php framework creation as the learning exercise it will for sure make you understand better how such frameworks work and what are their strengths or weaknesses.

      so its a win even if your framework cannot outperform top existing ones.

  • Guest

    The more you get advanced in php, the more you want to write your own framework or classes the way you like.

    • noticed the same.
      I guess we get used to the way we do things as coders.
      and each new framework will have its own way and structure. which is not always bad.

  • TuxLyn

    I agree, Ive always wanted to code my own php framwork. I just don’t like all the frameworks available. Also, if you don’t write you’re own tools/frameworks you have no place in programming world anyway. Don’t listen to anyone saying that you’re re-inventing the wheel, you might do it better.