Zend Certified Engineer

phpguru.org

Free PHP, Javascript and C# code

Application Structure

An error commonly made with applications and websites is made right at the very start - when laying out the structure of your application. It can make the difference between coding being a joy, and a chore. Not only this, but it can also help to make your app/website more secure, by preventing you having to remember important tasks like authentication. So onward...

First of all. Let me tell you this. You are not special. You are the all singing all dancing crap of the world. Not everyone thinks like you. Not everyone will understand your directory names. I tell you, it's infuriating seeing directories with three letter names which contain absolutely nothing related to what you were expecting. For example, a "lib" directory which doesn't contain "lib"raries, or a "bin" directory which doesn't contain "bin"aries. Be verbose! It doesn't hurt. Trust me.

So with supersized directory names firmly in mind (and citizens of the US of A, I'm afraid there's no fries with that), I present to you, the directory structure that I have, over the past three or four years, evolved to be using. Go ahead, click the pluses - they work...

Overview

The structure is laid out so that all major directories are at the same level, in the main application directory (in this case "www.example.com"). This structure suits both applications and websites equally well, since as we'll see paths and DocumentRoots can easily be customised. Normally though, the DocumentRoot would be the htdocs directory (so called as that's the name that the Apache webserver uses by default). So here's a break down of each directory...

cron

Holds all scripts that are run via cron, for example daily/hourly maintenance. Shouldn't be any reason why you have your maintenance scripts in another language either. Code reuse. Hoo-ya.

htdocs

As noted, the DocumentRoot. Holds all the "front end" scripts - the files whose names you tap daintily into your browsers address bar. Anything to be accessible by the user. Things like CSS files, images and Jabbascript files should of course be put away neatly in their own directories. We'll get to the config.php file later.

includes

The real meat of the site. All your application/site specific libraries go here. Classes, functions, you name it. Again, feel at liberty to further organise into subdirectories, in particular foreign code (eg. the jpgraph library). Again, the files shown here (prepend.php and template.php), we'll come to later.

logs

I don't always employ this one, but it's handy at times. Quite obviously, it's for your log files.

pear

Now this will probably be quite contentious. Simply put, the whole idea of a central PEAR installation gives me the willies. One upgrade can break multiple apps/websites? No thanks. Having to check every app/website when you do get around to upgrading? Double plus bad. So in each of my apps/websites there is a pear directory, in which lives a replica of the PEAR directory structure and all the PEAR code that I use. Heck if you really wanted to, you could even change the options in the installer and use the installer to manage this particular directory. That's far too much work for me though, so I use good old fashioned cut 'n' paste code reuse. Not only this, but if you're using source control, then all the PEAR code can more easily be incorporated into your repository.

scripts

This one is for shell scripts that support the app/site. Things like upload/release scripts, database import/export etc.

templates

And finally, the templates directory. And don't be under any illusion, we aren't talking "template engine" templates. Well, I'm not. You can if you must.

So there you have the directory structure. Very simple, very easy to understand, in particular if you're picking up maintenance of an app/site. This isn't all there is to it though. There's also how you structure your files. This is where you make your app easier and quicker to write, and more secure.

index.php
   |
   +- config.php
   |     |
   |     +- Path & environment setup
   |     +- Common libraries
   |     +- prepend.php
   |
  ... Logic goes here
   |
   |
   +- template.php

This here thing on the right, is how a files require()s are laid out. Starting at the top, working your way down:

  1. First thing in every single script, is to include the config.php file, which lives in the htdocs directory. This sets up various paths, all based on the current directory. These paths are then used to setup the include_path [1]. Also, things like error_reporting are set. This file, using the newly set include_path then includes all files which are commonly required. Examples of this are database, authentication and session libraries, things you don't want to be thinking about when putting together a new page.

  2. Then the prepend.php is dragged in. This is code which is common to every request. Things that you don't want to rewrite on every page, and things you don't want to have to remember. Examples are starting the session, authentication if you app/site requires it, opening a database connection etc. This is where the improved security comes in: the less you have to remember, the less there is to forget. Forget to check authentication on a page, and you're in deep doo-doo.

  3. Your logic. Simply put, this is your code that is specific to this page. Could be anything.

  4. The last thing to do is to show the page, and for that you need template.php. This isn't the template library itself, rather a file where you can put code that is common to showing a page. For example showing a header and/or footer, setting up variables that pertain to the header/footer etc. Again, showing headers/footers is not something you want to have to rewrite on every new page.

So that's it. A simple yet elegant way to layout your application/website which can save you time and mullah.


Notes

  1. You might think that munging the include_path on every page request is sub-optimal, and you'd be right. However, certainly whilst in development, it can be very handy. Consider this:

    <?php

    $_PATHS
    ["base"]      = dirname(dirname(__FILE__)) . "/";
    $_PATHS["includes"]  = $_PATHS["base"] . "includes/";
    $_PATHS["templates"] = $_PATHS["base"] . "templates/";
    $_PATHS["pear"]      = $_PATHS["base"] . "pear/";
    $_PATHS["logs"]      = $_PATHS["base"] . "logs/";

    /**
    * Set include path
    */
    ini_set("include_path",
            
    "$_PATHS[includes]:$_PATHS[pear]:$_PATHS[templates]");

    ?>

    By doing this, you can move your application around your filesystem at will, onto another server, and include/require calls won't break. How wonderful.

    As a side note, if your default include_path contains unnecessary directories, reducing it in this way can actually improve subsequent include/require performance, since fewer stat() calls to find files will be required.

Link to me

If you use any of the code on this site (and if you don't I guess) or it makes your life easier, I'd appreciate a link - http://www.phpguru.org. Thanks.

RSS Feed for Comments

Comments

Author: Alan Knowles
Posted: 14th March 2005 09:47
using prepend is evil!

It has a tendancy to make code totally unreadably when you come back 6 months latter.. - Questions like 'where is this method/class defined/configured, I cant find it the include anywhere' come to mind.

I've seen code where it does all sorts of magic vodoo in prepend, let alone the portibility issues of setting up the code on another server...

another problem you have in using templates in a third directory is that previewing the page, without the server is difficult. you can end up mundging paths really badly just to see get an idea of what it will look like.. images/css etc.
Quote
Author: Helgi
Posted: 14th March 2005 14:42
Well I my self find it better to have prepend and config together in one file, because to me it's all just config stuff :-)

Also you're only using none windows separators in the include_path (not like that's bad in anyway ;)) but I think windows has ; not :

IMHO people that use the system PEAR folder for any application are stupid, because of the things you mentioned, having ya own PEAR dir is veerrrry important (=
Wished more people would realize that.
Quote
Author: Arnaud
Posted: 14th March 2005 17:37
Helgi: which is why PEAR needs to improve to prevent system-wide breakdowns when you upgrade :)

ps: it won't improve magically, we need to do it :)
Quote
Author: Richard Heyes
Posted: 14th March 2005 17:51
Alan Knowles:
> using prepend is evil!

If you're referring to the auto_prepend setting, then sure, it's nasty, which is why all the file inclusion should be done with require(). The file is only named prepend.php becuase, well, it's at the beginning. :)

> another problem you have in using templates in
> a third directory is that previewing the page,
> without the server is difficult. you can end up
> mundging paths really badly just to see get an
> idea of what it will look like.. images/css
> etc.

Eeesh! Never develop without a webserver! :-)
Quote
Author: dravine
Posted: 14th March 2005 21:01
Developing web apps without a web server is just idiocy. How hard is it to install apache and php on your machine and develop locally? I've been doing it for years personally. People sometimes ask me why my laptop has a full suite of server apps on it, but when a server crashes or a network goes down, my productivity doesn't suffer.

Granted I'm not doing any of this on windows, and it may be a bit more difficult to get postgres etc. up and running on windows, but the benifits far outweigh the downsides. If you need MS office that bad, buy vmware and have at it.

I still don't understand the folks who comment that the script doesn't use windows paths. Big deal! I've yet to see anyone using PHP on windows in a production environment. So why would you want the development environment to be grossly different from the production one?
Quote
Author: Bert Van den Brande
Posted: 15th March 2005 10:02
dravine:
> So why
> would you want the development environment to
> be grossly different from the production one?

Because not everyone has the luxury and/or knowledge to work with something else than windows as the development environment ...
Quote
Author: Greg Strockbine
Posted: 24th March 2005 06:45
A separate copy of PEAR for each website?
oh dude, I wish I hadn't stumbled across
your site. This is scaring me into not using
php.

greg strockbine
Quote
Author: Richard Heyes
Posted: 24th March 2005 10:20
Greg Strockbine:
> A separate copy of PEAR for each website?
> oh dude, I wish I hadn't stumbled across
> your site. This is scaring me into not using
> php.

From the feedback I've been getting this appears to be what the vast majority of people do. Consider the need for one version of a class for one app, and another version for another app, both on the same server. Not good.
Quote
Author: Mike
Posted: 27th March 2005 18:22
interessting article!

I like the:
dirname(dirname(__FILE__)) . "/";
Quote
Author: Pies
Posted: 18th April 2005 02:46
While I agree that there's a great need to systematize the directory structure on your projects, I don't really like the one shown in the article. I wouldn't even know where to put the business logics in.

My own structure (based on Ruby on Rails):

/app
/controllers
/models
/views
/layouts
default.thtml
/config
database.php
routes.php
/docs
/libs
/logs
/public
/css
/img
dispatch.php
/scripts

This one is actually from an MVC framework I develop. The /app directory holds all application's business logics (controllers), data structures (models) and templates (views).

In /config you keep, well, configuration -- in my case it's database config and URL structure.

/docs and /logs are obvious and optional.

/libs keeps all the universal libraries, such as PEAR and PECL (if I used them).

/public is for files that are directly accessible to the visitors with a minor exception for dispatch.php, which is a script that includes some libraries and runs the query.

/scripts contains all the utility scripts, both cron and interactive.

Of course, what is the most comfortable direstory structure depends a lot on what kind of website are you developing, and depends even more on what you're used to. I like mine :)
Quote
Author: Pies
Posted: 18th April 2005 02:48
Eh, the structure once again:

/app
___/controllers
___/models
___/views
______/layouts
_________default.thtml
/config
___database.php
___routes.php
/docs
/libs
/logs
/public
___/css
___/img
___dispatch.php
/scripts

And see http://sputnik.pl/cake/ for information about Cake, the framework I use.
Quote
Author: Crache
Posted: 22nd April 2005 03:03
One thing that I don't like about the way you guys are laying out the directory structures is you seem to want to conquer the site. Though in defense of the article I think it was written with a general situation in mind.

I don't like shoving various parts of a project into lots of different directory scopes just because of some minor security benefits provided by default server configuration. I like to keep a project as isolated, simplified, flexible and compatible as possible within reasonable means.

The purpose of your article was I'm sure intended to benefit those who might not otherwise put forth the due diligence in deciding how they should best organize things. If someone isn't putting effort into how their projects are organized, they are dangerous to themselves and others. :) Especially when it comes to databases, where articulated architecture can mean the difference between a 1 week job and a 3 month job.

It's excellent for people to consider the file organization of a project in direct relation to how you maintain the overall idea in your mind. "Trash in, Trash out."

Here's how i normally structure a typical project (and this means it might not apply to everyone's specialized project types):

------------------------------------------

/htdocs/index.php (could also be in /htdocs/<project>/)

/htdocs/img/ (images relevant to site)

/htdocs/<project>/inc/config/inc_db.php
/htdocs/<project>/inc/config/inc_settings.php

/htdocs/<project>/inc/ (code relevant to all)
/htdocs/<project>/inc/inc_auth.php
/htdocs/<project>/inc/inc_html.php

/htdocs/<project>/inc/site/ (code relevant to site)
/htdocs/<project>/inc/site/html/css/
/htdocs/<project>/inc/site/html/js/
/htdocs/<project>/inc/site/html/<template>/css/
/htdocs/<project>/inc/site/html/<template>/js/

/htdocs/<project>/inc/backend/ (code relevant to backend)
/htdocs/<project>/inc/backend/cron/
/htdocs/<project>/inc/backend/img/ (could also be /htdocs/img/backend/)
/htdocs/<project>/inc/backend/html/css/
/htdocs/<project>/inc/backend/html/js/
/htdocs/<project>/inc/backend/html/<template>/css/
/htdocs/<project>/inc/backend/html/<template>/js/

/htdocs/<project>/logs/

/htdocs/<project>/resources/docs/
/htdocs/<project>/resources/utils/ (misc dev/management scripts that weren't worth building into the admin interface)

------------------------------------------

Of course that would look much cleaner in a dynamic tree format, but what the hey. Someone who'd never seen this particular <project> before could easily understand where all it's relevant files are and exactly how to find what they're looking for.

In this particular directory layout you can tell that /site/ is intended for a public site and /backend/ would be for the administrator of the site to manage content, mail, whatever. Or /site/ could be non-existent and there would just be a backend private application.

If the site is using SSL and the secure directory is not under /htdocs/, you might have the index.php under the live secure directory, but all the other aspects of the project that don't require encrypted transfer can stay under /htdocs/ so they don't take up unnecessary processor time.

Also, there are some directories you may not want to be public, so instead of hiding behind /htdocs/ and throwing it out of the project directory scope, you might want to just use an .htaccess file.

Another subject which I think would be a nice addition to your article would be file naming conventions, because they're just as important as the location of the files. In fact, with really good naming conventions, depending on the size of the project, you could do away with a lot of directories.


-Crache
Quote
Author: Thilo Raufeisen
Posted: 30th April 2005 15:59
The most important thing: Never put files, which contains passwords/access data, in the webroot.
Also: Put as less as possible in the webroot. A Databaseclass should not be accessible by a client. Also the Templatedirectory. There is no need to makes them world-wide readable.
Donīt rely on the php-parser. Code between <?php and ?> is not secure because itīs possible, that php crashes. In this case, the client can download the PHP-File.
Quote
Author: Ray Cauchi
Posted: 9th June 2005 14:22
I am still trying to figure how the hell to develop a web app in PHP without a server?

baffled...

As for directory structure, I must say I am guilty of the libs directory (guess it could be short for libidos - somewhere to store your libido when you have a client meeting perhaps? guess it depends on the client?)

I can't really fathom why installing AMP on either L or W is such an issue - it ain't that hard!

Nor can I fathom why a seperate installation of PEAR per app is swo difficult - it ain't ! though the idea of centralisation is utopia, actually doing it and making it work is much harder than downloading PEAR and installing it (manually even)

As for having different directories for everything, as humans we tend to put our undies in a separate drawer to our t-shirts (well, I do...) - its no different really. When I get dressed I usually wear both. I know where eahc is because i put them there. Isn't that part of getting dressed 101?

Similarly, if I split my files into what I at least consider to be logical directories, and then either document that or make it so bleedingly obvious what each directory does, that if another developer needs to work on my code I can stand behind them with a paddle and justifiably hit them square across the head when they ask me whats in the PEAR directory, isn't that really just the same as putting your t-shirts in one drawer and your undies in another?

I digress...back to work for fear of my Clients whacking ME across the head with that paddle...
Quote
Author: Eric
Posted: 10th June 2005 14:37
I would prefer the simple "all-purpose" structure from Richard to the more complex ones like Pie's or Crache's for a simple reason: It is so obvious than I seen at a glance where (almost) everything was supposed to be stored.

I agree that you should never store includes files, especialy ones with hardcoded passwords in htdocs but some hosting companies do not allow you to do that. Here is a few tips to make this as secure as possible when you have no other solution:
- Always use ".php" as file extension instead of some ".inc" or other fancy stuffs. It does not matter for PHP to include any file with any extension, but it will prevent peoples to access the source by just typing the file URL in their browser (most HTTP servers will not recognize ".inc" extension and will process it as TEXT/PLAIN...). You may use something like ".inc.php" if you really want to.
- Protect your include directory with a .htaccess (deny for all is OK since nobody is supposed to access the file with HTTP)
- Never (I mean NEVER !) display error message with connection information (i.e. to NOT follow: print "Unable to connect DB using '$login' account with '$password' password";)

You may think that the two first points are redundants, but it does not cost more, so use BOTH of them.
I did not think anybody may be fool enough for doing what I describe in the third point until I actually seen it... (the guy posted a code sample on a forum with both the include line AND its web site URL (another thing NOT to do...))

About installing AMP on W, peoples with very few admin skills may use easyphp (www.easyphp.org).
This thing will easily install Apache + PHP + MySQL + PhpMyAdmin in a few clicks with a nice GUI for starting/stopping servers.
Last release (1.8) even work on a USB keys and be launched from any computer you plug it into.

Just take care of cAsInG mismatch... Since windows has a no case-sensitive filesystem, it will work if you include "MyIncFile.php", even if the file name is "myINCfile.PHP". It will not on unix platform...
Same thing occurs with MySQL table names since MySQL store tables as files. If you create table 'foo' and perform the request "SELECT * FROM `Foo`;", it will work on windows, not elsewhere...

Eric
Quote
Author: pmcweb.at
Posted: 15th July 2005 11:50
Hint: to extend the code

ini_set("include_path", "$_PATHS[includes]:$_PATHS[pear]:$_PATHS[templates]");

one has to determin the OS and set a semi-colon, if not linux.

If using the PEAR, it is already done in the PEAR.php file.

changing it to
ini_set("include_path", $_PATHS[includes].PATH_SEPARATOR.$_PATHS[pear].PATH_SEPARATOR.$_PATHS[templates]);

make it platform indepented.
Quote
Author: john
Posted: 29th July 2005 08:55
$dburl = file_get_contents("path/to/file/with/password");

That call is fast. It keeps your password away from the visible parts of the site.
Quote
Author: Elantrix
Posted: 20th September 2005 11:03
The difference between windows and *nixes is not that big, the only time you really need to worry about this is when you are working with:
A) networking
B) system calls

As for the file structure. I do it like this

Base dir: /www/vhosts/www.test.org/html/

index.php
includes/
template/
template/xml/
public/images/
public/styles/
public/files/
pulic/scripts/
webcms/ (usually different for every website for security)
var/
lang/
install/ (temp install dir)
Quote
Author: James
Posted: 31st October 2005 23:23
Here's mine. Everything is in the doc root on my development box at present, although I may move it around later.

cache
cache/mail
cache/page
cache/query
cache/thumb
chrome (CSS and layout images)
class
class/<classname>
class/<classname>/class.<classname>.php (makes it easy for __autoload to find everything in PHP 5)
class/<classname>/dialog.<dialogname>.php (template for popup dialog)
class/<classname>/method.<methodname>.php (include template for methods that write HTML)
client (JS and SWF files)
data (mostly CSV files)
include
include/PEAR (only the PEAR files used in the app, not the whole PEAR archive)
include/<packagename>
servlet (specialized scripts that serve files from the database, RSS, photorolls, etc.)
Quote
Author: Krokodox
Posted: 9th November 2005 22:39
dravine:

> I still don't understand the folks who comment
> that the script doesn't use windows paths. Big
> deal! I've yet to see anyone using PHP on
> windows in a production environment. So why
> would you want the development environment to
> be grossly different from the production one?

Wake up and smell the coffe! We are running a *LARGE* site on 20+ PHP / IIS6 / W2K3 servers with MySQL (also on W2k3!), albeit slimmed down W2K3 and IIS6 installations, with wonderful performance, stability and manageability.

I would never dream of switching to Linux / Apache 1.x, not when IIS6 is excellent in multithreading, easy to configure, maintain and lock down to be PHP-only.

Installation from bare-bones to up-and-running server takes less than an hour with preconfiguired LAN boot and setup scripts.

Awake yet? ;-)
Quote
Author: Anurag
Posted: 15th December 2005 04:07
a bottom-up approach would suggest something like this

[Basic Structure]

/configuration.php -- contains gloal configuration
/initialize.php -- initializes application according to environment
/index.php -- document root
/Frontend/ -- all frontend stuff including css,presentation pages, images, javascript etc., etc.
/Backend/ -- all backend stuff including back-end scripting, business logic etc etc

:)
Quote
Author: Anurag
Posted: 15th December 2005 04:27
you can extend the Frontend/ and Backend/ directories further, but for a simple web application even this structure would suffice.

configuration and initialization are two different things. you shouldnt combine them into the same step for portability reasons.

/configuration.php simply holds application-wide configuration like database connection information, paths and so on.
example
define("ROOT", "/htdocs/");
define("HTTP_ROOT", "/");
define("DB_USERNAME", "...");
define("DB_PASSWORD", "...");
define("DB_DATABASE", "...");
define("DB_TYPE", "..."); // mysql/pgsql/oracle etc

/initialization.php is used to initialize the application to conform to the current environment.
example
ini_set('include_path', ROOT);
ini_set('error_reporting', E_ALL);
ini_set('magic_quotes_runtime', false);
Quote
Author: Prashant
Posted: 16th February 2006 07:48
I have a small company and i just started working in php,mysql,apache. I like to make c/s arch. but i do't know how to do it will any on 1 help me pls. mail me in prashcom@gmail.com
I am using windows Xp and i m using phpdev5(compaq pack of php,mysql,apache).I need help from anyone
Quote
Author: Chris
Posted: 16th June 2008 19:10
I am curious how people display images within HTML code when it is a couple of folders down the chain?
Quote
Author: Richard Heyes
Posted: 16th June 2008 19:12
Chris:
> I am curious how people display images within
> HTML code when it is a couple of folders down
> the chain?

Just have a top level images folder and all of your image paths will start: /images/...
Quote
Author: Chris
Posted: 16th June 2008 23:04
What happens if you have a number of templates which automatically and dynamically change? Just multiple sub-folders within the main images folder?
Quote

Post Comment

Your name:
Your email:
(Don't worry, I won't spam you.)
Comments:
  Do not post support type questions please

 
CAPTCHA image If you can't read the CAPTCHA then press the submit button to get another. Your comment will re-appear (as if by magic...).
Captcha image
Last modified: 16:14 29th December 2006