Patterns for PHP: Page Controller Draft

Patterns for PHP Contribution

I’ve decided it would have been a mockery to PHP developers, if I had taken up writing about MVC, which I still barely know anything about. However, I have been working a little bit with Page Controller Pattern of MVC. I decided I could write what little I do know and let someone with more knowledge fill in the blanks. Helping myself and others in the community.

Types of Page Controllers

From my experience, it seems Page Controlling falls into three categories, based on difficultly of implementation.

  1. IF Block Structure
  2. Directory Structure
  3. Object Method

If Block

When I first seen this in Dragon Knight, I laughed like a fool. At the time, I was coding using multiple pages with no mod_rewrite. Nothing wrong with using multiple pages, however I noticed some security problems with the Dragon Knights method, which were fixed.

The structure is as follows:

if($page == 'page_name') {

    // Do and include stuff

} else if($page == 'page_name') {

    // Do and include stuff

} else if($page == 'another_page_name') {

    // Do and include stuff

}

Really easy to do and the most basic representation of a Page Controller pattern. The Page variable can be from a $_GET key or from the url path function.

This method has flaws: for one, if there are many pages that need to be controlled, then the if block can get fairly large and hard to manage; and two, once it does get large, say around 1000 to 100000 blocks, it can be slow.

Directory Structure

This method has been bouncing around in my mind every since I read and heard the podcast about “PHP Best Practices” and for the life of me, I can’t remember where the blog and podcast is. I didn’t laugh, but I just thought that without any more information, such as PHP code, the podcast was pretty worthless. The statement was only having one index.php file that included all of the required files, adding some security and ease of development. It was interesting, but I didn’t “grok” it until several days ago when I was thinking about how to best maintain the Gamehole Page Controller.

Note: I haven’t developed any code, but I do have some sort of pseudo-code for how to go about the method.

// Get the path names for inclusion
$pathList = explode('/', $_SERVER['QUERY_STRING']);

// Find the amount of levels for directory and file inclusion.
$pathDepth = count($pathList);

define("PROJECT_PATH", realpath(dirname(__FILE__).'/../project'));

if($pathDepth == 0) {
     require PROJECT_PATH.'/controller/default.php';
} else {
    $path = PROJECT_PATH;
    foreach($pathList as $pathElement)
    {
        $file = $path.'/'.$pathElement;

        if($pathDepth == 1) {
            if(is_file($file)) {
                include($file);
            } else {
                if(is_file($file.'/default.php')) {
                    include($file.'/default.php');
                } else {
                    header("Status: 404 Not Found");
                }
            }
        } else {
            if(!is_dir($file)) {
                header("Status: 404 Not Found");
            }
        }

        $pathDepth--;    // Is Directory; Maybe
    }
}

The amount of lines is still less than Gamehole, even with the checks. Without any debugging this probably won’t work “out of box”. As a prototype, it is meant to collect the directory structure from the URL and finally the file, then include it after checking that it exists.

The advantage is that I wouldn’t have to touch the page controller at all to add new pages to the list. It also has less chance that I’ll forget a bracket and the whole PHP site would fail. Removing a single point of site failure is a problem that I needed to address with future development.

Object Method

Many frameworks and classes exist for handling the Page Controller using an object.

This is where my “tutorial” ends. I have not yet developed with this method, so I know nothing how it works. I do hope to learn after working with the second method for a while.

Update:

The page controller I was looking for was Cgiapp2.

Possibly Related Posts:


7 Comments.

  1. If you really want to check out a cool page controller, you should check out CGI::App for php by Matthew Weier O’Phinney. The class is not only cool, but hes a really great guy and has always been on hand to answer my questions about it. I used an older version of it to power a site that gets now over a few hundred thousand unique visitors a month. His site is:
    http://weierophinney.net/matthew/

  2. Sweet. Thanks that is exactly the class I was looking for!

  3. Page Controller = An object that handles a request for a specific page or action on a Web site.
    Front Controller = A controller that handles all requests for a Web site.

    This means (at least) examples 1 and 2 are Front Controllers and not Page Controllers.

    For more info see Patterns of Enterprise Application by Martin Fowler.

  4. this is my version of the IF block:


    require_once 'config.php';

    $action = 'welcome';

    if (isset($_REQUEST['action'])) {
    $action = $_REQUEST['action'];

    $params = '';
    if (isset($_REQUEST['params']))
    {
    $params = unserialize(base64_decode($_REQUEST['params']));
    }

    unset($continue);

    require_once 'action/' . $action . '.php';

    if (isset($continue))
    {
    header('Location: index.php?' . $continue);
    }

    it can’t get more simpler than that…
    and I love simplicity…

    /sak

  5. sak,
    You’ll want to be extremely careful with that type of front controller. As it stands now someone could potentially have access to any file your web server has permissions too by simply passing a string like ‘../../../try/a/few/paths’. When allowing for users to supply paths to files via the http request you want to be sure you are in some way controlling what they are including. Passing vars blindly into include or require is just a recipe for nastiness.

  6. Page Controller = An object that handles a request for a specific page or action on a Web site….For more info see Patterns of Enterprise Application by Martin Fowler.

    I tried to find the other definition from the Gang of Four, but I lost the link. However, the person you reference is Martin Fowler and the book is online. So here is the text.

    As a result, Page Controller has one input controller for each logical page of the Web site. That controller may be the page itself, as it often is in server page environments, or it may be a separate object that corresponds to that page.

    Taking the liberal interpretation, all three of my choices would represent a Page Controller. It doesn’t have to be an object and that is where I think people fall apart on the issue.

    At Mike Lively: Should I also check for either ‘.’ or ‘..’ instead.

  7. I wouldn’t filter out single dots as they can of course realisticly be in a valid file or even directory name. You could filter out .. path directories. One of my favorites (though it’s not necessarily the best performance wise) is using realpath. Would look something like this (in saks example):

    $valid_root = realpath( ‘action/’ );
    $user_supplied_path = realpath( ‘action/’ . $action . ‘.php’ );

    if (!$valid_root || !$user_supplied_path || strpos($user_supplied_path, $valid_root) !== 0) {
    die(“Invalid path”);
    } else {
    require $user_supplied_path;
    }

    There are of course bad side effects to this. If you are relying on symbolic links you are kind of screwed. It’s not as quick probably as a find/replace for ‘..’. Those two issues aside though it does a good job in ensuring that you aren’t including files you don’t want to.

    Hope it helps. (Don’t rely on the above code. I haven’t had my coffee yet. :)