[ previously in this series: Blueprint for PHP Applications: Bootstrapping – part 1 ]
In Part 1 of this article I talked a lot about funneling. Sending every request to one PHP file that then controls the flow of the request into our application code. This one PHP file is called the “Bootstrapper” and deals with everything in common for every request our application receives. The bootstrapper can setup, configure and gift wrap everything that all pages have in common. It can make sure the include path is setup correctly, that the environment is configured correctly, all PHP settings are set, that common model objects are loaded, and that the front controller is invoked to begin your MVC processing. If you setup the bootstrapper correctly your application code will be more manageable and consistent, along with being easier to write in the first place.
Now that all requests are headed its way, we can dig deeper into the Bootstrapper itself.
The Basic Bootstrapper
Let’s narrow the scope of our initial bootstrapper and make sure it is the kernel that we can expand over time as the Blueprint is continued in future articles. Let’s tackle the following issues as we continue this series:
- Directory structure of our application
- PHP settings
- Application settings
- Session management
- HTTP Headers
- Delegating to a controller
- Error handling
Some of these items will be roughed in place-holders for future best practice discussions. For example, error handling will grab the error and display it, whereas in future articles we will discuss logging and custom error pages.
Directory Structure
The directory structure of an application may change depending on if you are inhabiting a server where you have full control, or running within one where you are limited to stay within your document root. Typically, we would want to limit the amount of files under the document root to include the .htaccess, index.php and static files (images, css, JavaScript, html, etc.). But in this blueprint example we will assume the worse case of running within the document root, and therefore require strict protections around file access. I will use this model, but make it easy to rearrange the directories if you have more control on your host and want to follow the best practice of keeping extras out of the document root. The same goes for settings placed in the .htaccess file that you could just as easily move up to the httpd.conf file if you have access and the desire to do so. But before you give up on using .htaccess, take a look at all of what you can do with this fun little .htaccess file.
Here is the structure for working under the document root (in fancy ASCII text):
www
|-- private
| |-- app
| | |-- php
| | | |-- classes
| | | +-- scripts
| | |-- settings
| | +-- sql
| +-- lib
| +-- ZendFramework-HEAD
+-- public
|-- css
|-- images
+-- scripts
The contents of the www/private directory can be moved outside the document root if your server configuration allows. The only adjustments you will have to make are with the include path PHP setting to make sure files can be found when included by another script. In the meantime we need to protect the private directory from inadvertent access directly by an end-user, so we place a special .htacess file in the www/private directory that contains this one line of configuration:
deny from all
This will provide an error of “Forbidden” to anyone trying to directly access a file below this point. If you have a need to open access again for specific files under www/private, you can reverse this setting at a lower level, or move the location of this file to more specific points you wish to protect.
In the /www directory we place our .htaccess and index.php that provide our funnel and bootstrapper and those will look like:
.htaccess
RewriteEngine on RewriteBase / RewriteRule .* index.php php_flag magic_quotes_gpc off php_value include_path "./private/app/php/classes:./private/app/php/scripts:./private/lib/ZendFramework-HEAD/library:./private/lib/ZendFramework-HEAD/incubator"
Remember on Windows to change the colons ":" in the include_path to semicolons ";" if you want this to work outside of a Unix environment. Also, if you are running under an alias such as http://localhost/test/, then change the RewriteBase / to RewriteBase /test/ as well. Also note that we turn off magic quoting so that it is ensured to be off, and that we set the PHP include path in this file since it is machine specific and the application should not carry a hard coded value that might change in different deployments. The .htaccess file is assumed to be heavily modified for each installation, so we focus most guaranteed-to-change values into this file, which can also be protected so that only the administrator can see the contents (such as database passwords).
index.php
<?php
require_once 'Zend.php';
echo 'Hello Baron<br />';
echo Zend::dump(array('testing' => 'worked'), null, false);
?>
And now you are ready to test. You should find that any and all URL’s will end up hitting our bootstrap file, and should show results similar to the following if everything (i.e. path to Zend Framework) is setup correctly:
Hello Baron
array(1) {
["testing"] => string(6) "worked"
}
This shows that our Zend Framework path is correct and that our rewrite rules and .htaccess are working just fine.
Allowing Static Files Through
What about the css, images and scripts directories under www/public? They won’t serve anything at the moment with the .htaccess file in the root blocking them, so we will add a custom .htaccess file to the www/public directory turning off rewriting altogether and exposing the entire contents beneath for the world to see.
.htaccess for www/public directory
RewriteEngine off
Anything placed in those three directories is fair game for the public to see in their entirety. They are not secured directories and you should limit what you place within each. If you do not like having these under a subdirectory called “public”, you can always place each of these at the root of the www directory and put the same .htaccess file in each.
Final Directory Structure With Files
The final directory structure with files added is as follows:
/www
|-- /private
| |-- /app
| | |-- /php
| | | |-- /classes
| | | +-- /scripts
| | |-- /settings
| | +-- /sql
| |-- /lib
| | +-- /ZendFramework-HEAD
| +-- .htaccess (denying all access)
|-- /public
| |-- /css
| |-- /images
| |-- /scripts
| +-- .htaccess (allowing all access to all files)
|-- .htaccess (funnelling all requests to index.php)
+-- index.php (bootstrap file)
By now, you probably are wondering about the www/private/app/php directory containing both classes and scripts. The classes directory will contain application code that can be loaded using the Zend::loadClass() static method that follows a specific subdirectory and naming convention. scripts will contain directly included files that do not follow this pattern.
One last note about the directory structure: I have named the Zend Framework directory ZendFramework-HEAD so that I can differentiate between multiple versions of the framework that I may be tracking and control which one is in use at the current moment. It is a best practice to include the version number (or Tag) of any library so that the directory name is self documenting as to what exactly it contains. And since I’m using the Zend Framework in this article and calling it from index.php, be sure to download the current version of the framework from the Zend Framework site or from its Subversion repository. With the use of the framework, we also enter PHP 5.x territory and must be running a supported version of PHP as well.
From our list of items for the bootstrapper, we have just scratched the surface and knocked down a basic implementation of the directory structure, the rest will be covered in the next part of this series. Here is where we are, and what we have left to cover:
- Directory structure of our application (completed)
- PHP settings
- Application settings
- Session management
- HTTP Headers
- Delegating to a controller
- Error handling
I’ll see you in “Blueprint for PHP Applications: Bootstrapping (part 3)” where we will knock down the rest of that list and provide the first working, downloadable, but somewhat empty Blueprint application.


Comments (Login to leave comments)
Placing a .htaccess with "deny from all" in the /private directoy is quite handy. Until now I did always setup a password protection in the .htaccess. Your approach is much simpler. Thanks for that!
I also like the .htaccess with the "RewriteEngine off" in the /public directory, because it makes the RewriteRule in the .htaccess of the document root much simpler as well. So now I can get rid of the
RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php
and just write
RewriteRule .* index.php
Nevertheless, in the .htaccess in the /public directory I would add the following
Options -Indexes
This makes sure to avoid the directory listing just in case it is not properly set within the httpd.conf of the Apache.
Waiting for the next part :-)
One thing to be aware of, with the new rewriterule, is the need to make paths to css and js includes absolute, like this:
href="/public/css/core.css"
Or else inclusion will fail if the URI trailing slash is omitted.
I've just recreated your suggested directory structure, including files.
I thought it might be handy if you could save other readers time, offering a downloadable zip of the neccesary folders and files.
Just a thought :)
Very much enjoying it so far
Without mod_php it's impossible to use php_flag and php_value. I would recommend to put the include path in the bootstrap file.
Nice articles, thanks.
Nice article, but I'm wondering... is really this htaccess the best approach? First of all it isn't compatible with other webserver than apache (I may be wrong :), but not 100%).
You may not have access to the htdocs file everytime, and you may have to setup applications on many different hosting environments, and sometimes you just discover it isn't working... and what then?
I'm using sort of a different approach:
In the bootstrap file you define a constant like FLOW_OK with a value of '1', and afterwards every "private"
file (classes for example) should contain a "test header", like this:
if (FLOW_OK != 1){
die();
}
I know this only works with php files, but I name my files with the php extension (even templates, as I'm not using Smarty or some other template engine). I'm also aware this isn't the right approach when using third party extensions (as not every file may be parsed as php), but I think that something like this should at least be used in conjunction with htaccess. :)
I am very much looking forward to the next article. I hope you still have plans to write it, as I see it has been a while since your last edition.
Thanks for sharing your best practices. It has made a big difference to me!
Now, if I can just work out this 'echo' statement... :-)
LFaR.
Usually I like to include some room to set up temlates for engines such as smarty. I don't know if this is will be a part of the next part of the article, in any case it could be nice to add something like:
<pre style="background-color: rgb(85, 51, 51);"> /www
|-- /public
| |-- /Templates
| |-- /skin1
| |-- /css
| |-- /images
| |-- /scripts
| |-- /template_sources
</pre>
In order to keep particular things together within the structure.
What do you think ?
Your templates, and skins, etc. - anything that's processed on the backend, should reside inside your private app folder structure. There's no need for a client to ever directly grab your templates unprocessed (well, unless you're hosting a smarty template gallery or something - though then you'd probably want to give them some nice syntax and browsing options...)
-M
can't you make it easyer to set up for us?
Is Part 3 still in the works? Has it become part of a bigger project? Or has it been forgotten completely?
At least let the readers know where this series of articles stand, if that's not too much to ask.
Regards,
KD
Asher
Why is .htaccess so secure? What is to stop a hacker from simply ftping or otherwise copying their own version of .htaccess over your own? It is close enough to a universally named file that everybody knows it is there regardless of hidden status or not.
Mark
"Why is .htaccess so secure? What is to stop a hacker from simply ftping or otherwise copying their own version of .htaccess over your own?"
If your FTP account is compromised then surely you're screwed anyway. I'd advise disabling FTP, where possible, and closing unnecessary ports (SSH and HTTP being necessary, obviously).
Your Apache configuration file should retain these default settings to prevent .ht* files from being read over HTTP:
<Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
And of course the permissions for the .htaccess file should be as strict as possible, e.g. 0600.
-newbie