views:

464

answers:

4

I personally use the following method for all my sites. It has grown a little bit from using prefixed $_GET variables to using mod__rewrite but i have had these basics for a couple of years now.

.htaccess:

RewriteEngine On

RewriteRule ^includes/ - [L] [OR] #do not apply for direct requests to  /includes or 
RewriteRule ^images/ - [L] [OR] #do not apply for direct requests to /images

RewriteRule ^(([^/]+)/){0,}([^/]+)?$ index.php #rewrite all requests to index.php

index.php

*this file is obviously simplified, flattened and stripped to it's bare bones. All the basics are the same though: be super-flexible and have as little overhead as possible.

<?php 
session_start();
global $_TPL, $_URI; #$_URI will hold all the request parts. $_TPL will hold title, scripts, body. menu, custom page javascript, whatever you want.

error_reporting(E_ALL);

/* figure out the base url to index.php no matter where you place this script. could be in the root of a site, or even in some 2-level subdir */

$basedir = 'http://'.$_SERVER['HTTP_HOST'].(dirname($_SERVER['SCRIPT_NAME']) != '/' ? dirname($_SERVER["SCRIPT_NAME"]).'/' : '/');

/* convert URI to lower case, strip the basedir, drop empty parts and explode it to an array */
$uri = explode('/', str_replace(strtolower($baseDir), '', urldecode(strtolower('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']))));

foreach($uri as $key=>$val)
{
    if(!empty($val)) $_URI[] = $val;
}

/* now $_URI contains all url parts. we can load the plugins: */

function LoadPlugins($dirname)
{
    global $_TPL, $db;
    $files = glob("{$dirname}*.php");
    foreach ($files as $currentfile)
    {
     require($currentfile);
    }
}

LoadPlugins('./plugins/'); // this will just include all the files in the plugin dir.

include './includes/template.inc.php';
?>

Each plugin in ./plugins/ looks like this:

<?php

global $_TPL, $_URI;

switch($_URI[0])
{
    case 'comment':

        switch ($_URI[1])
         {
            case 'submit':

               /* 
                    do your action for http://yoursite/comment/submit here. 
                    Maybe create some objects,etc. When you're done, either die() with some html 
                    if you run an ajax request, or let the loop continue so that the next plugins will 
                    be loaded and we'll eventually land back @ index.php where the
                    template can be included.
               */
                   $_TPL['body'] .= "you have submitted a new comment";
            break;
            case 'delete':
                   /* this is one of my typical ajax actions (obviously simplified and without checks) 
        normally i also have an __autoload() function available that handles class loading. 
      */
                   $comment = new comment($_POST['id']);
                   $comment->deleteYourself();
                   die("comment {$_POST['id']} deleted.");

            break;
            default:
                   /* unknown action for /comment/ */

                   die("wtf are you trying?");

            break;
         }
      break;
}
?>

And finally: template.inc.php looks like this (i'm a huge fan of the 'PHP IS the template language' mantra)

<?php global $_TPL; ?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&gt;
<html>
<head>
<title><?=$_TPL['title'];?></title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<? 
if (!empty($_TPL['baseDir']))
{
    echo ("<base href='{$_TPL['baseDir']}' >\n");
}
if (!empty($_TPL['scripts']))
{
    $_TPL['scripts'] = array_unique($_TPL['scripts']);
    for ($i=0; $i<sizeof($_TPL['scripts']);$i++)
    {
    echo('<script type="text/javascript" src="'.$_TPL['scripts'][$i].'"></script>'."\n");
    }
}
if(!empty($_TPL['styles'])) {
    foreach($_TPL['styles'] as $css)
    {
     echo("<link rel='stylesheet' type='text/css' href='{$css}'>");
    }
}
?>
<?=((!empty($_TPL['style'])) ? '<style type="text/css">'."\n".$_TPL['style']."\n</style>" : '');?>
<?=((!empty($_TPL['script'])) ? '<script language="javascript">'."\n".$_TPL['script']."\n</script>" : '');?>

</head>
<body>
<div id="maincontent" class="<?=$_TPL['bodyclass'];?>">
<?=$_TPL['body'];?>
</div>

</body>
</html>

There you have it. my plugin-based, 'kinda-mvc' lightweight base php setup. The stuff i thow into a directory everytime i start a new site.

There are no tight rules this system forces you to follow, but it does hand you a super simple default setup with everything you need available.

I have thought about a modification where each of the plugins is actually a class, but that would probaly have little to no added functionality,you can just write any initialisation code you need in the index.php before loadPLugins.

Now i'm curious: What are the bare basics you put down when you start a new PHP project?

Please no answers like 'i use cakephp'. It would be nice if everybody could go into a little more detail than that, also describing what you need to do for like a hello world.

A: 

This is a bit of a broad question to be honest. An answer like 'i use cakephp' is completely valid for some people.

Personally I would setup the basic directory structure I expect to need (ie images, includes, etc) From there I would make sure that any libraries I expect to be used are ready and in a reasonable path.

It all depends on how you develop... if you use a prefab content management then you need to do less than if you mostly roll your own.

getting into config file level stuff it really all depends on what it is you are going to be using

Laith
+2  A: 

That's not really a good question, because there is no actual answer for it.

I'll make a few notes about your posted example though. Hope you can use some of them.

a) What is this? It's not going to execute.

include template.inc.php;

b) This looks misguided.

$uri = explode('/', str_replace(strtolower($baseDir), '', urldecode(strtolower('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']))));

Why are you urldecoding the URL? If there are forward-slashes in a GET-parameter, you won't get the expected result. Use parse_url or just use a regexp to strip everything from the first ? and forth away.

c) You don't need to declare $_TPL + $_URI as globals in the included file, since they are already in the scope of LoadPlugins

d) In your templates, you are not escaping output. This is a serious flaw, which could likely turn into a security hazard. You must escape all strings embedded in HTML with htmlspecialchars. Since it's a bit longwinded to type out echo htmlentities($foo); all the time, you may want to create a helper function. This also makes it much easier to spot if you accidentally missed one. I use:

function e($str) {
  echo htmlspecialchars($str);
}

e) While this doesn't hurt (Assuming you're using ISO-8859-1), it probably doesn't do what you expect:

<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

Make sure that the web server is actually sending the proper charset with the HTTP-headers, since these take precedence over a tag. The meta tag is only used if there isn't sent a proper HTTP header, which most web servers do by default. In PHP, you can tell the web server to send a header with the header function. Eg.:

header("Content-Type: text/html; charset=ISO-8859-1");
troelskn
A) A copy/paste/ last addition typo. I fixed it.B) decoding the URL is used for urlencoded urls :-) I ignore any get parameters mostly, which is caught by the switching of only $_URI These will not mix up even if you try.C) Very true! Probably some legacy stuff i forgot to remove. A valid point!
SchizoDuckie
D) Escaping of all HTML is all automatically handled on inserting and fetching data. that's out of the scope of this post.E) Also a good tip, i'll include that in my standard functions.php
SchizoDuckie
Re B:And what happens when the user requests the following URL:/foo/bar/cux?ding=dong%2FzapRe D:That is a *very* bad practise you have going there.
troelskn
No, no, no you're not getting the point.Note that i *explicitly* *have* *to* switch $_URI[0] for foo and $_URI[1] for bar AND $_URI[2] for cux and thén do *something* with $_URI 3 that's triggered by ?ding=dong ! Stuff *only* happens if you explicitly declare it using these switches!
SchizoDuckie
Well, I still don't understand why you need to call urldecode. If you don't use the data in the querystring, why decode it at all?
troelskn
A: 

This is one of the first functions I like to place on my project: setUrlVariables

mrlinx
A: 
/
 config.php
 index.php
 home.php
 header.php
 footer.php

 /images

 /scripts
  foo.js
  jquery_packed.js

 /styles
  /yui
  screen.foo.css
  print.foo.css
  ie.screen.css

 /foo
  foo.php
  index.php

 /foo-subtopic
  foo-subtopic.php
  index.php

 /bar
  bar.php
  index.php
------------------

*config.php holds constants and other universal variables
* foo/index.php simply includes 'foo.php'
*At top of foo/foo.php:
    * <?php require_once '../config.php'; ?>`
    * <?php require_once C_REL_PATH_ROOT . 'header.php'; ?>
*At bottom:
    * <?php require_once C_REL_PATH_ROOT . 'footer.php'; ?>


  • Does not rely of .htaccess to get decently clean URLs (ignoring the querystrings/parameters aspect).

  • Good portability to a given webserver host configuration.

  • foo.php for every index.php in a subdirectory avoids seeing 'index.php' a dozen times over in your editor at development time.

This is not the end-all-be-all, just my common state of mind for simple website (not full blown webapp) setups.

micahwittman